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();