From 1e2e144231880923f89e3c495734af973df3c624 Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Thu, 6 Jan 2011 11:55:18 -0500 Subject: [PATCH] Schematic reference object refactoring and minor dialog fix. * Schematic reference object now completely encapsulated. * Schematic reference list object refactoring complete. * Make OK default button in PCBNew block operation dialog. --- eeschema/annotate.cpp | 467 +---------------------- eeschema/component_references_lister.cpp | 396 ++++++++++++++++++- eeschema/dialogs/dialog_build_BOM.cpp | 8 +- eeschema/netlist.h | 80 +++- eeschema/sch_sheet_path.cpp | 2 +- pcbnew/block.cpp | 1 + 6 files changed, 476 insertions(+), 478 deletions(-) diff --git a/eeschema/annotate.cpp b/eeschema/annotate.cpp index 458da4e4a0..022af0bb23 100644 --- a/eeschema/annotate.cpp +++ b/eeschema/annotate.cpp @@ -19,29 +19,6 @@ #include "sch_component.h" #include "lib_pin.h" -//#define USE_OLD_ALGO - -/** - * Function ComputeReferenceNumber - * Compute the reference number for components without reference number - * i.e. .m_NumRef member of each SCH_REFERENCE_LIST item not yet annotated - * in aComponentsList. - * if aUseSheetNum is false, this number starts from 1 - * if aUseSheetNum is false, this number starts from from SheetNumber * aSheetIntervalId - * @param aComponentsList = the SCH_REFERENCE_LIST to fill - * @param aUseSheetNum = false to start Ids from 0, - * true to start each sheet annotation from SheetNumber * aSheetIntervalId - * @param aSheetIntervalId = number of allowed Id by sheet and by reference prefix - * if There are more than aSheetIntervalId of reference prefix in a given sheet - * number overlap next sheet inveral, but there is no annotation problem. - * Useful values are only 100 or 1000 - * For instance for a sheet number = 2, and aSheetIntervalId = 100, the first Id = 101 - * and the last Id is 199 when no overlap occurs with sheet number 2. - * Rf there are 150 items in sheet number 2, items are referenced U201 to U351, - * and items in sheet 3 start from U352 - */ -static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, - bool aUseSheetNum, int aSheetIntervalId ); /** * Function DeleteAnnotation @@ -179,11 +156,25 @@ void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic, } // Recalculate and update reference numbers in schematic - ComputeReferenceNumber( references, useSheetNum, idStep ); + references.Annotate( useSheetNum, idStep ); references.UpdateAnnotation(); + wxArrayString errors; + /* Final control (just in case ... )*/ - CheckAnnotate( NULL, !aAnnotateSchematic ); + if( CheckAnnotate( &errors, !aAnnotateSchematic ) ) + { + wxString msg; + + for( size_t i = 0; i < errors.GetCount(); i++ ) + msg += errors[i]; + + // wxLogWarning is a cheap and dirty way to dump a potentially long list of + // strings to a dialog that can be saved to a file. This should be replaced + // by a more elegant solution. + wxLogWarning( msg ); + } + OnModify(); // Update on screen references, that can be modified by previous calculations: @@ -194,215 +185,6 @@ void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic, } -#ifndef USE_OLD_ALGO -/** - * helper function CreateFirstFreeRefId - * Search for a free ref Id inside a list of reference numbers in use. - * Because this function just search for a hole in a list of incremented numbers, - * this list must be: - * sorted by increasing values. - * and each value stored only once - * @see BuildRefIdInUseList to prepare this list - * @param aIdList = the buffer that contains Ids in use - * @param aFirstValue = the first expected free value - * @return a free (not yet used) Id - * and this new id is added in list - */ -static int CreateFirstFreeRefId( std::vector& aIdList, int aFirstValue ) -{ - int expectedId = aFirstValue; - - // We search for expected Id a value >= aFirstValue. - // Skip existing Id < aFirstValue - unsigned ii = 0; - - for( ; ii < aIdList.size(); ii++ ) - { - if( expectedId <= aIdList[ii] ) - break; - } - - // Ids are sorted by increasing value, from aFirstValue - // So we search from aFirstValue the first not used value, i.e. the first hole in list. - for(; ii < aIdList.size(); ii++ ) - { - if( expectedId != aIdList[ii] ) // This id is not yet used. - { - // Insert this free Id, in order to keep list sorted - aIdList.insert(aIdList.begin() + ii, expectedId); - return expectedId; - } - - expectedId++; - } - - // All existing Id are tested, and all values are found in use. - // So Create a new one. - aIdList.push_back( expectedId ); - return expectedId; -} -#endif - -/* - * Function ComputeReferenceNumber - * Compute the reference number for components without reference number - * i.e. .m_NumRef member of each SCH_REFERENCE_LIST item not yet annotated - * in aComponentsList. - * if aUseSheetNum is false, this number starts from 1 - * if aUseSheetNum is false, this number starts from from SheetNumber * aSheetIntervalId - */ -static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, - bool aUseSheetNum, int aSheetIntervalId ) -{ - if ( aComponentsList.GetCount() == 0 ) - return; - - int LastReferenceNumber = 0; - int NumberOfUnits, Unit; - - /* Components with an invisible reference (power...) always are re-annotated. */ - aComponentsList.ResetHiddenReferences(); - - /* calculate index of the first component with the same reference prefix - * than the current component. All components having the same reference - * prefix will receive a reference number with consecutive values: - * IC .. will be set to IC4, IC4, IC5 ... - */ - unsigned first = 0; - - /* calculate the last used number for this reference prefix: */ -#ifdef USE_OLD_ALGO - int minRefId = 0; - - // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId - if( aUseSheetNum ) - minRefId = aComponentsList[first].m_SheetNum * aSheetIntervalId; - - LastReferenceNumber = aComponentsList.GetLastReference( first, minRefId ); -#else - int minRefId = 1; - - // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId - if( aUseSheetNum ) - minRefId = aComponentsList[first].m_SheetNum * aSheetIntervalId + 1; - - // This is the list of all Id already in use for a given reference prefix. - // Will be refilled for each new reference prefix. - std::vectoridList; - aComponentsList.GetRefsInUse( first, idList, minRefId ); -#endif - for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) - { - if( aComponentsList[ii].m_Flag ) - continue; - - if( ( aComponentsList[first].CompareRef( aComponentsList[ii] ) != 0 ) - || ( aUseSheetNum - && ( aComponentsList[first].m_SheetNum != aComponentsList[ii].m_SheetNum ) ) ) - { - /* New reference found: we need a new ref number for this reference */ - first = ii; -#ifdef USE_OLD_ALGO - minRefId = 0; - - // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId - if( aUseSheetNum ) - minRefId = aComponentsList[ii].m_SheetNum * aSheetIntervalId; - - LastReferenceNumber = aComponentsList.GetLastReference( ii, minRefId ); -#else - minRefId = 1; - - // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId - if( aUseSheetNum ) - minRefId = aComponentsList[ii].m_SheetNum * aSheetIntervalId + 1; - - aComponentsList.GetRefsInUse( first, idList, minRefId ); -#endif - } - - // Annotation of one part per package components (trivial case). - if( aComponentsList[ii].GetLibComponent()->GetPartCount() <= 1 ) - { - if( aComponentsList[ii].m_IsNew ) - { -#ifdef USE_OLD_ALGO - LastReferenceNumber++; -#else - LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId ); -#endif - aComponentsList[ii].m_NumRef = LastReferenceNumber; - } - - aComponentsList[ii].m_Unit = 1; - aComponentsList[ii].m_Flag = 1; - aComponentsList[ii].m_IsNew = false; - continue; - } - - /* Annotation of multi-part components ( n parts per package ) (complex case) */ - NumberOfUnits = aComponentsList[ii].GetLibComponent()->GetPartCount(); - - if( aComponentsList[ii].m_IsNew ) - { -#ifdef USE_OLD_ALGO - LastReferenceNumber++; -#else - LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId ); -#endif - aComponentsList[ii].m_NumRef = LastReferenceNumber; - - if( !aComponentsList[ii].IsPartsLocked() ) - aComponentsList[ii].m_Unit = 1; - - aComponentsList[ii].m_Flag = 1; - } - - /* search for others units of this component. - * we search for others parts that have the same value and the same - * reference prefix (ref without ref number) - */ - for( Unit = 1; Unit <= NumberOfUnits; Unit++ ) - { - if( aComponentsList[ii].m_Unit == Unit ) - continue; - - int found = aComponentsList.FindUnit( ii, Unit ); - - if( found >= 0 ) - continue; /* this unit exists for this reference (unit already annotated) */ - - /* Search a component to annotate ( same prefix, same value, not annotated) */ - for( unsigned jj = ii + 1; jj < aComponentsList.GetCount(); jj++ ) - { - if( aComponentsList[jj].m_Flag ) // already tested - continue; - - if( aComponentsList[ii].CompareRef( aComponentsList[jj] ) != 0 ) - continue; - - if( aComponentsList[jj].CompareValue( aComponentsList[ii] ) != 0 ) - continue; - - if( !aComponentsList[jj].m_IsNew ) - continue; - - /* Component without reference number found, annotate it if possible */ - if( !aComponentsList[jj].IsPartsLocked() - || ( aComponentsList[jj].m_Unit == Unit ) ) - { - aComponentsList[jj].m_NumRef = aComponentsList[ii].m_NumRef; - aComponentsList[jj].m_Unit = Unit; - aComponentsList[jj].m_Flag = 1; - aComponentsList[jj].m_IsNew = false; - break; - } - } - } - } -} - - /** * Function CheckAnnotate * Check errors relatives to annotation: @@ -411,21 +193,15 @@ static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, * for multiple parts per package components : * part number > number of parts * different values between parts - * @param aMessageList = a wxArrayString to store messages. If NULL, they - * are displayed in a wxMessageBox + * @param aMessageList = a wxArrayString to store messages. * @param aOneSheetOnly : true = search is made only in the current sheet * false = search in whole hierarchy (usual search). * @return errors count */ int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOnly ) { - int error = 0; - wxString Buff; - wxString msg, cmpref; - /* build the screen list */ SCH_SHEET_LIST SheetList; - SCH_REFERENCE_LIST ComponentsList; /* Build the list of components */ @@ -434,212 +210,5 @@ int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOn else GetSheet()->GetComponents( ComponentsList ); - ComponentsList.SortByRefAndValue(); - - /* Break full components reference in name (prefix) and number: example: - * IC1 become IC, and 1 */ - ComponentsList.SplitReferences(); - - /* count not yet annotated items or annotation error*/ - for( unsigned ii = 0; ii < ComponentsList.GetCount(); ii++ ) - { - msg.Empty(); - Buff.Empty(); - - if( ComponentsList[ii].m_IsNew ) // Not yet annotated - { - if( ComponentsList[ii].m_NumRef >= 0 ) - Buff << ComponentsList[ii].m_NumRef; - else - Buff = wxT( "?" ); - - cmpref = ComponentsList[ii].GetRef(); - msg.Printf( _( "item not annotated: %s%s" ), GetChars( cmpref ), GetChars( Buff ) ); - - if( ( ComponentsList[ii].m_Unit > 0 ) && ( ComponentsList[ii].m_Unit < 0x7FFFFFFF ) ) - { - Buff.Printf( _( "( unit %d)" ), ComponentsList[ii].m_Unit ); - msg << Buff; - } - - if( aMessageList ) - aMessageList->Add( msg + wxT( "\n" ) ); - else - DisplayError( NULL, msg ); - - error++; - break; - } - - // Annotate error if unit selected does not exist ( i.e. > number of parts ) - // Can happen if a component has changed in a lib, after a previous annotation - if( MAX( ComponentsList[ii].GetLibComponent()->GetPartCount(), 1 ) < ComponentsList[ii].m_Unit ) - { - if( ComponentsList[ii].m_NumRef >= 0 ) - Buff << ComponentsList[ii].m_NumRef; - else - Buff = wxT( "?" ); - - cmpref = ComponentsList[ii].GetRef(); - - msg.Printf( _( "Error item %s%s" ), GetChars( cmpref ), GetChars( Buff ) ); - - Buff.Printf( _( " unit %d and no more than %d parts" ), - ComponentsList[ii].m_Unit, - ComponentsList[ii].GetLibComponent()->GetPartCount() ); - msg << Buff; - - if( aMessageList ) - aMessageList->Add( msg + wxT( "\n" )); - else - DisplayError( NULL, msg ); - - error++; - break; - } - } - - if( error ) - return error; - - // count the duplicated elements (if all are annotated) - int imax = ComponentsList.GetCount() - 1; - for( int ii = 0; (ii < imax) && (error < 4); ii++ ) - { - msg.Empty(); - Buff.Empty(); - - if( ( ComponentsList[ii].CompareRef( ComponentsList[ii + 1] ) != 0 ) - || ( ComponentsList[ii].m_NumRef != ComponentsList[ii + 1].m_NumRef ) ) - continue; - - /* Same reference found. If same unit, error ! - */ - if( ComponentsList[ii].m_Unit == ComponentsList[ii + 1].m_Unit ) - { - if( ComponentsList[ii].m_NumRef >= 0 ) - Buff << ComponentsList[ii].m_NumRef; - else - Buff = wxT( "?" ); - - cmpref = ComponentsList[ii].GetRef(); - - msg.Printf( _( "Multiple item %s%s" ), GetChars( cmpref ), GetChars( Buff ) ); - - if( ( ComponentsList[ii].m_Unit > 0 )&& ( ComponentsList[ii].m_Unit < 0x7FFFFFFF ) ) - { - Buff.Printf( _( " (unit %d)" ), ComponentsList[ii].m_Unit ); - msg << Buff; - } - - if( aMessageList ) - aMessageList->Add( msg + wxT( "\n" )); - else - DisplayError( NULL, msg ); - - error++; - continue; - } - - /* Test error if units are different but number of parts per package - * too high (ex U3 ( 1 part) and we find U3B this is an error) */ - if( ComponentsList[ii].GetLibComponent()->GetPartCount() - != ComponentsList[ii + 1].GetLibComponent()->GetPartCount() ) - { - if( ComponentsList[ii].m_NumRef >= 0 ) - Buff << ComponentsList[ii].m_NumRef; - else - Buff = wxT( "?" ); - - cmpref = ComponentsList[ii].GetRef(); - msg.Printf( _( "Multiple item %s%s" ), GetChars( cmpref ), GetChars( Buff ) ); - - if( ( ComponentsList[ii].m_Unit > 0 ) && ( ComponentsList[ii].m_Unit < 0x7FFFFFFF ) ) - { - Buff.Printf( _( " (unit %d)" ), ComponentsList[ii].m_Unit ); - msg << Buff; - } - - if( aMessageList ) - aMessageList->Add( msg + wxT( "\n" )); - else - DisplayError( NULL, msg ); - - error++; - } - - /* Error if values are different between units, for the same reference */ - int next = ii + 1; - - if( ComponentsList[ii].CompareValue( ComponentsList[next] ) != 0 ) - { - wxString nextcmpref = ComponentsList[next].GetRef(); - - cmpref = ComponentsList[ii].GetRef(); - -#if defined(KICAD_GOST) - msg.Printf( _( "Diff values for %s%d.%c (%s) and %s%d.%c (%s)" ), - cmpref.GetData(), - ComponentsList[ii].m_NumRef, - ComponentsList[ii].m_Unit + '1' - 1, - GetChars( *ComponentsList[ii].m_Value ), - GetChars( nextcmpref ), - ComponentsList[next].m_NumRef, - ComponentsList[next].m_Unit + '1' - 1, - ComponentsList[next].m_Value->GetData() ); -#else - msg.Printf( _( "Diff values for %s%d%c (%s) and %s%d%c (%s)" ), - cmpref.GetData(), - ComponentsList[ii].m_NumRef, - ComponentsList[ii].m_Unit + 'A' - 1, - GetChars( *ComponentsList[ii].m_Value ), - GetChars( nextcmpref ), - ComponentsList[next].m_NumRef, - ComponentsList[next].m_Unit + 'A' - 1, - GetChars( *ComponentsList[next].m_Value ) ); -#endif - - if( aMessageList ) - aMessageList->Add( msg + wxT( "\n" )); - else - DisplayError( NULL, msg ); - - error++; - } - } - - // count the duplicated time stamps - ComponentsList.SortComponentsByTimeStamp(); - - for( int ii = 0; ( ii < imax ) && ( error < 4 ); ii++ ) - { - if( ( ComponentsList[ii].m_TimeStamp != ComponentsList[ii + 1].m_TimeStamp ) - || ( ComponentsList[ii].GetSheetPath() != ComponentsList[ii + 1].GetSheetPath() ) ) - continue; - - /* Same time stamp found. */ - wxString nextcmpref; - wxString full_path; - - full_path.Printf( wxT( "%s%8.8X" ), - GetChars( ComponentsList[ii].GetSheetPath().Path() ), - ComponentsList[ii].m_TimeStamp ); - - cmpref = ComponentsList[ii].GetRef(); - nextcmpref = ComponentsList[ii + 1].GetRef(); - - msg.Printf( _( "duplicate time stamp (%s) for %s%d and %s%d" ), - GetChars( full_path ), - GetChars( cmpref ), ComponentsList[ii].m_NumRef, - GetChars( nextcmpref ), ComponentsList[ii + 1].m_NumRef ); - - if( aMessageList ) - aMessageList->Add( msg + wxT( "\n" )); - else - DisplayError( NULL, msg ); - - error++; - } - - return error; + return ComponentsList.CheckAnnotation( aMessageList ); } diff --git a/eeschema/component_references_lister.cpp b/eeschema/component_references_lister.cpp index cc9b7f4e56..28a6f10b24 100644 --- a/eeschema/component_references_lister.cpp +++ b/eeschema/component_references_lister.cpp @@ -42,6 +42,8 @@ #include "sch_component.h" +//#define USE_OLD_ALGO + bool SCH_REFERENCE_LIST::sortByXPosition( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ) @@ -182,9 +184,6 @@ int SCH_REFERENCE_LIST::FindUnit( size_t aIndex, int aUnit ) } -/* Remove sub components from the list, when multiples parts per package are - * found in this list - */ void SCH_REFERENCE_LIST::RemoveSubComponentsFromList() { SCH_COMPONENT* libItem; @@ -197,6 +196,7 @@ void SCH_REFERENCE_LIST::RemoveSubComponentsFromList() for( unsigned ii = 0; ii < componentFlatList.size(); ii++ ) { + libItem = componentFlatList[ii].m_RootCmp; if( libItem == NULL ) continue; @@ -236,8 +236,8 @@ void SCH_REFERENCE_LIST::GetRefsInUse( int aIndex, std::vector< int >& aIdList, for( unsigned ii = 0; ii < componentFlatList.size(); ii++ ) { - if( ( componentFlatList[aIndex].CompareRef( componentFlatList[ii] ) == 0 ) - && ( componentFlatList[ii].m_NumRef >= aMinRefId ) ) + if( ( componentFlatList[aIndex].CompareRef( componentFlatList[ii] ) == 0 ) + && ( componentFlatList[ii].m_NumRef >= aMinRefId ) ) aIdList.push_back( componentFlatList[ii].m_NumRef ); } @@ -272,6 +272,391 @@ int SCH_REFERENCE_LIST::GetLastReference( int aIndex, int aMinValue ) } +int SCH_REFERENCE_LIST::CreateFirstFreeRefId( std::vector& aIdList, int aFirstValue ) +{ + int expectedId = aFirstValue; + + // We search for expected Id a value >= aFirstValue. + // Skip existing Id < aFirstValue + unsigned ii = 0; + + for( ; ii < aIdList.size(); ii++ ) + { + if( expectedId <= aIdList[ii] ) + break; + } + + // Ids are sorted by increasing value, from aFirstValue + // So we search from aFirstValue the first not used value, i.e. the first hole in list. + for( ; ii < aIdList.size(); ii++ ) + { + if( expectedId != aIdList[ii] ) // This id is not yet used. + { + // Insert this free Id, in order to keep list sorted + aIdList.insert( aIdList.begin() + ii, expectedId ); + return expectedId; + } + + expectedId++; + } + + // All existing Id are tested, and all values are found in use. + // So Create a new one. + aIdList.push_back( expectedId ); + return expectedId; +} + + +void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId ) +{ + if ( componentFlatList.size() == 0 ) + return; + + int LastReferenceNumber = 0; + int NumberOfUnits, Unit; + + /* Components with an invisible reference (power...) always are re-annotated. */ + ResetHiddenReferences(); + + /* calculate index of the first component with the same reference prefix + * than the current component. All components having the same reference + * prefix will receive a reference number with consecutive values: + * IC .. will be set to IC4, IC4, IC5 ... + */ + unsigned first = 0; + + /* calculate the last used number for this reference prefix: */ +#ifdef USE_OLD_ALGO + int minRefId = 0; + + // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId + if( aUseSheetNum ) + minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId; + + LastReferenceNumber = GetLastReference( first, minRefId ); +#else + int minRefId = 1; + + // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId + if( aUseSheetNum ) + minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId + 1; + + // This is the list of all Id already in use for a given reference prefix. + // Will be refilled for each new reference prefix. + std::vectoridList; + GetRefsInUse( first, idList, minRefId ); +#endif + for( unsigned ii = 0; ii < componentFlatList.size(); ii++ ) + { + if( componentFlatList[ii].m_Flag ) + continue; + + if( ( componentFlatList[first].CompareRef( componentFlatList[ii] ) != 0 ) + || ( aUseSheetNum && ( componentFlatList[first].m_SheetNum != componentFlatList[ii].m_SheetNum ) ) ) + { + /* New reference found: we need a new ref number for this reference */ + first = ii; +#ifdef USE_OLD_ALGO + minRefId = 0; + + // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId + if( aUseSheetNum ) + minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId; + + LastReferenceNumber = componentFlatList.GetLastReference( ii, minRefId ); +#else + minRefId = 1; + + // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId + if( aUseSheetNum ) + minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId + 1; + + GetRefsInUse( first, idList, minRefId ); +#endif + } + + // Annotation of one part per package components (trivial case). + if( componentFlatList[ii].GetLibComponent()->GetPartCount() <= 1 ) + { + if( componentFlatList[ii].m_IsNew ) + { +#ifdef USE_OLD_ALGO + LastReferenceNumber++; +#else + LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId ); +#endif + componentFlatList[ii].m_NumRef = LastReferenceNumber; + } + + componentFlatList[ii].m_Unit = 1; + componentFlatList[ii].m_Flag = 1; + componentFlatList[ii].m_IsNew = false; + continue; + } + + /* Annotation of multi-part components ( n parts per package ) (complex case) */ + NumberOfUnits = componentFlatList[ii].GetLibComponent()->GetPartCount(); + + if( componentFlatList[ii].m_IsNew ) + { +#ifdef USE_OLD_ALGO + LastReferenceNumber++; +#else + LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId ); +#endif + componentFlatList[ii].m_NumRef = LastReferenceNumber; + + if( !componentFlatList[ii].IsPartsLocked() ) + componentFlatList[ii].m_Unit = 1; + + componentFlatList[ii].m_Flag = 1; + } + + /* search for others units of this component. + * we search for others parts that have the same value and the same + * reference prefix (ref without ref number) + */ + for( Unit = 1; Unit <= NumberOfUnits; Unit++ ) + { + if( componentFlatList[ii].m_Unit == Unit ) + continue; + + int found = FindUnit( ii, Unit ); + + if( found >= 0 ) + continue; /* this unit exists for this reference (unit already annotated) */ + + /* Search a component to annotate ( same prefix, same value, not annotated) */ + for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ ) + { + if( componentFlatList[jj].m_Flag ) // already tested + continue; + + if( componentFlatList[ii].CompareRef( componentFlatList[jj] ) != 0 ) + continue; + + if( componentFlatList[jj].CompareValue( componentFlatList[ii] ) != 0 ) + continue; + + if( !componentFlatList[jj].m_IsNew ) + continue; + + /* Component without reference number found, annotate it if possible */ + if( !componentFlatList[jj].IsPartsLocked() + || ( componentFlatList[jj].m_Unit == Unit ) ) + { + componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef; + componentFlatList[jj].m_Unit = Unit; + componentFlatList[jj].m_Flag = 1; + componentFlatList[jj].m_IsNew = false; + break; + } + } + } + } +} + + +int SCH_REFERENCE_LIST::CheckAnnotation( wxArrayString* aMessageList ) +{ + int error = 0; + wxString tmp; + wxString msg; + + SortByRefAndValue(); + + // Spiit reference designators into name (prefix) and number: IC1 becomes IC, and 1. + SplitReferences(); + + // count not yet annotated items or annotation error. + for( unsigned ii = 0; ii < componentFlatList.size(); ii++ ) + { + msg.Empty(); + tmp.Empty(); + + if( componentFlatList[ii].m_IsNew ) // Not yet annotated + { + if( componentFlatList[ii].m_NumRef >= 0 ) + tmp << componentFlatList[ii].m_NumRef; + else + tmp = wxT( "?" ); + + msg.Printf( _( "Item not annotated: %s%s" ), + GetChars( componentFlatList[ii].GetRef() ), GetChars( tmp ) ); + + if( ( componentFlatList[ii].m_Unit > 0 ) + && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) ) + { + tmp.Printf( _( " (unit %d)" ), componentFlatList[ii].m_Unit ); + msg << tmp; + } + + if( aMessageList ) + aMessageList->Add( msg + wxT( "\n" ) ); + + error++; + break; + } + + // Error if unit number selected does not exist ( greater than the number of + // parts in the component ). This can happen if a component has changed in a + // library after a previous annotation. + if( MAX( componentFlatList[ii].GetLibComponent()->GetPartCount(), 1 ) + < componentFlatList[ii].m_Unit ) + { + if( componentFlatList[ii].m_NumRef >= 0 ) + tmp << componentFlatList[ii].m_NumRef; + else + tmp = wxT( "?" ); + + msg.Printf( _( "Error item %s%s" ), GetChars( componentFlatList[ii].GetRef() ), + GetChars( tmp ) ); + + tmp.Printf( _( " unit %d and no more than %d parts" ), + componentFlatList[ii].m_Unit, + componentFlatList[ii].GetLibComponent()->GetPartCount() ); + msg << tmp; + + if( aMessageList ) + aMessageList->Add( msg + wxT( "\n" ) ); + + error++; + break; + } + } + + if( error ) + return error; + + // count the duplicated elements (if all are annotated) + int imax = componentFlatList.size() - 1; + + for( int ii = 0; (ii < imax) && (error < 4); ii++ ) + { + msg.Empty(); + tmp.Empty(); + + if( ( componentFlatList[ii].CompareRef( componentFlatList[ii + 1] ) != 0 ) + || ( componentFlatList[ii].m_NumRef != componentFlatList[ii + 1].m_NumRef ) ) + continue; + + // Same reference found. If same unit, error! + if( componentFlatList[ii].m_Unit == componentFlatList[ii + 1].m_Unit ) + { + if( componentFlatList[ii].m_NumRef >= 0 ) + tmp << componentFlatList[ii].m_NumRef; + else + tmp = wxT( "?" ); + + msg.Printf( _( "Multiple item %s%s" ), + GetChars( componentFlatList[ii].GetRef() ), GetChars( tmp ) ); + + if( ( componentFlatList[ii].m_Unit > 0 ) + && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) ) + { + tmp.Printf( _( " (unit %d)" ), componentFlatList[ii].m_Unit ); + msg << tmp; + } + + if( aMessageList ) + aMessageList->Add( msg + wxT( "\n" ) ); + + error++; + continue; + } + + /* Test error if units are different but number of parts per package + * too high (ex U3 ( 1 part) and we find U3B this is an error) */ + if( componentFlatList[ii].GetLibComponent()->GetPartCount() + != componentFlatList[ii + 1].GetLibComponent()->GetPartCount() ) + { + if( componentFlatList[ii].m_NumRef >= 0 ) + tmp << componentFlatList[ii].m_NumRef; + else + tmp = wxT( "?" ); + + msg.Printf( _( "Multiple item %s%s" ), + GetChars( componentFlatList[ii].GetRef() ), GetChars( tmp ) ); + + if( ( componentFlatList[ii].m_Unit > 0 ) + && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) ) + { + tmp.Printf( _( " (unit %d)" ), componentFlatList[ii].m_Unit ); + msg << tmp; + } + + if( aMessageList ) + aMessageList->Add( msg + wxT( "\n" )); + + error++; + } + + /* Error if values are different between units, for the same reference */ + int next = ii + 1; + + if( componentFlatList[ii].CompareValue( componentFlatList[next] ) != 0 ) + { +#if defined(KICAD_GOST) + msg.Printf( _( "Different values for %s%d.%c (%s) and %s%d.%c (%s)" ), + GetChars( componentFlatList[ii].GetRef() ), + componentFlatList[ii].m_NumRef, + componentFlatList[ii].m_Unit + '1' - 1, + GetChars( *componentFlatList[ii].m_Value ), + GetChars( componentFlatList[next].GetRef() ), + componentFlatList[next].m_NumRef, + componentFlatList[next].m_Unit + '1' - 1, + componentFlatList[next].m_Value->GetData() ); +#else + msg.Printf( _( "Different values for %s%d%c (%s) and %s%d%c (%s)" ), + GetChars( componentFlatList[ii].GetRef() ), + componentFlatList[ii].m_NumRef, + componentFlatList[ii].m_Unit + 'A' - 1, + GetChars( *componentFlatList[ii].m_Value ), + GetChars( componentFlatList[next].GetRef() ), + componentFlatList[next].m_NumRef, + componentFlatList[next].m_Unit + 'A' - 1, + GetChars( *componentFlatList[next].m_Value ) ); +#endif + + if( aMessageList ) + aMessageList->Add( msg + wxT( "\n" )); + + error++; + } + } + + // count the duplicated time stamps + SortByTimeStamp(); + + for( int ii = 0; ( ii < imax ) && ( error < 4 ); ii++ ) + { + if( ( componentFlatList[ii].m_TimeStamp != componentFlatList[ii + 1].m_TimeStamp ) + || ( componentFlatList[ii].GetSheetPath() != componentFlatList[ii + 1].GetSheetPath() ) ) + continue; + + /* Same time stamp found. */ + wxString full_path; + + full_path.Printf( wxT( "%s%8.8X" ), + GetChars( componentFlatList[ii].GetSheetPath().Path() ), + componentFlatList[ii].m_TimeStamp ); + + msg.Printf( _( "Duplicate time stamp (%s) for %s%d and %s%d" ), + GetChars( full_path ), + GetChars( componentFlatList[ii].GetRef() ), componentFlatList[ii].m_NumRef, + GetChars( componentFlatList[ii + 1].GetRef() ), + componentFlatList[ii + 1].m_NumRef ); + + if( aMessageList ) + aMessageList->Add( msg + wxT( "\n" )); + + error++; + } + + return error; +} + + SCH_REFERENCE::SCH_REFERENCE( SCH_COMPONENT* aComponent, LIB_COMPONENT* aLibComponent, SCH_SHEET_PATH& aSheetPath ) { @@ -364,4 +749,3 @@ void SCH_REFERENCE::Split() SetRefStr( refText ); } } - diff --git a/eeschema/dialogs/dialog_build_BOM.cpp b/eeschema/dialogs/dialog_build_BOM.cpp index a55745710b..ea61124aa6 100644 --- a/eeschema/dialogs/dialog_build_BOM.cpp +++ b/eeschema/dialogs/dialog_build_BOM.cpp @@ -649,7 +649,7 @@ int DIALOG_BUILD_BOM::PrintComponentsListByRef( FILE* f, isMulti = entry->IsMulti(); if( isMulti && aIncludeSubComponents ) - subRef = LIB_COMPONENT::ReturnSubReference( aList[ii].m_Unit ); + subRef = LIB_COMPONENT::ReturnSubReference( aList[ii].GetUnit() ); else subRef.Empty(); @@ -786,8 +786,8 @@ int DIALOG_BUILD_BOM::PrintComponentsListByPart( FILE* f, SCH_REFERENCE_LIST& aL multi = 0; } - if ( multi && aList[ii].m_Unit > 0 ) - unitId.Printf( wxT("%c"), 'A' -1 + aList[ii].m_Unit ); + if ( multi && aList[ii].GetUnit() > 0 ) + unitId.Printf( wxT("%c"), 'A' -1 + aList[ii].GetUnit() ); else unitId.Empty(); @@ -901,7 +901,7 @@ int DIALOG_BUILD_BOM::PrintComponentsListByVal( FILE* f, wxString subRef; if( isMulti && aIncludeSubComponents ) - subRef = LIB_COMPONENT::ReturnSubReference( aList[ii].m_Unit ); + subRef = LIB_COMPONENT::ReturnSubReference( aList[ii].GetUnit() ); else subRef.Empty(); diff --git a/eeschema/netlist.h b/eeschema/netlist.h index ce0dda4716..134aff8b91 100644 --- a/eeschema/netlist.h +++ b/eeschema/netlist.h @@ -66,24 +66,19 @@ private: LIB_COMPONENT* m_Entry; ///< The source component from a library. wxPoint m_CmpPos; ///< The physical position of the component in schematic ///< used to annotate by X or Y position + int m_Unit; ///< The unit number for components with multiple parts + ///< per package. SCH_SHEET_PATH m_SheetPath; ///< The sheet path for this reference. + bool m_IsNew; ///< True if not yet annotated. + int m_SheetNum; ///< The sheet number for the reference. + unsigned long m_TimeStamp; ///< The time stamp for the reference. + wxString* m_Value; ///< The component value of the refernce. It is the + ///< same for all instances. + int m_NumRef; ///< The numeric part of the reference designator. + int m_Flag; friend class SCH_REFERENCE_LIST; -public: - int m_Unit; /* Selected part (For multi parts per - * package) depending on sheet path */ - int m_SheetNum; // the sheet num for this component - unsigned long m_TimeStamp; /* unique identification number - * depending on sheet path */ - bool m_IsNew; /* true for not yet annotated - * components */ - wxString* m_Value; /* Component value (same for all - * instances) */ - int m_NumRef; /* Reference number (for IC1, this is - * 1) ) depending on sheet path*/ - int m_Flag; /* flag for computations */ - public: SCH_REFERENCE() @@ -108,6 +103,10 @@ public: SCH_SHEET_PATH GetSheetPath() const { return m_SheetPath; } + int GetUnit() const { return m_Unit; } + + void SetSheetNumber( int aSheetNumber ) { m_SheetNum = aSheetNumber; } + /** * Function Annotate * updates the annotation of the component according the the current object state. @@ -165,9 +164,9 @@ public: /** * Class SCH_REFERENCE_LIST * is used create a flattened list of components because in a complex hierarchy, a component - * can used more than once and its reference designator is dependent on the sheet path for the - * same component. This flattened list is used for netlist generation, BOM generation, and - * schematic annotation. + * can be used more than once and its reference designator is dependent on the sheet path for + * the same component. This flattened list is used for netlist generation, BOM generation, + * and schematic annotation. */ class SCH_REFERENCE_LIST { @@ -262,6 +261,38 @@ public: } } + /** + * Function Annotate + * set the reference designators in the list that have not been annotated. + * @param aUseSheetNum Set to true to start annotation for each sheet at the sheet number + * times \a aSheetIntervalId. Otherwise annotate incrementally. + * @param aSheetIntervalId The per sheet reference designator multiplier. + *

