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, DO_TRANSLATE ) );
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 non translated (canonical) names
445 // for mandatory fields
446 m_updateFields.clear();
447
448 for( unsigned ii = 0; ii < m_fieldsBox->GetCount(); ++ii )
449 {
450 if( m_fieldsBox->IsChecked( ii ) )
451 m_updateFields.insert( m_fieldsBox->GetString( ii ) );
452 }
453
454 for( FIELD_T fieldId : MANDATORY_FIELDS )
455 {
456 if( m_fieldsBox->IsChecked( m_mandatoryFieldListIndexes[fieldId] ) )
457 m_updateFields.insert( GetCanonicalFieldName( fieldId ) );
458 }
459
460 if( processMatchingSymbols( &commit) )
461 commit.Push( m_mode == MODE::CHANGE ? _( "Change Symbols" ) : _( "Update Symbols" ) );
462
463 m_messagePanel->Flush( false );
464}
465
466
468{
469 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
470
471 wxCHECK( frame, false );
472
473 if( !aSymbol )
474 return false;
475
476 if( m_matchAll->GetValue() )
477 {
478 return true;
479 }
480 else if( m_matchBySelection->GetValue() )
481 {
482 return aSymbol == m_symbol || aSymbol->IsSelected();
483 }
484 else if( m_matchByReference->GetValue() )
485 {
486 return WildCompareString( m_specifiedReference->GetValue(),
487 UnescapeString( aSymbol->GetRef( aInstance, false ) ),
488 false );
489 }
490 else if( m_matchByValue->GetValue() )
491 {
492 return WildCompareString( m_specifiedValue->GetValue(),
494 false );
495 }
496 else if( m_matchById )
497 {
498 LIB_ID id;
499
501 return aSymbol->GetLibId() == id;
502 }
503
504 return false;
505}
506
507
509{
510 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
511
512 wxCHECK( frame, false );
513
514 LIB_ID newId;
515 int matchesProcessed = 0;
516 SCH_SYMBOL* symbol = nullptr;
517
518 if( m_mode == MODE::CHANGE )
519 {
520 newId.Parse( getLibIdValue( m_newId ) );
521
522 if( !newId.IsValid() )
523 return false;
524 }
525
526 std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO> symbols;
527
528 for( SCH_SHEET_PATH& instance : frame->Schematic().Hierarchy() )
529 {
530 SCH_SCREEN* screen = instance.LastScreen();
531
532 wxCHECK2( screen, continue );
533
534 // Fetch all the symbols that meet the change criteria.
535 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
536 {
537 symbol = static_cast<SCH_SYMBOL*>( item );
538
539 wxCHECK2( symbol, continue );
540
541 if( !isMatch( symbol, &instance ) )
542 continue;
543
544 if( m_mode == MODE::UPDATE )
545 newId = symbol->GetLibId();
546
547 auto it = symbols.find( symbol );
548
549 if( it == symbols.end() )
550 {
552
553 info.m_Instances.emplace_back( instance );
554 info.m_LibId = newId;
555 symbols.insert( { symbol, info } );
556 }
557 else
558 {
559 it->second.m_Instances.emplace_back( instance );
560 }
561 }
562 }
563
564 if( symbols.size() > 0 )
565 matchesProcessed += processSymbols( aCommit, symbols );
566 else
567 m_messagePanel->Report( _( "*** No symbols matching criteria found ***" ), RPT_SEVERITY_ERROR );
568
570
571 return matchesProcessed;
572}
573
574
576 SYMBOL_CHANGE_INFO>& aSymbols )
577{
578 wxCHECK( !aSymbols.empty(), 0 );
579
580 int matchesProcessed = 0;
581 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
582 wxString msg;
583
584 wxCHECK( frame, 0 );
585
586 std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO> symbols = aSymbols;
587 std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO>::iterator it = symbols.begin();
588
589 // Remove all symbols that don't have a valid library symbol link or enough units to
590 // satisfy the library symbol update.
591 while( it != symbols.end() )
592 {
593 SCH_SYMBOL* symbol = it->first;
594
595 wxCHECK2( symbol, ++it; continue );
596
597 if( !it->second.m_LibId.IsValid() )
598 {
599 msg = getSymbolReferences( *symbol, it->second.m_LibId );
600 msg << wxT( ": " ) << _( "*** symbol lib id not valid ***" );
601 m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
602 it = symbols.erase( it );
603 continue;
604 }
605
606 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( it->second.m_LibId );
607
608 if( !libSymbol )
609 {
610 msg = getSymbolReferences( *symbol, it->second.m_LibId );
611 msg << wxT( ": " ) << _( "*** symbol not found ***" );
612 m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
613 it = symbols.erase( it );
614 continue;
615 }
616
617 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
618
619 if( flattenedSymbol->GetUnitCount() < symbol->GetUnit() )
620 {
621 msg = getSymbolReferences( *symbol, it->second.m_LibId );
622 msg << wxT( ": " ) << _( "*** new symbol has too few units ***" );
623 m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
624 it = symbols.erase( it );
625 }
626 else
627 {
628 ++it;
629 }
630 }
631
632 // Removing the symbol needs to be done before the LIB_SYMBOL is changed to prevent stale
633 // library symbols in the schematic file.
634 for( const auto& [ symbol, symbol_change_info ] : symbols )
635 {
636 wxCHECK( symbol && !symbol_change_info.m_Instances.empty(), 0 );
637
638 SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
639
640 wxCHECK( screen, 0 );
641
642 screen->Remove( symbol );
643 SCH_SYMBOL* symbol_copy = static_cast<SCH_SYMBOL*>( symbol->Clone() );
644 aCommit->Modified( symbol, symbol_copy, screen );
645 }
646
647 for( const auto& [ symbol, symbol_change_info ] : symbols )
648 {
649 // Remember initial link before changing for diags purpose
650 wxString initialLibLinkName = UnescapeString( symbol->GetLibId().Format() );
651
652 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol_change_info.m_LibId );
653
654 wxCHECK2( libSymbol, continue );
655
656 if( symbol_change_info.m_LibId != symbol->GetLibId() )
657 symbol->SetLibId( symbol_change_info.m_LibId );
658
659 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
660 SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
661
662 const bool keepPinMaps = !m_resetPinMapOverrides->IsChecked();
663
664 PIN_MAP_SET savedPinMaps;
665 std::vector<ASSOCIATED_FOOTPRINT> savedAssociations;
666
667 if( keepPinMaps && symbol->GetLibSymbolRef() )
668 {
669 savedPinMaps = symbol->GetLibSymbolRef()->GetPinMaps();
670 savedAssociations = symbol->GetLibSymbolRef()->GetAssociatedFootprints();
671 }
672
673 symbol->SetLibSymbol( flattenedSymbol.release() );
674
675 if( keepPinMaps && symbol->GetLibSymbolRef() )
676 {
677 symbol->GetLibSymbolRef()->SetPinMaps( savedPinMaps );
678 symbol->GetLibSymbolRef()->SetAssociatedFootprints( savedAssociations );
679 }
680
681 if( m_resetAttributes->GetValue() )
682 {
683 // Fetch the attributes from the *flattened* library symbol. They are not supported
684 // in derived symbols.
685 symbol->SetExcludedFromSim( symbol->GetLibSymbolRef()->GetExcludedFromSim() );
686 symbol->SetExcludedFromBOM( symbol->GetLibSymbolRef()->GetExcludedFromBOM() );
687 symbol->SetExcludedFromBoard( symbol->GetLibSymbolRef()->GetExcludedFromBoard() );
688 symbol->SetExcludedFromPosFiles( symbol->GetLibSymbolRef()->GetExcludedFromPosFiles() );
689 }
690
691 if( m_resetPinTextVisibility->GetValue() )
692 {
693 symbol->SetShowPinNames( symbol->GetLibSymbolRef()->GetShowPinNames() );
694 symbol->SetShowPinNumbers( symbol->GetLibSymbolRef()->GetShowPinNumbers() );
695 }
696
697 bool removeExtras = m_removeExtraBox->GetValue();
698 bool resetVis = m_resetFieldVisibilities->GetValue();
699 bool resetEffects = m_resetFieldEffects->GetValue();
700 bool resetPositions = m_resetFieldPositions->GetValue();
701
702 for( int ii = (int) symbol->GetFields().size() - 1; ii >= 0; ii-- )
703 {
704 SCH_FIELD& field = symbol->GetFields()[ii];
705 SCH_FIELD* libField = nullptr;
706 bool doUpdate = field.IsPrivate();
707
708 // Mandatory fields always exist in m_updateFields, but these names can be translated.
709 // so use GetCanonicalName().
710 doUpdate |= alg::contains( m_updateFields, field.GetCanonicalName() );
711
712 if( !doUpdate )
713 continue;
714
715 if( field.IsMandatory() )
716 libField = symbol->GetLibSymbolRef()->GetField( field.GetId() );
717 else
718 libField = symbol->GetLibSymbolRef()->GetField( field.GetName() );
719
720 if( libField )
721 {
722 field.SetPrivate( libField->IsPrivate() );
723
724 bool resetText = libField->GetText().IsEmpty() ? m_resetEmptyFields->GetValue()
725 : m_resetFieldText->GetValue();
726
727 if( resetText )
728 {
729 if( field.GetId() == FIELD_T::REFERENCE )
730 {
731 wxString prefix = UTIL::GetRefDesPrefix( libField->GetText() );
732
733 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
734 {
735 wxString ref = symbol->GetRef( &instance );
736 int number = UTIL::GetRefDesNumber( ref );
737
738 if( number >= 0 )
739 ref.Printf( wxS( "%s%d" ), prefix, number );
740 else
741 ref = UTIL::GetRefDesUnannotated( prefix );
742
743 symbol->SetRef( &instance, ref );
744 }
745 }
746 else if( field.GetId() == FIELD_T::VALUE )
747 {
748 if( !symbol->IsPower() || m_resetCustomPower->IsChecked() )
749 symbol->SetValueFieldText( UnescapeString( libField->GetText() ) );
750 }
751 else
752 {
753 field.SetText( libField->GetText() );
754 }
755 }
756
757 if( resetVis )
758 field.SetVisible( libField->IsVisible() );
759
760 if( resetEffects )
761 {
762 // Careful: the visible bit and position are also set by SetAttributes()
763 bool visible = field.IsVisible();
764 VECTOR2I pos = field.GetPosition();
765
766 field.SetAttributes( *libField );
767
768 field.SetVisible( visible );
769 field.SetPosition( pos );
770 field.SetNameShown( libField->IsNameShown() );
771 field.SetCanAutoplace( libField->CanAutoplace() );
772 }
773
774 if( resetPositions )
775 field.SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
776 }
777 else if( !field.IsMandatory() && removeExtras )
778 {
779 symbol->RemoveField( field.GetName() );
780 }
781 }
782
783 std::vector<SCH_FIELD*> libFields;
784 symbol->GetLibSymbolRef()->GetFields( libFields );
785
786 for( SCH_FIELD* libField : libFields )
787 {
788 if( libField->IsMandatory() )
789 continue;
790
791 if( !alg::contains( m_updateFields, libField->GetCanonicalName() ) )
792 continue;
793
794 if( !symbol->GetField( libField->GetName() ) )
795 {
796 SCH_FIELD* schField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, libField->GetName() ) );
797
798 // SetAttributes() also covers text angle, size, italic and bold
799 schField->SetAttributes( *libField );
800 schField->SetVisible( libField->IsVisible() );
801 schField->SetText( libField->GetText() );
802 schField->SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
803 schField->SetPrivate( libField->IsPrivate() );
804 }
805
806 if( resetPositions && frame->eeconfig()->m_AutoplaceFields.enable )
807 {
808 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
809
810 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
811 symbol->AutoplaceFields( screen, fieldsAutoplaced );
812 }
813 }
814
815 symbol->SetSchSymbolLibraryName( wxEmptyString );
816 screen->Append( symbol );
817
818 if( resetPositions )
819 {
820 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
821
822 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
823 symbol->AutoplaceFields( screen, fieldsAutoplaced );
824 }
825
826 // Clear alternate pins as required.
827 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
828 {
829 for( SCH_PIN* pin : symbol->GetPins( &instance ) )
830 {
831 if( !pin->GetAlt().IsEmpty() )
832 {
833 // There is a bug that allows the alternate pin name to be set to the default pin
834 // name which causes library symbol comparison errors. Clear the alternate pin
835 // name in this case even if the reset option is not checked. Also clear the
836 // alternate pin name if it no longer exists in the alternate pin map.
837 if( m_resetAlternatePin->IsChecked()
838 || ( pin->GetAlt() == pin->GetBaseName() )
839 || ( pin->GetAlternates().count( pin->GetAlt() ) == 0 ) )
840 {
841 pin->SetAlt( wxEmptyString );
842 }
843 }
844 }
845 }
846
847 if( m_resetPinMapOverrides->IsChecked() )
848 {
849 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
850 symbol->SetPinMapOverride( PIN_MAP_INSTANCE_OVERRIDE(), &instance );
851 }
852
853 frame->GetCanvas()->GetView()->Update( symbol );
854
855 msg = getSymbolReferences( *symbol, symbol_change_info.m_LibId, &initialLibLinkName );
856 msg += wxS( ": OK" );
857 m_messagePanel->Report( msg, RPT_SEVERITY_ACTION );
858 matchesProcessed +=1;
859 }
860
861 return matchesProcessed;
862}
863
864
866 const wxString* aOldLibLinkName )
867{
868 wxString msg;
869 wxString references;
870 const LIB_ID& oldId = aSymbol.GetLibId();
871 wxString oldLibLinkName; // For report
872
873 if( aOldLibLinkName )
874 oldLibLinkName = *aOldLibLinkName;
875 else
876 oldLibLinkName = UnescapeString( oldId.Format() );
877
878 SCH_EDIT_FRAME* parent = dynamic_cast< SCH_EDIT_FRAME* >( GetParent() );
879
880 wxCHECK( parent, msg );
881
882 SCH_SHEET_LIST sheets = parent->Schematic().Hierarchy();
883
884 for( const SCH_SYMBOL_INSTANCE& instance : aSymbol.GetInstances() )
885 {
886 // Only include the symbol instances for the current project.
887 if( !sheets.HasPath( instance.m_Path ) )
888 continue;
889
890 if( references.IsEmpty() )
891 references = instance.m_Reference;
892 else
893 references += wxT( " " ) + instance.m_Reference;
894 }
895
896 if( m_mode == MODE::UPDATE )
897 {
898 if( aSymbol.GetInstances().size() == 1 )
899 {
900 msg.Printf( _( "Update symbol %s from '%s' to '%s'" ),
901 references,
902 oldLibLinkName,
903 UnescapeString( aNewId.Format() ) );
904 }
905 else
906 {
907 msg.Printf( _( "Update symbols %s from '%s' to '%s'" ),
908 references,
909 oldLibLinkName,
910 UnescapeString( aNewId.Format() ) );
911 }
912 }
913 else // mode is MODE::CHANGE
914 {
915 if( aSymbol.GetInstances().size() == 1 )
916 {
917 msg.Printf( _( "Change symbol %s from '%s' to '%s'" ),
918 references,
919 oldLibLinkName,
920 UnescapeString( aNewId.Format() ) );
921 }
922 else
923 {
924 msg.Printf( _( "Change symbols %s from '%s' to '%s'" ),
925 references,
926 oldLibLinkName,
927 UnescapeString( aNewId.Format() ) );
928 }
929 }
930
931 return msg;
932}
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:180
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:132
virtual VECTOR2I GetTextPos() const
Definition eda_text.h:294
virtual bool IsVisible() const
Definition eda_text.h:208
virtual void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:576
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:428
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:381
AUTOPLACE_FIELDS m_AutoplaceFields
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:221
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:80
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:123
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.
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #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:218
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:128
FIELD_T GetId() const
Definition sch_field.h:132
void SetCanAutoplace(bool aCanPlace)
Definition sch_field.h:230
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
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:229
void SetText(const wxString &aText) override
void SetNameShown(bool aShown=true)
Definition sch_field.h:219
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
void SetPrivate(bool aPrivate)
Definition sch_item.h:247
int GetUnit() const
Definition sch_item.h:233
bool IsPrivate() const
Definition sch_item.h:248
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:115
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
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:69
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:128
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:158
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
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:65
@ AUTOPLACE_MANUAL
Definition sch_item.h:68
@ AUTOPLACE_AUTO
Definition sch_item.h:67
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:...
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
@ CTX_LIBID
Per-instance override of the active pin map and a sparse delta on top.
Definition pin_map.h:199
A simple container for schematic symbol instance information.
wxString GetDefaultFieldName(FIELD_T aFieldId, bool aTranslateForHI)
Return a default symbol field name for a mandatory field type.
#define DO_TRANSLATE
#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".
wxString GetCanonicalFieldName(FIELD_T aFieldType)
KIBIS_PIN * pin
@ SCH_SYMBOL_T
Definition typeinfo.h:169
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683