KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_change_symbols.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2020-2021 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Wayne Stambaugh <[email protected]>
8 *
9 * This program is free software: you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
24#include <algorithm>
25
26#include <bitmaps.h>
27#include <connection_graph.h>
28#include <string_utils.h> // WildCompareString
29#include <kiway.h>
30#include <refdes_utils.h>
31#include <core/kicad_algo.h>
33#include <sch_symbol.h>
34#include <sch_edit_frame.h>
35#include <sch_screen.h>
36#include <schematic.h>
37#include <template_fieldnames.h>
40#include <sch_commit.h>
41
42
45 m_symbol( aSymbol),
46 m_mode( aMode )
47{
48 wxASSERT( aParent );
49
50 if( m_mode == MODE::UPDATE )
51 {
52 m_newIdSizer->Show( false );
53 }
54 else
55 {
56 m_matchAll->SetLabel( _( "Change all symbols in schematic" ) );
57 SetTitle( _( "Change Symbols" ) );
58 m_matchSizer->FindItem( m_matchAll )->Show( false );
59
60 m_matchByReference->SetLabel( _( "Change symbols matching reference designator:" ) );
61 m_matchByValue->SetLabel( _( "Change symbols matching value:" ) );
62 m_matchById->SetLabel( _( "Change symbols matching library identifier:" ) );
63
64 m_updateFieldsSizer->GetStaticBox()->SetLabel( _( "Update Fields" ) );
65 m_removeExtraBox->SetLabel( _( "Remove fields if not in new symbol" ) );
66 m_resetEmptyFields->SetLabel( _( "Reset fields if empty in new symbol" ) );
67 m_resetFieldText->SetLabel( _( "Update field text" ) );
68 m_resetFieldVisibilities->SetLabel( _( "Update field visibilities" ) );
69 m_resetFieldEffects->SetLabel( _( "Update field sizes and styles" ) );
70 m_resetFieldPositions->SetLabel( _( "Update field positions" ) );
71 m_resetAttributes->SetLabel( _( "Update symbol attributes" ) );
72 m_resetPinTextVisibility->SetLabel( _( "Update pin name/number visibilities" ) );
73 m_resetAlternatePin->SetLabel( _( "Reset alternate pin functions" ) );
74 m_resetCustomPower->SetLabel( _( "Reset custom power symbols" ) );
75
76 if( m_symbol )
77 m_matchBySelection->SetLabel( _( "Change selected symbol(s)" ) );
78 }
79
80 if( !m_symbol )
81 m_matchSizer->FindItem( m_matchBySelection )->Show( false );
82
85
86 m_matchSizer->SetEmptyCellSize( wxSize( 0, 0 ) );
87 m_matchSizer->Layout();
88
89 bool selectReference = false;
90 bool selectValue = false;
91
93 {
94 selectReference = cfg->m_ChangeSymbols.updateReferences;
95 selectValue = cfg->m_ChangeSymbols.updateValues;
96 }
97
98 for( FIELD_T fieldId : MANDATORY_FIELDS )
99 {
100 int listIdx = (int) m_fieldsBox->GetCount();
101
102 m_fieldsBox->Append( GetDefaultFieldName( fieldId, TRANSLATED ) );
103
104 // List boxes aren't currently handled in DIALOG_SHIM's control-state-save/restore
105 if( fieldId == FIELD_T::REFERENCE )
106 m_fieldsBox->Check( listIdx, selectReference );
107 else if( fieldId == FIELD_T::VALUE )
108 m_fieldsBox->Check( listIdx, selectValue );
109 else
110 m_fieldsBox->Check( listIdx, true );
111
112 m_mandatoryFieldListIndexes[fieldId] = listIdx;
113 }
114
115 // initialize controls based on m_mode in case there is no saved state yet
116 m_removeExtraBox->SetValue( false );
117 m_resetEmptyFields->SetValue( false );
118 m_resetFieldText->SetValue( true );
119 m_resetCustomPower->SetValue( false );
120 m_resetFieldVisibilities->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
121 m_resetFieldEffects->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
122 m_resetFieldPositions->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
123 m_resetAttributes->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
124 m_resetPinTextVisibility->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
125 m_resetAlternatePin->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
126 m_resetPinMapOverrides->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
127
128 m_messagePanel->SetLazyUpdate( true );
129 m_messagePanel->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
130
131 // DIALOG_SHIM needs a unique hash_key because classname is not sufficient
132 // because the update and change versions of this dialog have different controls.
133 m_hash_key = TO_UTF8( GetTitle() );
134
135 wxString okLabel = m_mode == MODE::CHANGE ? _( "Change" ) : _( "Update" );
136
137 SetupStandardButtons( { { wxID_OK, okLabel },
138 { wxID_CANCEL, _( "Close" ) } } );
139
140 // Now all widgets have the size fixed, call FinishDialogSettings
142}
143
144
146{
147 if( m_symbol )
148 {
149 SCH_SHEET_PATH* currentSheet = &m_symbol->Schematic()->CurrentSheet();
150
151 m_specifiedReference->ChangeValue( m_symbol->GetRef( currentSheet ) );
152 m_specifiedValue->ChangeValue( UnescapeString( m_symbol->GetField( FIELD_T::VALUE )->GetText() ) );
153 m_specifiedId->ChangeValue( UnescapeString( m_symbol->GetLibId().Format() ) );
154 }
155
156 if( m_symbol && m_symbol->IsSelected() )
157 m_matchBySelection->SetValue( true );
158 else if( m_mode == MODE::UPDATE )
159 m_matchAll->SetValue( true );
160 else
161 m_matchByReference->SetValue( true );
162
164
165 return true;
166}
167
168
169void DIALOG_CHANGE_SYMBOLS::onMatchByAll( wxCommandEvent& aEvent )
170{
172}
173
174
175void DIALOG_CHANGE_SYMBOLS::onMatchBySelected( wxCommandEvent& aEvent )
176{
178}
179
180
181void DIALOG_CHANGE_SYMBOLS::onMatchByReference( wxCommandEvent& aEvent )
182{
184 m_specifiedReference->SetFocus();
185}
186
187
188void DIALOG_CHANGE_SYMBOLS::onMatchByValue( wxCommandEvent& aEvent )
189{
191 m_specifiedValue->SetFocus();
192}
193
194
195void DIALOG_CHANGE_SYMBOLS::onMatchById( wxCommandEvent& aEvent )
196{
198 m_specifiedId->SetFocus();
199}
200
201
203{
205 event.Skip(); // Mandatory in wxFocusEvent
206}
207
208
210{
212 event.Skip(); // Mandatory in wxFocusEvent
213}
214
215
217{
219 event.Skip(); // Mandatory in wxFocusEvent
220}
221
222
224{
225 // List boxes aren't currently handled in DIALOG_SHIM's control-state-save/restore
227 {
228 EESCHEMA_SETTINGS::DIALOG_CHANGE_SYMBOLS& dlg_cfg = cfg->m_ChangeSymbols;
229
232 }
233}
234
235
236wxString getLibIdValue( const wxTextCtrl* aCtrl )
237{
238 wxString rawValue = aCtrl->GetValue();
239 wxString itemName;
240 wxString libName = rawValue.BeforeFirst( ':', &itemName );
241
242 return EscapeString( libName, CTX_LIBID ) + ':' + EscapeString( itemName, CTX_LIBID );
243}
244
245
247{
248 wxString newName = getLibIdValue( m_specifiedId );
249
250 if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_SYMBOL_CHOOSER, true, this ) )
251 {
252 if( frame->ShowModal( &newName, this ) )
253 {
254 m_specifiedId->SetValue( UnescapeString( newName ) );
256 }
257
258 frame->Destroy();
259 }
260}
261
262
264{
265 wxString newName = getLibIdValue( m_newId );
266
267 if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_SYMBOL_CHOOSER, true, this ) )
268 {
269 if( frame->ShowModal( &newName, this ) )
270 {
271 m_newId->SetValue( UnescapeString( newName ) );
273 }
274
275 frame->Destroy();
276 }
277}
278
279
281{
282 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
283
284 wxCHECK( frame, /* void */ );
285
286 // Load non-mandatory fields from all matching symbols and their library symbols
287 std::set<wxString> fieldNames;
288
289 for( SCH_SHEET_PATH& instance : frame->Schematic().Hierarchy() )
290 {
291 SCH_SCREEN* screen = instance.LastScreen();
292
293 wxCHECK2( screen, continue );
294
295 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
296 {
297 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
298
299 wxCHECK2( symbol, continue );
300
301 if( !isMatch( symbol, &instance ) )
302 continue;
303
304 for( SCH_FIELD& field : symbol->GetFields() )
305 {
306 if( !field.IsMandatory() && !field.IsPrivate() )
307 fieldNames.insert( field.GetName() );
308 }
309
310 if( m_mode == MODE::UPDATE && symbol->GetLibId().IsValid() )
311 {
312 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol->GetLibId() );
313
314 if( libSymbol )
315 {
316 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
317 std::vector<SCH_FIELD*> orderedLibFields;
318
319 flattenedSymbol->GetFields( orderedLibFields );
320
321 for( SCH_FIELD* libField : orderedLibFields )
322 {
323 if( !libField->IsMandatory() && !libField->IsPrivate() )
324 fieldNames.insert( libField->GetName() );
325 }
326 }
327 }
328 }
329 }
330
331 // Load non-mandatory fields from the change-to library symbol
332 if( m_mode == MODE::CHANGE )
333 {
334 LIB_ID newId;
335
336 newId.Parse( getLibIdValue( m_newId ) );
337
338 if( newId.IsValid() )
339 {
340 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( newId );
341
342 if( libSymbol )
343 {
344 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
345 std::vector<SCH_FIELD*> orderedLibFields;
346
347 flattenedSymbol->GetFields( orderedLibFields );
348
349 for( SCH_FIELD* libField : orderedLibFields )
350 {
351 if( !libField->IsMandatory() && !libField->IsPrivate() )
352 fieldNames.insert( libField->GetName() );
353 }
354 }
355 }
356 }
357
358 // Update the listbox widget
359 wxArrayInt checkedItems;
360 wxArrayString checkedNames;
361
362 m_fieldsBox->GetCheckedItems( checkedItems );
363
364 for( int ii : checkedItems )
365 checkedNames.push_back( m_fieldsBox->GetString( ii ) );
366
367 bool allChecked = true;
368
369 for( int ii = 0; ii < (int) m_fieldsBox->GetCount(); ++ii )
370 {
371 if( !m_fieldsBox->IsChecked( ii )
374 {
375 allChecked = false;
376 }
377 }
378
379 auto isMandatoryField =
380 [&]( int listbox_idx )
381 {
382 for( FIELD_T fieldId : MANDATORY_FIELDS )
383 {
384 if( m_mandatoryFieldListIndexes[fieldId] == listbox_idx )
385 return true;
386 }
387
388 return false;
389 };
390
391 for( int ii = (int) m_fieldsBox->GetCount() - 1; ii >= 0; --ii )
392 {
393 if( isMandatoryField( ii ) )
394 continue;
395
396 m_fieldsBox->Delete( ii );
397 }
398
399 for( const wxString& fieldName : fieldNames )
400 {
401 m_fieldsBox->Append( fieldName );
402
403 if( allChecked || alg::contains( checkedNames, fieldName ) )
404 m_fieldsBox->Check( m_fieldsBox->GetCount() - 1, true );
405 }
406}
407
408
410{
411 for( unsigned i = 0; i < m_fieldsBox->GetCount(); ++i )
412 m_fieldsBox->Check( i, aSelect );
413}
414
415
417{
418 m_removeExtraBox->SetValue( aCheck );
419 m_resetEmptyFields->SetValue( aCheck );
420 m_resetFieldText->SetValue( aCheck );
421 m_resetFieldVisibilities->SetValue( aCheck );
422 m_resetFieldEffects->SetValue( aCheck );
423 m_resetFieldPositions->SetValue( aCheck );
424 m_resetPinTextVisibility->SetValue( aCheck );
425 m_resetAlternatePin->SetValue( aCheck );
426 m_resetPinMapOverrides->SetValue( aCheck );
427 m_resetAttributes->SetValue( aCheck );
428 m_resetCustomPower->SetValue( aCheck );
429}
430
431
432void DIALOG_CHANGE_SYMBOLS::onOkButtonClicked( wxCommandEvent& aEvent )
433{
434 SCH_EDIT_FRAME* parent = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
435
436 wxCHECK( parent, /* void */ );
437
438 wxBusyCursor dummy;
439 SCH_COMMIT commit( parent );
440
441 m_messagePanel->Clear();
442 m_messagePanel->Flush( false );
443
444 // Create the set of fields to be updated. Use untranslated names for mandatory fields.
445 m_updateFields.clear();
446
447 for( unsigned ii = 0; ii < m_fieldsBox->GetCount(); ++ii )
448 {
449 if( m_fieldsBox->IsChecked( ii ) )
450 m_updateFields.insert( m_fieldsBox->GetString( ii ) );
451 }
452
453 for( FIELD_T fieldId : MANDATORY_FIELDS )
454 {
455 if( m_fieldsBox->IsChecked( m_mandatoryFieldListIndexes[fieldId] ) )
456 m_updateFields.insert( GetDefaultFieldName( fieldId, UNTRANSLATED ) );
457 }
458
459 if( processMatchingSymbols( &commit) )
460 commit.Push( m_mode == MODE::CHANGE ? _( "Change Symbols" ) : _( "Update Symbols" ) );
461
462 m_messagePanel->Flush( false );
463}
464
465
467{
468 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
469
470 wxCHECK( frame, false );
471
472 if( !aSymbol )
473 return false;
474
475 if( m_matchAll->GetValue() )
476 {
477 return true;
478 }
479 else if( m_matchBySelection->GetValue() )
480 {
481 return aSymbol == m_symbol || aSymbol->IsSelected();
482 }
483 else if( m_matchByReference->GetValue() )
484 {
485 return WildCompareString( m_specifiedReference->GetValue(),
486 UnescapeString( aSymbol->GetRef( aInstance, false ) ),
487 false );
488 }
489 else if( m_matchByValue->GetValue() )
490 {
491 return WildCompareString( m_specifiedValue->GetValue(),
493 false );
494 }
495 else if( m_matchById )
496 {
497 LIB_ID id;
498
500 return aSymbol->GetLibId() == id;
501 }
502
503 return false;
504}
505
506
508{
509 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
510
511 wxCHECK( frame, false );
512
513 LIB_ID newId;
514 int matchesProcessed = 0;
515 SCH_SYMBOL* symbol = nullptr;
516
517 if( m_mode == MODE::CHANGE )
518 {
519 newId.Parse( getLibIdValue( m_newId ) );
520
521 if( !newId.IsValid() )
522 return false;
523 }
524
525 std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO> symbols;
526
527 for( SCH_SHEET_PATH& instance : frame->Schematic().Hierarchy() )
528 {
529 SCH_SCREEN* screen = instance.LastScreen();
530
531 wxCHECK2( screen, continue );
532
533 // Fetch all the symbols that meet the change criteria.
534 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
535 {
536 symbol = static_cast<SCH_SYMBOL*>( item );
537
538 wxCHECK2( symbol, continue );
539
540 if( !isMatch( symbol, &instance ) )
541 continue;
542
543 if( m_mode == MODE::UPDATE )
544 newId = symbol->GetLibId();
545
546 auto it = symbols.find( symbol );
547
548 if( it == symbols.end() )
549 {
551
552 info.m_Instances.emplace_back( instance );
553 info.m_LibId = newId;
554 symbols.insert( { symbol, info } );
555 }
556 else
557 {
558 it->second.m_Instances.emplace_back( instance );
559 }
560 }
561 }
562
563 if( symbols.size() > 0 )
564 matchesProcessed += processSymbols( aCommit, symbols );
565 else
566 m_messagePanel->Report( _( "*** No symbols matching criteria found ***" ), RPT_SEVERITY_ERROR );
567
569
570 return matchesProcessed;
571}
572
573
575 SYMBOL_CHANGE_INFO>& aSymbols )
576{
577 wxCHECK( !aSymbols.empty(), 0 );
578
579 int matchesProcessed = 0;
580 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
581 wxString msg;
582
583 wxCHECK( frame, 0 );
584
585 std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO> symbols = aSymbols;
586 std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO>::iterator it = symbols.begin();
587
588 // Remove all symbols that don't have a valid library symbol link or enough units to
589 // satisfy the library symbol update.
590 while( it != symbols.end() )
591 {
592 SCH_SYMBOL* symbol = it->first;
593
594 wxCHECK2( symbol, ++it; continue );
595
596 if( !it->second.m_LibId.IsValid() )
597 {
598 msg = getSymbolReferences( *symbol, it->second.m_LibId );
599 msg << wxT( ": " ) << _( "*** symbol lib id not valid ***" );
600 m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
601 it = symbols.erase( it );
602 continue;
603 }
604
605 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( it->second.m_LibId );
606
607 if( !libSymbol )
608 {
609 msg = getSymbolReferences( *symbol, it->second.m_LibId );
610 msg << wxT( ": " ) << _( "*** symbol not found ***" );
611 m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
612 it = symbols.erase( it );
613 continue;
614 }
615
616 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
617
618 if( flattenedSymbol->GetUnitCount() < symbol->GetUnit() )
619 {
620 msg = getSymbolReferences( *symbol, it->second.m_LibId );
621 msg << wxT( ": " ) << _( "*** new symbol has too few units ***" );
622 m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
623 it = symbols.erase( it );
624 }
625 else
626 {
627 ++it;
628 }
629 }
630
631 // Snapshot before symbols leave their screens so a prefix change cannot reuse a taken ref
632 std::set<wxString> usedRefs;
633 std::map<wxString, wxString> renamedRefs;
634
635 for( const SCH_SHEET_PATH& path : frame->Schematic().Hierarchy() )
636 {
637 SCH_SCREEN* screen = path.LastScreen();
638
639 wxCHECK2( screen, continue );
640
641 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
642 usedRefs.insert( static_cast<SCH_SYMBOL*>( item )->GetRef( &path ) );
643 }
644
645 // Removing the symbol needs to be done before the LIB_SYMBOL is changed to prevent stale
646 // library symbols in the schematic file.
647 for( const auto& [ symbol, symbol_change_info ] : symbols )
648 {
649 wxCHECK( symbol && !symbol_change_info.m_Instances.empty(), 0 );
650
651 SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
652
653 wxCHECK( screen, 0 );
654
655 screen->Remove( symbol );
656 SCH_SYMBOL* symbol_copy = static_cast<SCH_SYMBOL*>( symbol->Clone() );
657 aCommit->Modified( symbol, symbol_copy, screen );
658 }
659
660 for( const auto& [ symbol, symbol_change_info ] : symbols )
661 {
662 // Remember initial link before changing for diags purpose
663 wxString initialLibLinkName = UnescapeString( symbol->GetLibId().Format() );
664
665 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol_change_info.m_LibId );
666
667 wxCHECK2( libSymbol, continue );
668
669 if( symbol_change_info.m_LibId != symbol->GetLibId() )
670 symbol->SetLibId( symbol_change_info.m_LibId );
671
672 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
673 SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
674
675 const bool keepPinMaps = !m_resetPinMapOverrides->IsChecked();
676
677 PIN_MAP_SET savedPinMaps;
678 std::vector<ASSOCIATED_FOOTPRINT> savedAssociations;
679
680 if( keepPinMaps && symbol->GetLibSymbolRef() )
681 {
682 savedPinMaps = symbol->GetLibSymbolRef()->GetPinMaps();
683 savedAssociations = symbol->GetLibSymbolRef()->GetAssociatedFootprints();
684 }
685
686 symbol->SetLibSymbol( flattenedSymbol.release() );
687
688 if( screen )
689 screen->IncludeVariantSymbols( *symbol, true );
690
691 if( keepPinMaps && symbol->GetLibSymbolRef() )
692 {
693 symbol->GetLibSymbolRef()->SetPinMaps( savedPinMaps );
694 symbol->GetLibSymbolRef()->SetAssociatedFootprints( savedAssociations );
695 }
696
697 if( m_resetAttributes->GetValue() )
698 {
699 // Fetch the attributes from the *flattened* library symbol. They are not supported
700 // in derived symbols.
701 symbol->SetExcludedFromSim( symbol->GetLibSymbolRef()->GetExcludedFromSim() );
702 symbol->SetExcludedFromBOM( symbol->GetLibSymbolRef()->GetExcludedFromBOM() );
703 symbol->SetExcludedFromBoard( symbol->GetLibSymbolRef()->GetExcludedFromBoard() );
704 symbol->SetExcludedFromPosFiles( symbol->GetLibSymbolRef()->GetExcludedFromPosFiles() );
705 }
706
707 if( m_resetPinTextVisibility->GetValue() )
708 {
709 symbol->SetShowPinNames( symbol->GetLibSymbolRef()->GetShowPinNames() );
710 symbol->SetShowPinNumbers( symbol->GetLibSymbolRef()->GetShowPinNumbers() );
711 }
712
713 bool removeExtras = m_removeExtraBox->GetValue();
714 bool resetVis = m_resetFieldVisibilities->GetValue();
715 bool resetEffects = m_resetFieldEffects->GetValue();
716 bool resetPositions = m_resetFieldPositions->GetValue();
717
718 for( int ii = (int) symbol->GetFields().size() - 1; ii >= 0; ii-- )
719 {
720 SCH_FIELD& field = symbol->GetFields()[ii];
721 SCH_FIELD* libField = nullptr;
722 bool doUpdate = field.IsPrivate();
723
724 // Mandatory fields always exist in m_updateFields, but these names can be translated,
725 // so use GetUntranslatedName().
726 doUpdate |= alg::contains( m_updateFields, field.GetUntranslatedName() );
727
728 if( !doUpdate )
729 continue;
730
731 if( field.IsMandatory() )
732 libField = symbol->GetLibSymbolRef()->GetField( field.GetId() );
733 else
734 libField = symbol->GetLibSymbolRef()->GetField( field.GetName() );
735
736 if( libField )
737 {
738 field.SetPrivate( libField->IsPrivate() );
739
740 bool resetText = libField->GetText().IsEmpty() ? m_resetEmptyFields->GetValue()
741 : m_resetFieldText->GetValue();
742
743 if( resetText )
744 {
745 if( field.GetId() == FIELD_T::REFERENCE )
746 {
747 wxString prefix = UTIL::GetRefDesPrefix( libField->GetText() );
748
749 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
750 {
751 wxString oldRef = symbol->GetRef( &instance );
752 int number = UTIL::GetRefDesNumber( oldRef );
753 wxString ref;
754 auto renamed = renamedRefs.find( oldRef );
755
756 if( number < 0 )
757 {
758 ref = UTIL::GetRefDesUnannotated( prefix );
759 }
760 else if( renamed != renamedRefs.end()
761 && UTIL::GetRefDesPrefix( renamed->second ) == prefix )
762 {
763 // Keep the units of a multi-unit symbol together
764 ref = renamed->second;
765 }
766 else
767 {
768 ref.Printf( wxS( "%s%d" ), prefix, number );
769
770 if( ref != oldRef )
771 {
772 while( usedRefs.count( ref ) )
773 ref.Printf( wxS( "%s%d" ), prefix, ++number );
774
775 usedRefs.insert( ref );
776 renamedRefs[oldRef] = ref;
777 }
778 }
779
780 symbol->SetRef( &instance, ref );
781 }
782 }
783 else if( field.GetId() == FIELD_T::VALUE )
784 {
785 if( !symbol->IsPower() || m_resetCustomPower->IsChecked() )
786 symbol->SetValueFieldText( UnescapeString( libField->GetText() ) );
787 }
788 else
789 {
790 field.SetText( libField->GetText() );
791 }
792 }
793
794 if( resetVis )
795 field.SetVisible( libField->IsVisible() );
796
797 if( resetEffects )
798 {
799 // Careful: the visible bit and position are also set by SetAttributes()
800 bool visible = field.IsVisible();
801 VECTOR2I pos = field.GetPosition();
802
803 field.SetAttributes( *libField );
804
805 field.SetVisible( visible );
806 field.SetPosition( pos );
807 field.SetNameShown( libField->IsNameShown() );
808 field.SetCanAutoplace( libField->CanAutoplace() );
809 }
810
811 if( resetPositions )
812 field.SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
813 }
814 else if( !field.IsMandatory() && removeExtras )
815 {
816 symbol->RemoveField( field.GetName() );
817 }
818 }
819
820 std::vector<SCH_FIELD*> libFields;
821 symbol->GetLibSymbolRef()->GetFields( libFields );
822
823 for( SCH_FIELD* libField : libFields )
824 {
825 if( libField->IsMandatory() )
826 continue;
827
828 if( !alg::contains( m_updateFields, libField->GetUntranslatedName() ) )
829 continue;
830
831 if( !symbol->GetField( libField->GetName() ) )
832 {
833 SCH_FIELD* schField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, libField->GetName() ) );
834
835 // SetAttributes() also covers text angle, size, italic and bold
836 schField->SetAttributes( *libField );
837 schField->SetVisible( libField->IsVisible() );
838 schField->SetText( libField->GetText() );
839 schField->SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
840 schField->SetPrivate( libField->IsPrivate() );
841 }
842
843 if( resetPositions && frame->eeconfig()->m_AutoplaceFields.enable )
844 {
845 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
846
847 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
848 symbol->AutoplaceFields( screen, fieldsAutoplaced );
849 }
850 }
851
852 symbol->SetSchSymbolLibraryName( wxEmptyString );
853 screen->Append( symbol );
854
855 if( resetPositions )
856 {
857 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
858
859 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
860 symbol->AutoplaceFields( screen, fieldsAutoplaced );
861 }
862
863 // Clear alternate pins as required.
864 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
865 {
866 for( SCH_PIN* pin : symbol->GetPins( &instance ) )
867 {
868 if( !pin->GetAlt().IsEmpty() )
869 {
870 // There is a bug that allows the alternate pin name to be set to the default pin
871 // name which causes library symbol comparison errors. Clear the alternate pin
872 // name in this case even if the reset option is not checked. Also clear the
873 // alternate pin name if it no longer exists in the alternate pin map.
874 if( m_resetAlternatePin->IsChecked()
875 || ( pin->GetAlt() == pin->GetBaseName() )
876 || ( pin->GetAlternates().count( pin->GetAlt() ) == 0 ) )
877 {
878 pin->SetAlt( wxEmptyString );
879 }
880 }
881 }
882 }
883
884 if( m_resetPinMapOverrides->IsChecked() )
885 {
886 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
887 symbol->SetPinMapOverride( PIN_MAP_INSTANCE_OVERRIDE(), &instance );
888 }
889
890 frame->GetCanvas()->GetView()->Update( symbol );
891
892 msg = getSymbolReferences( *symbol, symbol_change_info.m_LibId, &initialLibLinkName );
893 msg += wxS( ": OK" );
894 m_messagePanel->Report( msg, RPT_SEVERITY_ACTION );
895 matchesProcessed +=1;
896 }
897
898 return matchesProcessed;
899}
900
901
903 const wxString* aOldLibLinkName )
904{
905 wxString msg;
906 wxString references;
907 const LIB_ID& oldId = aSymbol.GetLibId();
908 wxString oldLibLinkName; // For report
909
910 if( aOldLibLinkName )
911 oldLibLinkName = *aOldLibLinkName;
912 else
913 oldLibLinkName = UnescapeString( oldId.Format() );
914
915 SCH_EDIT_FRAME* parent = dynamic_cast< SCH_EDIT_FRAME* >( GetParent() );
916
917 wxCHECK( parent, msg );
918
919 SCH_SHEET_LIST sheets = parent->Schematic().Hierarchy();
920
921 for( const SCH_SYMBOL_INSTANCE& instance : aSymbol.GetInstances() )
922 {
923 // Only include the symbol instances for the current project.
924 if( !sheets.HasPath( instance.m_Path ) )
925 continue;
926
927 if( references.IsEmpty() )
928 references = instance.m_Reference;
929 else
930 references += wxT( " " ) + instance.m_Reference;
931 }
932
933 if( m_mode == MODE::UPDATE )
934 {
935 if( aSymbol.GetInstances().size() == 1 )
936 {
937 msg.Printf( _( "Update symbol %s from '%s' to '%s'" ),
938 references,
939 oldLibLinkName,
940 UnescapeString( aNewId.Format() ) );
941 }
942 else
943 {
944 msg.Printf( _( "Update symbols %s from '%s' to '%s'" ),
945 references,
946 oldLibLinkName,
947 UnescapeString( aNewId.Format() ) );
948 }
949 }
950 else // mode is MODE::CHANGE
951 {
952 if( aSymbol.GetInstances().size() == 1 )
953 {
954 msg.Printf( _( "Change symbol %s from '%s' to '%s'" ),
955 references,
956 oldLibLinkName,
957 UnescapeString( aNewId.Format() ) );
958 }
959 else
960 {
961 msg.Printf( _( "Change symbols %s from '%s' to '%s'" ),
962 references,
963 oldLibLinkName,
964 UnescapeString( aNewId.Format() ) );
965 }
966 }
967
968 return msg;
969}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
COMMIT & Modified(EDA_ITEM *aItem, EDA_ITEM *aCopy, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition commit.cpp:224
DIALOG_CHANGE_SYMBOLS_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Update Symbols from Library"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
void onNewLibIDKillFocus(wxFocusEvent &event) override
void onMatchBySelected(wxCommandEvent &aEvent) override
bool isMatch(SCH_SYMBOL *aSymbol, SCH_SHEET_PATH *aInstance)
std::map< FIELD_T, int > m_mandatoryFieldListIndexes
Index in the list control for each mandatory FIELD_T type.
void onOkButtonClicked(wxCommandEvent &aEvent) override
void selectAll(bool aSelect)
Select or deselect all fields in the listbox widget.
std::set< wxString > m_updateFields
Set of field names that should have values updated.
void onMatchById(wxCommandEvent &aEvent) override
void launchMatchIdSymbolBrowser(wxCommandEvent &aEvent) override
void onMatchByReference(wxCommandEvent &aEvent) override
void onMatchByValue(wxCommandEvent &aEvent) override
int processMatchingSymbols(SCH_COMMIT *aCommit)
DIALOG_CHANGE_SYMBOLS(SCH_EDIT_FRAME *aParent, SCH_SYMBOL *aSymbol, MODE aMode=MODE::UPDATE)
void onMatchTextKillFocus(wxFocusEvent &event) override
void onMatchIDKillFocus(wxFocusEvent &event) override
wxString getSymbolReferences(SCH_SYMBOL &aSymbol, const LIB_ID &aNewId, const wxString *aOldLibLinkName=nullptr)
void launchNewIdSymbolBrowser(wxCommandEvent &aEvent) override
void onMatchByAll(wxCommandEvent &aEvent) override
int processSymbols(SCH_COMMIT *aCommit, const std::map< SCH_SYMBOL *, SYMBOL_CHANGE_INFO > &aSymbols)
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
bool IsSelected() const
Definition eda_item.h:134
virtual VECTOR2I GetTextPos() const
Definition eda_text.h:313
virtual bool IsVisible() const
Definition eda_text.h:226
virtual void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:556
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:394
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
AUTOPLACE_FIELDS m_AutoplaceFields
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:248
void Update(const KIGFX::VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition sch_view.cpp:73
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:65
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
UTF8 Format() const
Definition lib_id.cpp:132
Define a library symbol object.
Definition lib_symbol.h:114
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
A symbol-owned ordered set of named pin maps.
Definition pin_map.h:124
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
EESCHEMA_SETTINGS * eeconfig() const
LIB_SYMBOL * GetLibSymbol(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowErrorMsg=false)
Load symbol from symbol library table.
Commit for the schematic and symbol editors.
Definition sch_commit.h:54
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the KIGFX::VIEW instance used in the panel.
Schematic editor (Eeschema) main window.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
bool IsMandatory() const
VECTOR2I GetPosition() const override
bool IsNameShown() const
Definition sch_field.h:229
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:139
FIELD_T GetId() const
Definition sch_field.h:143
void SetCanAutoplace(bool aCanPlace)
Definition sch_field.h:241
wxString GetUntranslatedName() const
Get the untranslated field name for storage, variable look-up, etc.
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetPosition(const VECTOR2I &aPosition) override
bool CanAutoplace() const
Definition sch_field.h:240
void SetText(const wxString &aText) override
void SetNameShown(bool aShown=true)
Definition sch_field.h:230
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
void SetPrivate(bool aPrivate)
Definition sch_item.h:258
int GetUnit() const
Definition sch_item.h:243
bool IsPrivate() const
Definition sch_item.h:259
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
void IncludeVariantSymbols(const SCH_SYMBOL &aSymbol, bool aRefresh=false)
Include the alternate symbols that aSymbol's variants select in the library symbols.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
bool HasPath(const KIID_PATH &aPath) const
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void UpdateAllScreenReferences() const
Update all the symbol references for this sheet path.
Schematic symbol object.
Definition sch_symbol.h:75
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:135
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:165
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
wxString getLibIdValue(const wxTextCtrl *aCtrl)
#define _(s)
@ FRAME_SYMBOL_CHOOSER
Definition frame_type.h:33
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition idf_helpers.h:37
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
wxString GetRefDesUnannotated(const wxString &aSource)
Return an unannotated refdes from either a prefix or an existing refdes.
int GetRefDesNumber(const wxString &aRefDes)
Get the numeric suffix from a refdes - e.g.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
Collection of utility functions for component reference designators (refdes)
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_ACTION
AUTOPLACE_ALGO
Definition sch_item.h:73
@ AUTOPLACE_MANUAL
Definition sch_item.h:76
@ AUTOPLACE_AUTO
Definition sch_item.h:75
T * GetAppSettings(const char *aFilename)
std::vector< FAB_LAYER_COLOR > dummy
bool WildCompareString(const wxString &pattern, const wxString &string_to_tst, bool case_sensitive)
Compare a string against wild card (* and ?) pattern using the usual rules.
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
Per-instance override of the active pin map and a sparse delta on top.
Definition pin_map.h:200
A simple container for schematic symbol instance information.
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
#define MANDATORY_FIELDS
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ USER
The field ID hasn't been set yet; field is invalid.
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
@ UNTRANSLATED
@ TRANSLATED
std::string path
KIBIS_PIN * pin
@ SCH_SYMBOL_T
Definition typeinfo.h:168
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708