+ * If a the sheet number is 2 and \a aSheetIntervalId is 100, then the first reference + * designator would be 201 and the last reference designator would be 299 when no overlap + * occurs with sheet number 3. If there are 150 items in sheet number 2, then items are + * referenced U201 to U351, and items in sheet 3 start from U352 + *

+ */ + void Annotate( bool aUseSheetNum, int aSheetIntervalId ); + + /** + * Function CheckAnnotation + * check for annotations errors. + *

+ * The following annotation error conditions are tested: + *

    + *
  • Components not annotated.
  • + *
  • Components having the same reference designator (duplicates).
  • + *
  • Components with multiple parts per package having different reference designators.
  • + *
  • Components with multiple parts per package with invalid part count.
  • + *
+ *

+ * @param aMessageList A wxArrayString to store error messages. + * @return The number of errors found. + */ + int CheckAnnotation( wxArrayString* aMessageList ); + /** * Function sortByXCoordinate * sorts the list of references by X position. @@ -305,7 +336,7 @@ public: * sort the flat list by Time Stamp. * Useful to detect duplicate Time Stamps */ - void SortComponentsByTimeStamp() + void SortByTimeStamp() { sort( componentFlatList.begin(), componentFlatList.end(), sortByTimeStamp ); } @@ -417,6 +448,19 @@ private: static bool sortByValueOnly( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); static bool sortByReferenceOnly( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); + + /** + * Function CreateFirstFreeRefId + * searches for the first free reference number in \a aListId of reference numbers in use. + * This function just searches for a hole in a list of incremented numbers, this list must + * be sorted by increasing values and each value can be stored only once. The new value + * is added to the list. + * @see BuildRefIdInUseList to prepare this list + * @param aIdList The buffer that contains the reference numbers in use. + * @param aFirstValue The first expected free value + * @return The first free (not yet used) value. + */ + int CreateFirstFreeRefId( std::vector& aIdList, int aFirstValue ); }; diff --git a/eeschema/sch_sheet_path.cpp b/eeschema/sch_sheet_path.cpp index 0dce4df9e7..cbfa7e2c5b 100644 --- a/eeschema/sch_sheet_path.cpp +++ b/eeschema/sch_sheet_path.cpp @@ -341,7 +341,7 @@ void SCH_SHEET_PATH::GetComponents( SCH_REFERENCE_LIST& aReferences, continue; SCH_REFERENCE reference = SCH_REFERENCE( component, entry, *this ); - reference.m_SheetNum = sheetnumber; + reference.SetSheetNumber( sheetnumber ); aReferences.AddItem( reference ); } } diff --git a/pcbnew/block.cpp b/pcbnew/block.cpp index cb4f947af4..dd54b07dc6 100644 --- a/pcbnew/block.cpp +++ b/pcbnew/block.cpp @@ -118,6 +118,7 @@ DIALOG_BLOCK_OPTIONS::DIALOG_BLOCK_OPTIONS( WinEDA_BasePcbFrame* aParent, m_Include_Edges_Items->SetValue( blockIncludeBoardOutlineLayer ); m_Include_PcbTextes->SetValue( blockIncludePcbTexts ); m_DrawBlockItems->SetValue( blockDrawItems ); + m_sdbSizer1OK->SetDefault(); SetFocus(); GetSizer()->SetSizeHints( this ); Centre();