Bug fixes for multiple symbol instances in complex hierarchies

1) use SCH_COMPONENT::GetRef(), GetValue() and GetFootprint() when
instance-specific info is needed
2) update UpdateAllScreenReferences() to handle value and footprint.
3) BACKANNO is CvPcb's handler, not back annotation's handler.  Which
means it needs GUI behaviour, not back annotation behaviour.

Fixes https://gitlab.com/kicad/code/kicad/issues/5520
This commit is contained in:
Jeff Young 2020-09-06 13:05:07 +01:00
parent b28332c5f1
commit 7b05e456cc
15 changed files with 101 additions and 64 deletions

View File

@ -587,17 +587,9 @@ void CVPCB_MAINFRAME::SetFootprintFilter( FOOTPRINTS_LISTBOX::FP_FILTER_T aFilte
// Apply the filter accordingly // Apply the filter accordingly
switch( aAction ) switch( aAction )
{ {
case CVPCB_MAINFRAME::FILTER_DISABLE: case CVPCB_MAINFRAME::FILTER_DISABLE: m_filteringOptions &= ~option; break;
m_filteringOptions &= ~option; case CVPCB_MAINFRAME::FILTER_ENABLE: m_filteringOptions |= option; break;
break; case CVPCB_MAINFRAME::FILTER_TOGGLE: m_filteringOptions ^= option; break;
case CVPCB_MAINFRAME::FILTER_ENABLE:
m_filteringOptions |= option;
break;
case CVPCB_MAINFRAME::FILTER_TOGGLE:
m_filteringOptions ^= option;
break;
} }
wxListEvent l_event; wxListEvent l_event;

View File

@ -216,13 +216,13 @@ void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic,
if( comp->GetUnitCount() > 1 ) if( comp->GetUnitCount() > 1 )
msg.Printf( _( "Updated %s (unit %s) from %s to %s" ), msg.Printf( _( "Updated %s (unit %s) from %s to %s" ),
comp->GetField( VALUE )->GetShownText(), comp->GetValue( sheet ),
LIB_PART::SubReference( comp->GetUnit(), false ), LIB_PART::SubReference( comp->GetUnit(), false ),
prevRef, prevRef,
newRef ); newRef );
else else
msg.Printf( _( "Updated %s from %s to %s" ), msg.Printf( _( "Updated %s from %s to %s" ),
comp->GetField( VALUE )->GetShownText(), comp->GetValue( sheet ),
prevRef, prevRef,
newRef ); newRef );
} }
@ -230,12 +230,12 @@ void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic,
{ {
if( comp->GetUnitCount() > 1 ) if( comp->GetUnitCount() > 1 )
msg.Printf( _( "Annotated %s (unit %s) as %s" ), msg.Printf( _( "Annotated %s (unit %s) as %s" ),
comp->GetField( VALUE )->GetShownText(), comp->GetValue( sheet ),
LIB_PART::SubReference( comp->GetUnit(), false ), LIB_PART::SubReference( comp->GetUnit(), false ),
newRef ); newRef );
else else
msg.Printf( _( "Annotated %s as %s" ), msg.Printf( _( "Annotated %s as %s" ),
comp->GetField( VALUE )->GetShownText(), comp->GetValue( sheet ),
newRef ); newRef );
} }

View File

@ -686,8 +686,8 @@ SCH_REFERENCE::SCH_REFERENCE( SCH_COMPONENT* aComponent, LIB_PART* aLibPart,
m_NumRef = -1; m_NumRef = -1;
if( aComponent->GetField( VALUE )->GetText().IsEmpty() ) if( aComponent->GetValue( &aSheetPath ).IsEmpty() )
aComponent->GetField( VALUE )->SetText( wxT( "~" ) ); aComponent->SetValue( &aSheetPath, wxT( "~" ) );
m_Value = aComponent->GetValue( &aSheetPath ); m_Value = aComponent->GetValue( &aSheetPath );
} }

View File

@ -70,12 +70,13 @@ DIALOG_CHANGE_SYMBOLS::DIALOG_CHANGE_SYMBOLS( SCH_EDIT_FRAME* aParent, SCH_COMPO
if( m_symbol ) if( m_symbol )
{ {
SCH_SHEET_PATH* currentSheet = &aParent->Schematic().CurrentSheet();
label.Printf( m_matchBySelection->GetLabel(), verb ); label.Printf( m_matchBySelection->GetLabel(), verb );
m_matchBySelection->SetLabel( label ); m_matchBySelection->SetLabel( label );
m_newId->AppendText( FROM_UTF8( m_symbol->GetLibId().Format().c_str() ) ); m_newId->AppendText( FROM_UTF8( m_symbol->GetLibId().Format().c_str() ) );
m_specifiedReference->ChangeValue( m_specifiedReference->ChangeValue( m_symbol->GetRef( currentSheet ) );
m_symbol->GetRef( &aParent->Schematic().CurrentSheet() ) ); m_specifiedValue->ChangeValue( m_symbol->GetValue( currentSheet ) );
m_specifiedValue->ChangeValue( m_symbol->GetField( VALUE )->GetText() );
m_specifiedId->ChangeValue( FROM_UTF8( m_symbol->GetLibId().Format().c_str() ) ); m_specifiedId->ChangeValue( FROM_UTF8( m_symbol->GetLibId().Format().c_str() ) );
} }
else else
@ -216,15 +217,23 @@ bool DIALOG_CHANGE_SYMBOLS::isMatch( SCH_COMPONENT* aSymbol, SCH_SHEET_PATH* aIn
wxCHECK( frame, false ); wxCHECK( frame, false );
if( m_matchAll->GetValue() ) if( m_matchAll->GetValue() )
{
return true; return true;
}
else if( m_matchBySelection->GetValue() ) else if( m_matchBySelection->GetValue() )
{
return aSymbol == m_symbol; return aSymbol == m_symbol;
}
else if( m_matchByReference->GetValue() ) else if( m_matchByReference->GetValue() )
{
return WildCompareString( m_specifiedReference->GetValue(), aSymbol->GetRef( aInstance ), return WildCompareString( m_specifiedReference->GetValue(), aSymbol->GetRef( aInstance ),
false ); false );
}
else if( m_matchByValue->GetValue() ) else if( m_matchByValue->GetValue() )
return WildCompareString( m_specifiedValue->GetValue(), {
aSymbol->GetField( VALUE )->GetText(), false ); return WildCompareString( m_specifiedValue->GetValue(), aSymbol->GetValue( aInstance ),
false );
}
else if( m_matchById ) else if( m_matchById )
{ {
id.Parse( m_specifiedId->GetValue(), LIB_ID::ID_SCH ); id.Parse( m_specifiedId->GetValue(), LIB_ID::ID_SCH );

View File

@ -661,6 +661,11 @@ bool DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::TransferDataFromWindow()
// reference. // reference.
m_comp->SetRef( &GetParent()->GetCurrentSheet(), m_fields->at( REFERENCE ).GetText() ); m_comp->SetRef( &GetParent()->GetCurrentSheet(), m_fields->at( REFERENCE ).GetText() );
// Similar for Value and Footprint, except that the GUI behaviour is that they are kept
// in sync between multiple instances.
m_comp->SetValue( m_fields->at( VALUE ).GetText() );
m_comp->SetFootprint( m_fields->at( FOOTPRINT ).GetText() );
m_comp->SetIncludeInBom( !m_cbExcludeFromBom->IsChecked() ); m_comp->SetIncludeInBom( !m_cbExcludeFromBom->IsChecked() );
m_comp->SetIncludeOnBoard( !m_cbExcludeFromBoard->IsChecked() ); m_comp->SetIncludeOnBoard( !m_cbExcludeFromBoard->IsChecked() );

View File

@ -756,7 +756,7 @@ bool DIALOG_EDIT_COMPONENTS_LIBID::TransferDataFromWindow()
// If value is a proxy for the itemName then make sure it gets updated // If value is a proxy for the itemName then make sure it gets updated
if( cmp.m_Component->GetLibId().GetLibItemName().wx_str() == value->GetText() ) if( cmp.m_Component->GetLibId().GetLibItemName().wx_str() == value->GetText() )
value->SetText( id.GetLibItemName().wx_str() ); cmp.m_Component->SetValue( id.GetLibItemName().wx_str() );
cmp.m_Component->SetLibId( id ); cmp.m_Component->SetLibId( id );
cmp.m_Component->SetLibSymbol( symbol->Flatten().release() ); cmp.m_Component->SetLibSymbol( symbol->Flatten().release() );

View File

@ -393,10 +393,16 @@ void DIALOG_SCH_EDIT_ONE_FIELD::UpdateField( SCH_FIELD* aField, SCH_SHEET_PATH*
SCH_ITEM* parent = dynamic_cast<SCH_ITEM*>( aField->GetParent() ); SCH_ITEM* parent = dynamic_cast<SCH_ITEM*>( aField->GetParent() );
int fieldType = aField->GetId(); int fieldType = aField->GetId();
if( parent && parent->Type() == SCH_COMPONENT_T && fieldType == REFERENCE ) if( parent && parent->Type() == SCH_COMPONENT_T )
{ {
wxASSERT( aSheetPath ); SCH_COMPONENT* comp = static_cast<SCH_COMPONENT*>( parent );
static_cast<SCH_COMPONENT*>( parent )->SetRef( aSheetPath, m_text );
if( fieldType == REFERENCE )
comp->SetRef( aSheetPath, m_text );
else if( fieldType == VALUE )
comp->SetValue( m_text );
else if( fieldType == FOOTPRINT )
comp->SetFootprint( m_text );
} }
bool positioningModified = false; bool positioningModified = false;

View File

@ -88,7 +88,7 @@ bool NETLIST_EXPORTER_CADSTAR::WriteNetlist( const wxString& aOutFileName, unsig
ret |= fprintf( f, "%s ", TO_UTF8( StartCmpDesc ) ); ret |= fprintf( f, "%s ", TO_UTF8( StartCmpDesc ) );
ret |= fprintf( f, "%s", TO_UTF8( msg ) ); ret |= fprintf( f, "%s", TO_UTF8( msg ) );
msg = component->GetField( VALUE )->GetShownText(); msg = component->GetValue( &sheetList[i] );
msg.Replace( wxT( " " ), wxT( "_" ) ); msg.Replace( wxT( " " ), wxT( "_" ) );
ret |= fprintf( f, " \"%s\"", TO_UTF8( msg ) ); ret |= fprintf( f, " \"%s\"", TO_UTF8( msg ) );
ret |= fprintf( f, " \"%s\"", TO_UTF8( footprint ) ); ret |= fprintf( f, " \"%s\"", TO_UTF8( footprint ) );

View File

@ -121,20 +121,20 @@ void NETLIST_EXPORTER_GENERIC::addComponentFields( XNODE* xcomp, SCH_COMPONENT*
// The lowest unit number wins. User should only set fields in any one unit. // The lowest unit number wins. User should only set fields in any one unit.
// remark: IsVoid() returns true for empty strings or the "~" string (empty // remark: IsVoid() returns true for empty strings or the "~" string (empty
// field value) // field value)
if( !comp2->GetField( VALUE )->IsVoid() if( !comp2->GetValue( &sheetList[i] ).IsEmpty()
&& ( unit < minUnit || fields.value.IsEmpty() ) ) && ( unit < minUnit || fields.value.IsEmpty() ) )
{ {
if( m_resolveTextVars ) if( m_resolveTextVars )
fields.value = comp2->GetField( VALUE )->GetShownText(); fields.value = comp2->GetValue( &sheetList[i] );
else else
fields.value = comp2->GetField( VALUE )->GetText(); fields.value = comp2->GetField( VALUE )->GetText();
} }
if( !comp2->GetField( FOOTPRINT )->IsVoid() if( !comp2->GetFootprint( &sheetList[i] ).IsEmpty()
&& ( unit < minUnit || fields.footprint.IsEmpty() ) ) && ( unit < minUnit || fields.footprint.IsEmpty() ) )
{ {
if( m_resolveTextVars ) if( m_resolveTextVars )
fields.footprint = comp2->GetField( FOOTPRINT )->GetShownText(); fields.footprint = comp2->GetFootprint( &sheetList[i] );
else else
fields.footprint = comp2->GetField( FOOTPRINT )->GetText(); fields.footprint = comp2->GetField( FOOTPRINT )->GetText();
} }

View File

@ -83,26 +83,20 @@ bool NETLIST_EXPORTER_ORCADPCB2::WriteNetlist( const wxString& aOutFileName,
if( comp->GetPartRef() && comp->GetPartRef()->GetFootprints().GetCount() != 0 ) if( comp->GetPartRef() && comp->GetPartRef()->GetFootprints().GetCount() != 0 )
cmpList.push_back( SCH_REFERENCE( comp, comp->GetPartRef().get(), sheet ) ); cmpList.push_back( SCH_REFERENCE( comp, comp->GetPartRef().get(), sheet ) );
if( !comp->GetField( FOOTPRINT )->IsVoid() ) footprint = comp->GetFootprint( &sheet );
{
footprint = comp->GetField( FOOTPRINT )->GetShownText();
footprint.Replace( wxT( " " ), wxT( "_" ) ); footprint.Replace( wxT( " " ), wxT( "_" ) );
}
else
{
footprint = wxT( "$noname" );
}
field = comp->GetRef( &sheetList[i] );
ret |= fprintf( f, " ( %s %s", ret |= fprintf( f, " ( %s %s",
TO_UTF8( sheetList[i].PathAsString() + comp->m_Uuid.AsString() ), TO_UTF8( sheet.PathAsString() + comp->m_Uuid.AsString() ),
TO_UTF8( footprint ) ); TO_UTF8( footprint.IsEmpty() ? wxT( "$noname" ) : footprint ) );
field = comp->GetRef( &sheet );
ret |= fprintf( f, " %s", TO_UTF8( field ) ); ret |= fprintf( f, " %s", TO_UTF8( field ) );
field = comp->GetField( VALUE )->GetShownText(); field = comp->GetValue( &sheet );
field.Replace( wxT( " " ), wxT( "_" ) ); field.Replace( wxT( " " ), wxT( "_" ) );
ret |= fprintf( f, " %s", TO_UTF8( field ) ); ret |= fprintf( f, " %s", TO_UTF8( field ) );
ret |= fprintf( f, "\n" ); ret |= fprintf( f, "\n" );

View File

@ -569,7 +569,7 @@ const wxString SCH_COMPONENT::GetValue( const SCH_SHEET_PATH* sheet ) const
for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences ) for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
{ {
if( instance.m_Path == path && !instance.m_Footprint.IsEmpty() ) if( instance.m_Path == path && !instance.m_Value.IsEmpty() )
{ {
SCH_FIELD dummy( wxDefaultPosition, VALUE, const_cast<SCH_COMPONENT*>( this ) ); SCH_FIELD dummy( wxDefaultPosition, VALUE, const_cast<SCH_COMPONENT*>( this ) );
dummy.SetText( instance.m_Value ); dummy.SetText( instance.m_Value );
@ -583,6 +583,16 @@ const wxString SCH_COMPONENT::GetValue( const SCH_SHEET_PATH* sheet ) const
void SCH_COMPONENT::SetValue( const SCH_SHEET_PATH* sheet, const wxString& aValue ) void SCH_COMPONENT::SetValue( const SCH_SHEET_PATH* sheet, const wxString& aValue )
{ {
if( sheet == nullptr )
{
// Clear instance overrides and set primary field value
for( COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
instance.m_Value = wxEmptyString;
m_Fields[ VALUE ].SetText( aValue );
return;
}
KIID_PATH path = sheet->Path(); KIID_PATH path = sheet->Path();
// check to see if it is already there before inserting it // check to see if it is already there before inserting it
@ -620,6 +630,16 @@ const wxString SCH_COMPONENT::GetFootprint( const SCH_SHEET_PATH* sheet ) const
void SCH_COMPONENT::SetFootprint( const SCH_SHEET_PATH* sheet, const wxString& aFootprint ) void SCH_COMPONENT::SetFootprint( const SCH_SHEET_PATH* sheet, const wxString& aFootprint )
{ {
if( sheet == nullptr )
{
// Clear instance overrides and set primary field value
for( COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
instance.m_Value = wxEmptyString;
m_Fields[ FOOTPRINT ].SetText( aFootprint );
return;
}
KIID_PATH path = sheet->Path(); KIID_PATH path = sheet->Path();
// check to see if it is already there before inserting it // check to see if it is already there before inserting it
@ -1298,21 +1318,18 @@ void SCH_COMPONENT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, MSG_PANEL_ITEMS& aL
wxString msg; wxString msg;
SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame ); SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
// part and alias can differ if alias is not the root // part and alias can differ if alias is not the root
if( m_part ) if( m_part )
{ {
if( m_part.get() != dummy() ) if( m_part.get() != dummy() )
{ {
if( schframe ) aList.push_back( MSG_PANEL_ITEM( _( "Reference" ), GetRef( currentSheet ), DARKCYAN ) );
{
aList.push_back( MSG_PANEL_ITEM(
_( "Reference" ), GetRef( &schframe->GetCurrentSheet() ), DARKCYAN ) );
}
msg = m_part->IsPower() ? _( "Power symbol" ) : _( "Value" ); msg = m_part->IsPower() ? _( "Power symbol" ) : _( "Value" );
aList.push_back( MSG_PANEL_ITEM( msg, GetField( VALUE )->GetShownText(), DARKCYAN ) ); aList.push_back( MSG_PANEL_ITEM( msg, GetValue( currentSheet ), DARKCYAN ) );
#if 0 // Display component flags, for debug only #if 0 // Display component flags, for debug only
aList.push_back( MSG_PANEL_ITEM( _( "flags" ), aList.push_back( MSG_PANEL_ITEM( _( "flags" ),
@ -1344,7 +1361,7 @@ void SCH_COMPONENT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, MSG_PANEL_ITEMS& aL
} }
// Display the current associated footprint, if exists. // Display the current associated footprint, if exists.
msg = GetFootprint( &schframe->GetCurrentSheet() ); msg = GetFootprint( currentSheet );
if( msg.IsEmpty() ) if( msg.IsEmpty() )
msg = _( "<Unknown>" ); msg = _( "<Unknown>" );
@ -1359,14 +1376,9 @@ void SCH_COMPONENT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, MSG_PANEL_ITEMS& aL
} }
else else
{ {
if( schframe ) aList.push_back( MSG_PANEL_ITEM( _( "Reference" ), GetRef( currentSheet ), DARKCYAN ) );
{
aList.push_back( MSG_PANEL_ITEM(
_( "Reference" ), GetRef( &schframe->GetCurrentSheet() ), DARKCYAN ) );
}
aList.push_back( MSG_PANEL_ITEM( _( "Value" ), GetField( VALUE )->GetShownText(), aList.push_back( MSG_PANEL_ITEM( _( "Value" ), GetValue( currentSheet ), DARKCYAN ) );
DARKCYAN ) );
aList.push_back( MSG_PANEL_ITEM( _( "Name" ), GetLibId().GetLibItemName(), BROWN ) ); aList.push_back( MSG_PANEL_ITEM( _( "Name" ), GetLibId().GetLibItemName(), BROWN ) );
wxString libNickname = GetLibId().GetLibNickname(); wxString libNickname = GetLibId().GetLibNickname();

View File

@ -556,10 +556,22 @@ public:
const wxString GetValue( const SCH_SHEET_PATH* sheet ) const; const wxString GetValue( const SCH_SHEET_PATH* sheet ) const;
void SetValue( const SCH_SHEET_PATH* sheet, const wxString& aValue ); void SetValue( const SCH_SHEET_PATH* sheet, const wxString& aValue );
// Set the value for all instances (the default GUI behaviour)
void SetValue( const wxString& aValue )
{
SetValue( nullptr, aValue );
}
// Returns the instance-specific footprint assignment for the given sheet path. // Returns the instance-specific footprint assignment for the given sheet path.
const wxString GetFootprint( const SCH_SHEET_PATH* sheet ) const; const wxString GetFootprint( const SCH_SHEET_PATH* sheet ) const;
void SetFootprint( const SCH_SHEET_PATH* sheet, const wxString& aFootprint ); void SetFootprint( const SCH_SHEET_PATH* sheet, const wxString& aFootprint );
// Set the value for all instances (the default GUI behaviour)
void SetFootprint( const wxString& aFootprint )
{
SetFootprint( nullptr, aFootprint );
}
// Geometric transforms (used in block operations): // Geometric transforms (used in block operations):
void Move( const wxPoint& aMoveVector ) override void Move( const wxPoint& aMoveVector ) override

View File

@ -183,8 +183,11 @@ void SCH_PIN::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, MSG_PANEL_ITEMS& aList )
msg = MessageTextFromValue( aFrame->GetUserUnits(), m_position.y, true ); msg = MessageTextFromValue( aFrame->GetUserUnits(), m_position.y, true );
aList.emplace_back( _( "Pos Y" ), msg, DARKMAGENTA ); aList.emplace_back( _( "Pos Y" ), msg, DARKMAGENTA );
aList.emplace_back( GetParentComponent()->GetField( REFERENCE )->GetShownText(), SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
GetParentComponent()->GetField( VALUE )->GetShownText(), DARKCYAN ); SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
SCH_COMPONENT* comp = GetParentComponent();
aList.emplace_back( comp->GetRef( currentSheet ), comp->GetValue( currentSheet ), DARKCYAN );
#if defined(DEBUG) #if defined(DEBUG)

View File

@ -248,6 +248,8 @@ void SCH_SHEET_PATH::UpdateAllScreenReferences()
{ {
auto component = static_cast<SCH_COMPONENT*>( item ); auto component = static_cast<SCH_COMPONENT*>( item );
component->GetField( REFERENCE )->SetText( component->GetRef( this ) ); component->GetField( REFERENCE )->SetText( component->GetRef( this ) );
component->GetField( VALUE )->SetText( component->GetValue( this ) );
component->GetField( FOOTPRINT )->SetText( component->GetFootprint( this ) );
component->UpdateUnit( component->GetUnitSelection( this ) ); component->UpdateUnit( component->GetUnitSelection( this ) );
} }
} }

View File

@ -86,7 +86,9 @@ void SCH_EDITOR_CONTROL::BackAnnotateFootprints( const std::string& aChangedSetO
// Note: it can be not unique (multiple parts per package) // Note: it can be not unique (multiple parts per package)
// So we *do not* stop the search here // So we *do not* stop the search here
SCH_COMPONENT* component = refs[ii].GetComp(); SCH_COMPONENT* component = refs[ii].GetComp();
SCH_SHEET_PATH* sheetPath = &refs[ii].GetSheetPath(); // For backwards-compatibility CvPcb currently updates all instances of a
// component (even though it lists these instances separately).
SCH_SHEET_PATH* sheetPath = nullptr; // &refs[ii].GetSheetPath();
wxString oldfp = refs[ii].GetFootprint(); wxString oldfp = refs[ii].GetFootprint();
if( oldfp.IsEmpty() && component->GetField( FOOTPRINT )->IsVisible() ) if( oldfp.IsEmpty() && component->GetField( FOOTPRINT )->IsVisible() )