Commit 1e2e1442 authored by Wayne Stambaugh's avatar Wayne Stambaugh

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.
parent c42af938
......@@ -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,227 +156,32 @@ void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic,
}
// Recalculate and update reference numbers in schematic
ComputeReferenceNumber( references, useSheetNum, idStep );
references.Annotate( useSheetNum, idStep );
references.UpdateAnnotation();
/* Final control (just in case ... )*/
CheckAnnotate( NULL, !aAnnotateSchematic );
OnModify();
// Update on screen references, that can be modified by previous calculations:
m_CurrentSheet->UpdateAllScreenReferences();
SetSheetNumberAndCount();
DrawPanel->Refresh( true );
}
#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<int>& 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::vector<int>idList;
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;
wxArrayString errors;
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 )
/* Final control (just in case ... )*/
if( CheckAnnotate( &errors, !aAnnotateSchematic ) )
{
#ifdef USE_OLD_ALGO
LastReferenceNumber++;
#else
LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
#endif
aComponentsList[ii].m_NumRef = LastReferenceNumber;
wxString msg;
if( !aComponentsList[ii].IsPartsLocked() )
aComponentsList[ii].m_Unit = 1;
for( size_t i = 0; i < errors.GetCount(); i++ )
msg += errors[i];
aComponentsList[ii].m_Flag = 1;
// 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 );
}
/* 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;
OnModify();
if( !aComponentsList[jj].m_IsNew )
continue;
// Update on screen references, that can be modified by previous calculations:
m_CurrentSheet->UpdateAllScreenReferences();
SetSheetNumberAndCount();
/* 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;
}
}
}
}
DrawPanel->Refresh( true );
}
......@@ -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 );
}
......@@ -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;
......@@ -272,6 +272,391 @@ int SCH_REFERENCE_LIST::GetLastReference( int aIndex, int aMinValue )
}
int SCH_REFERENCE_LIST::CreateFirstFreeRefId( std::vector<int>& 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::vector<int>idList;
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 );
}
}
......@@ -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();
......
......@@ -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.
* <p>
* 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
* </p>
*/
void Annotate( bool aUseSheetNum, int aSheetIntervalId );
/**
* Function CheckAnnotation
* check for annotations errors.
* <p>
* The following annotation error conditions are tested:
* <ul>
* <li>Components not annotated.</li>
* <li>Components having the same reference designator (duplicates).</li>
* <li>Components with multiple parts per package having different reference designators.</li>
* <li>Components with multiple parts per package with invalid part count.</li>
* </ul>
* </p>
* @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<int>& aIdList, int aFirstValue );
};
......
......@@ -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 );
}
}
......
......@@ -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();
......
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