Commit 97884551 authored by Marco Mattila's avatar Marco Mattila

Make single part per line BOM generation compare all component fields.

parent 0a68744e
......@@ -42,6 +42,13 @@
//#define USE_OLD_ALGO
void SCH_REFERENCE_LIST::RemoveItem( int aIndex )
{
if( aIndex < componentFlatList.size() )
componentFlatList.erase( componentFlatList.begin() + aIndex );
}
bool SCH_REFERENCE_LIST::sortByXPosition( const SCH_REFERENCE& item1,
const SCH_REFERENCE& item2 )
{
......
......@@ -852,150 +852,45 @@ int DIALOG_BUILD_BOM::PrintComponentsListByRef( FILE* f,
}
/* Bom Output format option - single part per line
* a common part being defined as have a common value.
* This is true for most designs but will produce an
* incorrect output if two or more parts with the same
* value have different footprints, tolerances, voltage
* rating, etc. Also useful if the following fields
* are edited:
* FIELD1 - manufacture
* FIELD2 - manufacture part number
* FIELD3 - distributor part number
*/
int DIALOG_BUILD_BOM::PrintComponentsListByPart( FILE* f, SCH_REFERENCE_LIST& aList,
int DIALOG_BUILD_BOM::PrintComponentsListByPart( FILE* aFile, SCH_REFERENCE_LIST& aList,
bool aIncludeSubComponents )
{
int qty = 0;
wxString refName;
wxString fullRefName; // reference + part Id (for multiple parts per package
wxString valName;
#if defined(KICAD_GOST)
wxString footName;
wxString datsName;
#endif
wxString refNames;
wxString lastRef;
wxString unitId;
SCH_COMPONENT* currCmp;
SCH_COMPONENT* nextCmp;
SCH_COMPONENT dummyCmp; // A dummy component, to store fields
for( unsigned ii = 0; ii < aList.GetCount(); ii++ )
int index = 0;
while( index < aList.GetCount() )
{
currCmp = aList[ii].GetComponent();
if( ii < aList.GetCount() -1 )
nextCmp = aList[ii+1].GetComponent();
else
nextCmp = NULL;
// Store fields. Store non empty fields only.
for( int jj = FOOTPRINT; jj < currCmp->GetFieldCount(); jj++ )
SCH_COMPONENT *component = aList[index].GetComponent();
wxString referenceListStr;
int qty = 1;
referenceListStr.append( aList[index].GetRef() );
for( unsigned int i = index+1; i < aList.GetCount(); )
{
// Ensure fields exists in dummy component
if( dummyCmp.GetFieldCount() <= jj )
dummyCmp.AddField( *currCmp->GetField( jj ) );
// store useful data
if( !currCmp->GetField( jj )->m_Text.IsEmpty() )
dummyCmp.GetField( jj )->m_Text = currCmp->GetField( jj )->m_Text;
}
refName = aList[ii].GetRef();
valName = currCmp->GetField( VALUE )->m_Text;
#if defined(KICAD_GOST)
footName = currCmp->GetField( FOOTPRINT )->m_Text;
datsName = currCmp->GetField( DATASHEET )->m_Text;
#endif
int multi = 0;
if( aIncludeSubComponents )
if( *(aList[i].GetComponent()) == *component )
{
LIB_COMPONENT* entry = CMP_LIBRARY::FindLibraryComponent( currCmp->GetLibName() );
if( entry )
multi = entry->GetPartCount();
if ( multi <= 1 )
multi = 0;
}
if ( multi && aList[ii].GetUnit() > 0 )
unitId.Printf( wxT("%c"), 'A' -1 + aList[ii].GetUnit() );
else
unitId.Empty();
fullRefName = refName + unitId;
if( refNames.IsEmpty() )
refNames = fullRefName;
else
refNames << wxT( ", " ) << fullRefName;
// In multi parts per package, we have the reference more than once
// but we must count only one package
if( lastRef != refName )
referenceListStr.append( wxT( " " ) + aList[i].GetRef() );
aList.RemoveItem( i );
qty++;
lastRef = refName;
// if the next component has same value the line will be printed after.
#if defined(KICAD_GOST)
if( nextCmp && nextCmp->GetField( VALUE )->m_Text.CmpNoCase( valName ) == 0
&& nextCmp->GetField( FOOTPRINT )->m_Text.CmpNoCase( footName ) == 0
&& nextCmp->GetField( DATASHEET )->m_Text.CmpNoCase( datsName ) == 0 )
#else
if( nextCmp && nextCmp->GetField( VALUE )->m_Text.CmpNoCase( valName ) == 0 )
#endif
continue;
// Print line for the current component value:
fprintf( f, "%15s%c%3d", TO_UTF8( valName ), s_ExportSeparatorSymbol, qty );
if( IsFieldChecked(FOOTPRINT ) )
fprintf( f, "%c%15s", s_ExportSeparatorSymbol,
#if defined(KICAD_GOST)
TO_UTF8( footName ) );
#else
TO_UTF8( currCmp->GetField( FOOTPRINT )->m_Text ) );
#endif
#if defined(KICAD_GOST)
fprintf( f, "%c%20s", s_ExportSeparatorSymbol,TO_UTF8( datsName ) );
#endif
// wrap the field in quotes, since it has commas in it.
fprintf( f, "%c\"%s\"", s_ExportSeparatorSymbol, TO_UTF8( refNames ) );
// print fields, on demand
int last_nonempty_field_idx = 0;
for( int jj = FOOTPRINT; jj < dummyCmp.GetFieldCount(); jj++ )
{
if ( !dummyCmp.GetField( jj )->m_Text.IsEmpty() )
last_nonempty_field_idx = jj;
}
for( int jj = FIELD1; jj <= last_nonempty_field_idx ; jj++ )
{
if ( IsFieldChecked( jj ) )
fprintf( f, "%c%4s", s_ExportSeparatorSymbol,
TO_UTF8( dummyCmp.GetField( jj )->m_Text ) );
else
i++; // Increment index only when current item is not removed from the list
}
fprintf( f, "\n" );
// Clear strings and values, to prepare next component
qty = 0;
refNames.Empty();
// Write value, quantity and list of references
fprintf( aFile, "%15s%c%3d%c\"%s\"", TO_UTF8( component->GetField( VALUE )->GetText() ),
s_ExportSeparatorSymbol, qty,
s_ExportSeparatorSymbol, TO_UTF8( referenceListStr ) );
for( int jj = FOOTPRINT; jj < dummyCmp.GetFieldCount(); jj++ )
dummyCmp.GetField( jj )->m_Text.Empty();
// Write the rest of the fields if required
#if defined( KICAD_GOST )
fprintf( aFile, "%c%20s", s_ExportSeparatorSymbol,
TO_UTF8( component->GetField( DATASHEET )->GetText() ) );
#endif
for( int i = FOOTPRINT; i < component->GetFieldCount(); i++ )
if( IsFieldChecked( i ) )
fprintf( aFile, "%c%15s", s_ExportSeparatorSymbol,
TO_UTF8( component->GetField( i )->GetText() ) );
fprintf( aFile, "\n" );
index++;
}
return 0;
}
......
......@@ -220,6 +220,8 @@ public:
componentFlatList.push_back( aItem );
}
void RemoveItem( int aIndex );
/**
* Function RemoveSubComponentsFromList
* Remove sub components from the list, when multiples parts per package are
......
......@@ -1780,6 +1780,27 @@ bool SCH_COMPONENT::operator <( const SCH_ITEM& aItem ) const
}
bool SCH_COMPONENT::operator==( const SCH_COMPONENT& aComponent ) const
{
if( GetFieldCount() != aComponent.GetFieldCount() )
return false;
for( int i = VALUE; i < GetFieldCount(); i++ )
{
if( GetField( i )->GetText().Cmp( aComponent.GetField( i )->GetText() ) != 0 )
return false;
}
return true;
}
bool SCH_COMPONENT::operator!=( const SCH_COMPONENT& aComponent ) const
{
return !( *this == aComponent );
}
SCH_ITEM& SCH_COMPONENT::operator=( const SCH_ITEM& aItem )
{
wxCHECK_MSG( Type() == aItem.Type(), *this,
......
......@@ -401,6 +401,9 @@ public:
virtual bool operator <( const SCH_ITEM& aItem ) const;
bool operator==( const SCH_COMPONENT& aComponent) const;
bool operator!=( const SCH_COMPONENT& aComponent) const;
SCH_ITEM& operator=( const SCH_ITEM& aItem );
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment