kicad-source/eeschema/dialogs/dialog_change_symbols.cpp
Jeff Young e478c4db2e Allow resetting of pin visibility overrides.
Also fixes a bug where the .fbp file didn't get checked
in for the "Reset custom power symbols" checkbox addition.

Also adds disabled checkboxes to act as hints for what
is always updated.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17868
2024-04-27 13:30:45 +01:00

850 lines
28 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020-2021 CERN
* Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Wayne Stambaugh <stambaughw@gmail.com>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <bitmaps.h>
#include <connection_graph.h>
#include <string_utils.h> // WildCompareString
#include <kiway.h>
#include <refdes_utils.h>
#include <core/kicad_algo.h>
#include <dialog_change_symbols.h>
#include <sch_symbol.h>
#include <sch_edit_frame.h>
#include <sch_screen.h>
#include <schematic.h>
#include <template_fieldnames.h>
#include <widgets/wx_html_report_panel.h>
#include <widgets/std_bitmap_button.h>
#include <sch_commit.h>
bool g_selectRefDes = false;
bool g_selectValue = false;
// { change, update }
bool g_removeExtraFields[2] = { false, false };
bool g_resetEmptyFields[2] = { false, false };
bool g_resetFieldText[2] = { true, true };
bool g_resetFieldVisibilities[2] = { true, false };
bool g_resetFieldEffects[2] = { true, false };
bool g_resetFieldPositions[2] = { true, false };
bool g_resetAttributes[2] = { true, false };
bool g_resetCustomPower[2] = { false, false };
DIALOG_CHANGE_SYMBOLS::DIALOG_CHANGE_SYMBOLS( SCH_EDIT_FRAME* aParent, SCH_SYMBOL* aSymbol,
MODE aMode ) :
DIALOG_CHANGE_SYMBOLS_BASE( aParent ),
m_symbol( aSymbol),
m_mode( aMode )
{
wxASSERT( aParent );
if( m_mode == MODE::UPDATE )
{
m_newIdSizer->Show( false );
}
else
{
m_matchAll->SetLabel( _( "Change all symbols in schematic" ) );
SetTitle( _( "Change Symbols" ) );
m_matchSizer->FindItem( m_matchAll )->Show( false );
}
if( m_symbol )
{
SCH_SHEET_PATH* currentSheet = &aParent->Schematic().CurrentSheet();
if( m_mode == MODE::CHANGE )
m_matchBySelection->SetLabel( _( "Change selected symbol(s)" ) );
m_newId->ChangeValue( UnescapeString( m_symbol->GetLibId().Format() ) );
m_specifiedReference->ChangeValue( m_symbol->GetRef( currentSheet ) );
m_specifiedValue->ChangeValue( UnescapeString( m_symbol->GetField( VALUE_FIELD )->GetText() ) );
m_specifiedId->ChangeValue( UnescapeString( m_symbol->GetLibId().Format() ) );
}
else
{
m_matchSizer->FindItem( m_matchBySelection )->Show( false );
}
m_matchIdBrowserButton->SetBitmap( KiBitmapBundle( BITMAPS::small_library ) );
m_newIdBrowserButton->SetBitmap( KiBitmapBundle( BITMAPS::small_library ) );
if( m_mode == MODE::CHANGE )
{
m_matchByReference->SetLabel( _( "Change symbols matching reference designator:" ) );
m_matchByValue->SetLabel( _( "Change symbols matching value:" ) );
m_matchById->SetLabel( _( "Change symbols matching library identifier:" ) );
}
m_matchSizer->SetEmptyCellSize( wxSize( 0, 0 ) );
m_matchSizer->Layout();
for( int i = 0; i < MANDATORY_FIELDS; ++i )
{
m_fieldsBox->Append( TEMPLATE_FIELDNAME::GetDefaultFieldName( i, DO_TRANSLATE ) );
if( i == REFERENCE_FIELD )
m_fieldsBox->Check( i, g_selectRefDes );
else if( i == VALUE_FIELD )
m_fieldsBox->Check( i, g_selectValue );
else
m_fieldsBox->Check( i, true );
}
m_messagePanel->SetLazyUpdate( true );
m_messagePanel->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
if( aSymbol && aSymbol->IsSelected() )
{
m_matchBySelection->SetValue( true );
}
else
{
if( aMode == MODE::UPDATE )
m_matchAll->SetValue( true );
else
m_matchByReference->SetValue( true );
}
updateFieldsList();
if( m_mode == MODE::CHANGE )
{
m_updateFieldsSizer->GetStaticBox()->SetLabel( _( "Update Fields" ) );
m_removeExtraBox->SetLabel( _( "Remove fields if not in new symbol" ) );
m_resetEmptyFields->SetLabel( _( "Reset fields if empty in new symbol" ) );
m_resetFieldText->SetLabel( _( "Update field text" ) );
m_resetFieldVisibilities->SetLabel( _( "Update field visibilities" ) );
m_resetFieldEffects->SetLabel( _( "Update field sizes and styles" ) );
m_resetFieldPositions->SetLabel( _( "Update field positions" ) );
m_resetAttributes->SetLabel( _( "Update symbol attributes" ) );
}
m_removeExtraBox->SetValue( g_removeExtraFields[ (int) m_mode ] );
m_resetEmptyFields->SetValue( g_resetEmptyFields[ (int) m_mode ] );
m_resetFieldText->SetValue( g_resetFieldText[ (int) m_mode ] );
m_resetFieldVisibilities->SetValue( g_resetFieldVisibilities[ (int) m_mode ] );
m_resetFieldEffects->SetValue( g_resetFieldEffects[ (int) m_mode ] );
m_resetFieldPositions->SetValue( g_resetFieldPositions[ (int) m_mode ] );
m_resetAttributes->SetValue( g_resetAttributes[ (int) m_mode ] );
m_resetCustomPower->SetValue( g_resetCustomPower[ (int) m_mode ] );
// DIALOG_SHIM needs a unique hash_key because classname is not sufficient
// because the update and change versions of this dialog have different controls.
m_hash_key = TO_UTF8( GetTitle() );
wxString okLabel = m_mode == MODE::CHANGE ? _( "Change" ) : _( "Update" );
SetupStandardButtons( { { wxID_OK, okLabel },
{ wxID_CANCEL, _( "Close" ) } } );
// Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings();
}
void DIALOG_CHANGE_SYMBOLS::onMatchByAll( wxCommandEvent& aEvent )
{
updateFieldsList();
}
void DIALOG_CHANGE_SYMBOLS::onMatchBySelected( wxCommandEvent& aEvent )
{
updateFieldsList();
}
void DIALOG_CHANGE_SYMBOLS::onMatchByReference( wxCommandEvent& aEvent )
{
updateFieldsList();
m_specifiedReference->SetFocus();
}
void DIALOG_CHANGE_SYMBOLS::onMatchByValue( wxCommandEvent& aEvent )
{
updateFieldsList();
m_specifiedValue->SetFocus();
}
void DIALOG_CHANGE_SYMBOLS::onMatchById( wxCommandEvent& aEvent )
{
updateFieldsList();
m_specifiedId->SetFocus();
}
void DIALOG_CHANGE_SYMBOLS::onMatchTextKillFocus( wxFocusEvent& event )
{
updateFieldsList();
event.Skip(); // Mandatory in wxFocusEvent
}
void DIALOG_CHANGE_SYMBOLS::onMatchIDKillFocus( wxFocusEvent& event )
{
updateFieldsList();
event.Skip(); // Mandatory in wxFocusEvent
}
void DIALOG_CHANGE_SYMBOLS::onNewLibIDKillFocus( wxFocusEvent& event )
{
updateFieldsList();
event.Skip(); // Mandatory in wxFocusEvent
}
DIALOG_CHANGE_SYMBOLS::~DIALOG_CHANGE_SYMBOLS()
{
g_selectRefDes = m_fieldsBox->IsChecked( REFERENCE_FIELD );
g_selectValue = m_fieldsBox->IsChecked( VALUE_FIELD );
g_removeExtraFields[ (int) m_mode ] = m_removeExtraBox->GetValue();
g_resetEmptyFields[ (int) m_mode ] = m_resetEmptyFields->GetValue();
g_resetFieldText[ (int) m_mode ] = m_resetFieldText->GetValue();
g_resetFieldVisibilities[ (int) m_mode ] = m_resetFieldVisibilities->GetValue();
g_resetFieldEffects[ (int) m_mode ] = m_resetFieldEffects->GetValue();
g_resetFieldPositions[ (int) m_mode ] = m_resetFieldPositions->GetValue();
g_resetAttributes[ (int) m_mode ] = m_resetAttributes->GetValue();
g_resetCustomPower[ (int) m_mode ] = m_resetCustomPower->GetValue();
}
wxString getLibIdValue( const wxTextCtrl* aCtrl )
{
wxString rawValue = aCtrl->GetValue();
wxString itemName;
wxString libName = rawValue.BeforeFirst( ':', &itemName );
return EscapeString( libName, CTX_LIBID ) + ':' + EscapeString( itemName, CTX_LIBID );
}
void DIALOG_CHANGE_SYMBOLS::launchMatchIdSymbolBrowser( wxCommandEvent& aEvent )
{
wxString newName = getLibIdValue( m_specifiedId );
KIWAY_PLAYER* frame = Kiway().Player( FRAME_SYMBOL_CHOOSER, true, this );
if( frame->ShowModal( &newName, this ) )
{
m_specifiedId->SetValue( UnescapeString( newName ) );
updateFieldsList();
}
frame->Destroy();
}
void DIALOG_CHANGE_SYMBOLS::launchNewIdSymbolBrowser( wxCommandEvent& aEvent )
{
wxString newName = getLibIdValue( m_newId );
KIWAY_PLAYER* frame = Kiway().Player( FRAME_SYMBOL_CHOOSER, true, this );
if( frame->ShowModal( &newName, this ) )
{
m_newId->SetValue( UnescapeString( newName ) );
updateFieldsList();
}
frame->Destroy();
}
void DIALOG_CHANGE_SYMBOLS::updateFieldsList()
{
SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
wxCHECK( frame, /* void */ );
SCH_SHEET_LIST hierarchy = frame->Schematic().GetSheets();
// Load non-mandatory fields from all matching symbols and their library symbols
std::vector<SCH_FIELD*> fields;
std::vector<SCH_FIELD*> libFields;
std::set<wxString> fieldNames;
for( SCH_SHEET_PATH& instance : hierarchy )
{
SCH_SCREEN* screen = instance.LastScreen();
wxCHECK2( screen, continue );
for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
{
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
wxCHECK2( symbol, continue );
if( !isMatch( symbol, &instance ) )
continue;
fields.clear();
symbol->GetFields( fields, false );
for( unsigned i = MANDATORY_FIELDS; i < fields.size(); ++i )
fieldNames.insert( fields[i]->GetName() );
if( m_mode == MODE::UPDATE && symbol->GetLibId().IsValid() )
{
LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol->GetLibId() );
if( libSymbol )
{
std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
flattenedSymbol->GetFields( libFields );
for( unsigned i = MANDATORY_FIELDS; i < libFields.size(); ++i )
fieldNames.insert( libFields[i]->GetName() );
libFields.clear(); // flattenedSymbol is about to go out of scope...
}
}
}
}
// Load non-mandatory fields from the change-to library symbol
if( m_mode == MODE::CHANGE )
{
LIB_ID newId;
newId.Parse( getLibIdValue( m_newId ) );
if( newId.IsValid() )
{
LIB_SYMBOL* libSymbol = frame->GetLibSymbol( newId );
if( libSymbol )
{
std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
flattenedSymbol->GetFields( libFields );
for( unsigned i = MANDATORY_FIELDS; i < libFields.size(); ++i )
fieldNames.insert( libFields[i]->GetName() );
libFields.clear(); // flattenedSymbol is about to go out of scope...
}
}
}
// Update the listbox widget
wxArrayInt checkedItems;
wxArrayString checkedNames;
m_fieldsBox->GetCheckedItems( checkedItems );
for( int ii : checkedItems )
checkedNames.push_back( m_fieldsBox->GetString( ii ) );
bool allChecked = true;
for( unsigned ii = 0; ii < m_fieldsBox->GetCount(); ++ii )
{
if( ii == REFERENCE_FIELD || ii == VALUE_FIELD )
continue;
if( !m_fieldsBox->IsChecked( ii ) )
allChecked = false;
}
for( unsigned ii = m_fieldsBox->GetCount() - 1; ii >= MANDATORY_FIELDS; --ii )
m_fieldsBox->Delete( ii );
for( const wxString& fieldName : fieldNames )
{
m_fieldsBox->Append( fieldName );
if( allChecked || alg::contains( checkedNames, fieldName ) )
m_fieldsBox->Check( m_fieldsBox->GetCount() - 1, true );
}
}
void DIALOG_CHANGE_SYMBOLS::checkAll( bool aCheck )
{
for( unsigned i = 0; i < m_fieldsBox->GetCount(); ++i )
m_fieldsBox->Check( i, aCheck );
}
void DIALOG_CHANGE_SYMBOLS::onOkButtonClicked( wxCommandEvent& aEvent )
{
SCH_EDIT_FRAME* parent = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
wxCHECK( parent, /* void */ );
wxBusyCursor dummy;
SCH_COMMIT commit( parent );
m_messagePanel->Clear();
m_messagePanel->Flush( false );
// Create the set of fields to be updated. Use non translated (canonical) names
// for mandatory fields
m_updateFields.clear();
for( unsigned i = 0; i < m_fieldsBox->GetCount(); ++i )
{
if( m_fieldsBox->IsChecked( i ) )
{
if( i < MANDATORY_FIELDS )
{
SCH_FIELD dummy_field( nullptr, i );
m_updateFields.insert( dummy_field.GetCanonicalName() );
}
else
{
m_updateFields.insert( m_fieldsBox->GetString( i ) );
}
}
}
if( processMatchingSymbols( &commit) )
commit.Push( m_mode == MODE::CHANGE ? _( "Change Symbols" ) : _( "Update Symbols" ) );
m_messagePanel->Flush( false );
}
bool DIALOG_CHANGE_SYMBOLS::isMatch( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH* aInstance )
{
LIB_ID id;
wxCHECK( aSymbol, false );
SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
wxCHECK( frame, false );
if( m_matchAll->GetValue() )
{
return true;
}
else if( m_matchBySelection->GetValue() )
{
return aSymbol == m_symbol || aSymbol->IsSelected();
}
else if( m_matchByReference->GetValue() )
{
return WildCompareString( m_specifiedReference->GetValue(),
UnescapeString( aSymbol->GetRef( aInstance, false ) ),
false );
}
else if( m_matchByValue->GetValue() )
{
return WildCompareString( m_specifiedValue->GetValue(),
UnescapeString( aSymbol->GetField( VALUE_FIELD )->GetText() ),
false );
}
else if( m_matchById )
{
id.Parse( getLibIdValue( m_specifiedId ) );
return aSymbol->GetLibId() == id;
}
return false;
}
int DIALOG_CHANGE_SYMBOLS::processMatchingSymbols( SCH_COMMIT* aCommit )
{
SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
wxCHECK( frame, false );
LIB_ID newId;
wxString msg;
int matchesProcessed = 0;
SCH_SYMBOL* symbol = nullptr;
SCH_SHEET_LIST hierarchy = frame->Schematic().GetSheets();
if( m_mode == MODE::CHANGE )
{
newId.Parse( getLibIdValue( m_newId ) );
if( !newId.IsValid() )
return false;
}
std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO> symbols;
for( SCH_SHEET_PATH& instance : hierarchy )
{
SCH_SCREEN* screen = instance.LastScreen();
wxCHECK2( screen, continue );
// Fetch all the symbols that meet the change criteria.
for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
{
symbol = static_cast<SCH_SYMBOL*>( item );
wxCHECK2( symbol, continue );
if( !isMatch( symbol, &instance ) )
continue;
if( m_mode == MODE::UPDATE )
newId = symbol->GetLibId();
auto it = symbols.find( symbol );
if( it == symbols.end() )
{
SYMBOL_CHANGE_INFO info;
info.m_Instances.emplace_back( instance );
info.m_LibId = newId;
symbols.insert( { symbol, info } );
}
else
{
it->second.m_Instances.emplace_back( instance );
}
}
}
if( symbols.size() > 0 )
matchesProcessed += processSymbols( aCommit, symbols );
else
m_messagePanel->Report( _( "*** No symbols matching criteria found ***" ),
RPT_SEVERITY_ERROR );
frame->GetCurrentSheet().UpdateAllScreenReferences();
return matchesProcessed;
}
int DIALOG_CHANGE_SYMBOLS::processSymbols( SCH_COMMIT* aCommit,
const std::map<SCH_SYMBOL*,
SYMBOL_CHANGE_INFO>& aSymbols )
{
wxCHECK( !aSymbols.empty(), 0 );
int matchesProcessed = 0;
SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
wxString msg;
wxCHECK( frame, 0 );
std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO> symbols = aSymbols;
std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO>::iterator it = symbols.begin();
// Remove all symbols that don't have a valid library symbol link or enough units to
// satify the library symbol update.
while( it != symbols.end() )
{
SCH_SYMBOL* symbol = it->first;
wxCHECK2( symbol && it->second.m_LibId.IsValid(), continue );
LIB_SYMBOL* libSymbol = frame->GetLibSymbol( it->second.m_LibId );
if( !libSymbol )
{
msg = getSymbolReferences( *symbol, it->second.m_LibId );
msg << wxT( ": " ) << _( "*** symbol not found ***" );
m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
it = symbols.erase( it );
continue;
}
std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
if( flattenedSymbol->GetUnitCount() < symbol->GetUnit() )
{
msg = getSymbolReferences( *symbol, it->second.m_LibId );
msg << wxT( ": " ) << _( "*** new symbol has too few units ***" );
m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
it = symbols.erase( it );
}
else
{
++it;
}
}
// Removing the symbol needs to be done before the LIB_SYMBOL is changed to prevent stale
// library symbols in the schematic file.
for( const auto& [ symbol, symbol_change_info ] : symbols )
{
wxCHECK( symbol && !symbol_change_info.m_Instances.empty(), 0 );
SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
wxCHECK( screen, 0 );
screen->Remove( symbol );
SCH_SYMBOL* symbol_copy = static_cast<SCH_SYMBOL*>( symbol->Clone() );
aCommit->Modified( symbol, symbol_copy, screen );
CONNECTION_GRAPH* connectionGraph = screen->Schematic()->ConnectionGraph();
// When we replace the lib symbol below, we free the associated pins if the new symbol has
// fewer than the original. This will cause the connection graph to be out of date unless
// we replace references in the graph to the old symbol/pins with references to the ones stored
// in the undo stack.
if( connectionGraph )
connectionGraph->ExchangeItem( symbol, symbol_copy );
}
for( const auto& [ symbol, symbol_change_info ] : symbols )
{
// Remember initial link before changing for diags purpose
wxString initialLibLinkName = UnescapeString( symbol->GetLibId().Format() );
if( symbol_change_info.m_LibId != symbol->GetLibId() )
symbol->SetLibId( symbol_change_info.m_LibId );
LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol_change_info.m_LibId );
std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
symbol->SetLibSymbol( flattenedSymbol.release() );
if( m_resetAttributes->GetValue() )
{
// Fetch the attributes from the *flattened* library symbol. They are not supported
// in derived symbols.
symbol->SetExcludedFromSim( symbol->GetLibSymbolRef()->GetExcludedFromSim() );
symbol->SetExcludedFromBOM( symbol->GetLibSymbolRef()->GetExcludedFromBOM() );
symbol->SetExcludedFromBoard( symbol->GetLibSymbolRef()->GetExcludedFromBoard() );
}
if( m_resetPinTextVisibility->GetValue() )
{
symbol->SetShowPinNames( symbol->GetLibSymbolRef()->GetShowPinNames() );
symbol->SetShowPinNumbers( symbol->GetLibSymbolRef()->GetShowPinNumbers() );
}
bool removeExtras = m_removeExtraBox->GetValue();
bool resetVis = m_resetFieldVisibilities->GetValue();
bool resetEffects = m_resetFieldEffects->GetValue();
bool resetPositions = m_resetFieldPositions->GetValue();
for( unsigned i = 0; i < symbol->GetFields().size(); ++i )
{
SCH_FIELD& field = symbol->GetFields()[i];
SCH_FIELD* libField = nullptr;
// Mandatory fields always exist in m_updateFields, but these names can be translated.
// so use GetCanonicalName().
if( !alg::contains( m_updateFields, field.GetCanonicalName() ) )
continue;
if( i < MANDATORY_FIELDS )
libField = symbol->GetLibSymbolRef()->GetFieldById( (int) i );
else
libField = symbol->GetLibSymbolRef()->FindField( field.GetName() );
if( libField )
{
bool resetText = libField->GetText().IsEmpty() ? m_resetEmptyFields->GetValue()
: m_resetFieldText->GetValue();
if( resetText )
{
if( i == REFERENCE_FIELD )
{
wxString prefix = UTIL::GetRefDesPrefix( libField->GetText() );
for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
{
wxString ref = symbol->GetRef( &instance );
int number = UTIL::GetRefDesNumber( ref );
if( number >= 0 )
ref.Printf( wxS( "%s%d" ), prefix, number );
else
ref = UTIL::GetRefDesUnannotated( prefix );
symbol->SetRef( &instance, ref );
}
}
else if( i == VALUE_FIELD )
{
if( ( symbol->IsPower() && m_resetCustomPower->IsChecked() )
|| !symbol->IsPower() )
symbol->SetValueFieldText( UnescapeString( libField->GetText() ) );
}
else if( i == FOOTPRINT_FIELD )
{
symbol->SetFootprintFieldText( libField->GetText() );
}
else
{
field.SetText( libField->GetText() );
}
}
if( resetVis )
field.SetVisible( libField->IsVisible() );
if( resetEffects )
{
// Careful: the visible bit and position are also set by SetAttributes()
bool visible = field.IsVisible();
VECTOR2I pos = field.GetPosition();
field.SetAttributes( *libField );
field.SetVisible( visible );
field.SetPosition( pos );
field.SetNameShown( libField->IsNameShown() );
field.SetCanAutoplace( libField->CanAutoplace() );
}
if( resetPositions )
field.SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
}
else if( i >= MANDATORY_FIELDS && removeExtras )
{
symbol->RemoveField( field.GetName() );
i--;
}
}
std::vector<SCH_FIELD*> libFields;
symbol->GetLibSymbolRef()->GetFields( libFields );
for( unsigned i = MANDATORY_FIELDS; i < libFields.size(); ++i )
{
const SCH_FIELD& libField = *libFields[i];
if( !alg::contains( m_updateFields, libField.GetCanonicalName() ) )
continue;
if( !symbol->FindField( libField.GetName(), false ) )
{
wxString fieldName = libField.GetCanonicalName();
SCH_FIELD newField( VECTOR2I( 0, 0 ), symbol->GetFieldCount(), symbol,
fieldName );
SCH_FIELD* schField = symbol->AddField( newField );
// Careful: the visible bit and position are also set by SetAttributes()
schField->SetAttributes( libField );
schField->SetText( libField.GetText() );
schField->SetTextPos( symbol->GetPosition() + libField.GetTextPos() );
}
if( resetPositions && frame->eeconfig()->m_AutoplaceFields.enable )
symbol->AutoAutoplaceFields( screen );
}
symbol->SetSchSymbolLibraryName( wxEmptyString );
screen->Append( symbol );
if( resetPositions )
symbol->AutoAutoplaceFields( screen );
frame->GetCanvas()->GetView()->Update( symbol );
msg = getSymbolReferences( *symbol, symbol_change_info.m_LibId, &initialLibLinkName );
msg += wxS( ": OK" );
m_messagePanel->Report( msg, RPT_SEVERITY_ACTION );
matchesProcessed +=1;
}
return matchesProcessed;
}
wxString DIALOG_CHANGE_SYMBOLS::getSymbolReferences( SCH_SYMBOL& aSymbol,
const LIB_ID& aNewId,
const wxString* aOldLibLinkName )
{
wxString msg;
wxString references;
LIB_ID oldId = aSymbol.GetLibId();
wxString oldLibLinkName; // For report
if( aOldLibLinkName )
oldLibLinkName = *aOldLibLinkName;
else
oldLibLinkName = UnescapeString( oldId.Format() );
SCH_EDIT_FRAME* parent = dynamic_cast< SCH_EDIT_FRAME* >( GetParent() );
wxCHECK( parent, msg );
SCH_SHEET_LIST sheets = parent->Schematic().GetSheets();
for( const SCH_SYMBOL_INSTANCE& instance : aSymbol.GetInstances() )
{
// Only include the symbol instances for the current project.
if( !sheets.HasPath( instance.m_Path ) )
continue;
if( references.IsEmpty() )
references = instance.m_Reference;
else
references += wxT( " " ) + instance.m_Reference;
}
if( m_mode == MODE::UPDATE )
{
if( aSymbol.GetInstances().size() == 1 )
{
msg.Printf( _( "Update symbol %s from '%s' to '%s'" ),
references,
oldLibLinkName,
UnescapeString( aNewId.Format() ) );
}
else
{
msg.Printf( _( "Update symbols %s from '%s' to '%s'" ),
references,
oldLibLinkName,
UnescapeString( aNewId.Format() ) );
}
}
else // mode is MODE::CHANGE
{
if( aSymbol.GetInstances().size() == 1 )
{
msg.Printf( _( "Change symbol %s from '%s' to '%s'" ),
references,
oldLibLinkName,
UnescapeString( aNewId.Format() ) );
}
else
{
msg.Printf( _( "Change symbols %s from '%s' to '%s'" ),
references,
oldLibLinkName,
UnescapeString( aNewId.Format() ) );
}
}
return msg;
}