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 // Removing the symbol needs to be done before the LIB_SYMBOL is changed to prevent stale
632 // library symbols in the schematic file.
633 for( const auto& [ symbol, symbol_change_info ] : symbols )
634 {
635 wxCHECK( symbol && !symbol_change_info.m_Instances.empty(), 0 );
636
637 SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
638
639 wxCHECK( screen, 0 );
640
641 screen->Remove( symbol );
642 SCH_SYMBOL* symbol_copy = static_cast<SCH_SYMBOL*>( symbol->Clone() );
643 aCommit->Modified( symbol, symbol_copy, screen );
644 }
645
646 for( const auto& [ symbol, symbol_change_info ] : symbols )
647 {
648 // Remember initial link before changing for diags purpose
649 wxString initialLibLinkName = UnescapeString( symbol->GetLibId().Format() );
650
651 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol_change_info.m_LibId );
652
653 wxCHECK2( libSymbol, continue );
654
655 if( symbol_change_info.m_LibId != symbol->GetLibId() )
656 symbol->SetLibId( symbol_change_info.m_LibId );
657
658 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
659 SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
660
661 const bool keepPinMaps = !m_resetPinMapOverrides->IsChecked();
662
663 PIN_MAP_SET savedPinMaps;
664 std::vector<ASSOCIATED_FOOTPRINT> savedAssociations;
665
666 if( keepPinMaps && symbol->GetLibSymbolRef() )
667 {
668 savedPinMaps = symbol->GetLibSymbolRef()->GetPinMaps();
669 savedAssociations = symbol->GetLibSymbolRef()->GetAssociatedFootprints();
670 }
671
672 symbol->SetLibSymbol( flattenedSymbol.release() );
673
674 if( keepPinMaps && symbol->GetLibSymbolRef() )
675 {
676 symbol->GetLibSymbolRef()->SetPinMaps( savedPinMaps );
677 symbol->GetLibSymbolRef()->SetAssociatedFootprints( savedAssociations );
678 }
679
680 if( m_resetAttributes->GetValue() )
681 {
682 // Fetch the attributes from the *flattened* library symbol. They are not supported
683 // in derived symbols.
684 symbol->SetExcludedFromSim( symbol->GetLibSymbolRef()->GetExcludedFromSim() );
685 symbol->SetExcludedFromBOM( symbol->GetLibSymbolRef()->GetExcludedFromBOM() );
686 symbol->SetExcludedFromBoard( symbol->GetLibSymbolRef()->GetExcludedFromBoard() );
687 symbol->SetExcludedFromPosFiles( symbol->GetLibSymbolRef()->GetExcludedFromPosFiles() );
688 }
689
690 if( m_resetPinTextVisibility->GetValue() )
691 {
692 symbol->SetShowPinNames( symbol->GetLibSymbolRef()->GetShowPinNames() );
693 symbol->SetShowPinNumbers( symbol->GetLibSymbolRef()->GetShowPinNumbers() );
694 }
695
696 bool removeExtras = m_removeExtraBox->GetValue();
697 bool resetVis = m_resetFieldVisibilities->GetValue();
698 bool resetEffects = m_resetFieldEffects->GetValue();
699 bool resetPositions = m_resetFieldPositions->GetValue();
700
701 for( int ii = (int) symbol->GetFields().size() - 1; ii >= 0; ii-- )
702 {
703 SCH_FIELD& field = symbol->GetFields()[ii];
704 SCH_FIELD* libField = nullptr;
705 bool doUpdate = field.IsPrivate();
706
707 // Mandatory fields always exist in m_updateFields, but these names can be translated,
708 // so use GetUntranslatedName().
709 doUpdate |= alg::contains( m_updateFields, field.GetUntranslatedName() );
710
711 if( !doUpdate )
712 continue;
713
714 if( field.IsMandatory() )
715 libField = symbol->GetLibSymbolRef()->GetField( field.GetId() );
716 else
717 libField = symbol->GetLibSymbolRef()->GetField( field.GetName() );
718
719 if( libField )
720 {
721 field.SetPrivate( libField->IsPrivate() );
722
723 bool resetText = libField->GetText().IsEmpty() ? m_resetEmptyFields->GetValue()
724 : m_resetFieldText->GetValue();
725
726 if( resetText )
727 {
728 if( field.GetId() == FIELD_T::REFERENCE )
729 {
730 wxString prefix = UTIL::GetRefDesPrefix( libField->GetText() );
731
732 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
733 {
734 wxString ref = symbol->GetRef( &instance );
735 int number = UTIL::GetRefDesNumber( ref );
736
737 if( number >= 0 )
738 ref.Printf( wxS( "%s%d" ), prefix, number );
739 else
740 ref = UTIL::GetRefDesUnannotated( prefix );
741
742 symbol->SetRef( &instance, ref );
743 }
744 }
745 else if( field.GetId() == FIELD_T::VALUE )
746 {
747 if( !symbol->IsPower() || m_resetCustomPower->IsChecked() )
748 symbol->SetValueFieldText( UnescapeString( libField->GetText() ) );
749 }
750 else
751 {
752 field.SetText( libField->GetText() );
753 }
754 }
755
756 if( resetVis )
757 field.SetVisible( libField->IsVisible() );
758
759 if( resetEffects )
760 {
761 // Careful: the visible bit and position are also set by SetAttributes()
762 bool visible = field.IsVisible();
763 VECTOR2I pos = field.GetPosition();
764
765 field.SetAttributes( *libField );
766
767 field.SetVisible( visible );
768 field.SetPosition( pos );
769 field.SetNameShown( libField->IsNameShown() );
770 field.SetCanAutoplace( libField->CanAutoplace() );
771 }
772
773 if( resetPositions )
774 field.SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
775 }
776 else if( !field.IsMandatory() && removeExtras )
777 {
778 symbol->RemoveField( field.GetName() );
779 }
780 }
781
782 std::vector<SCH_FIELD*> libFields;
783 symbol->GetLibSymbolRef()->GetFields( libFields );
784
785 for( SCH_FIELD* libField : libFields )
786 {
787 if( libField->IsMandatory() )
788 continue;
789
790 if( !alg::contains( m_updateFields, libField->GetUntranslatedName() ) )
791 continue;
792
793 if( !symbol->GetField( libField->GetName() ) )
794 {
795 SCH_FIELD* schField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, libField->GetName() ) );
796
797 // SetAttributes() also covers text angle, size, italic and bold
798 schField->SetAttributes( *libField );
799 schField->SetVisible( libField->IsVisible() );
800 schField->SetText( libField->GetText() );
801 schField->SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
802 schField->SetPrivate( libField->IsPrivate() );
803 }
804
805 if( resetPositions && frame->eeconfig()->m_AutoplaceFields.enable )
806 {
807 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
808
809 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
810 symbol->AutoplaceFields( screen, fieldsAutoplaced );
811 }
812 }
813
814 symbol->SetSchSymbolLibraryName( wxEmptyString );
815 screen->Append( symbol );
816
817 if( resetPositions )
818 {
819 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
820
821 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
822 symbol->AutoplaceFields( screen, fieldsAutoplaced );
823 }
824
825 // Clear alternate pins as required.
826 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
827 {
828 for( SCH_PIN* pin : symbol->GetPins( &instance ) )
829 {
830 if( !pin->GetAlt().IsEmpty() )
831 {
832 // There is a bug that allows the alternate pin name to be set to the default pin
833 // name which causes library symbol comparison errors. Clear the alternate pin
834 // name in this case even if the reset option is not checked. Also clear the
835 // alternate pin name if it no longer exists in the alternate pin map.
836 if( m_resetAlternatePin->IsChecked()
837 || ( pin->GetAlt() == pin->GetBaseName() )
838 || ( pin->GetAlternates().count( pin->GetAlt() ) == 0 ) )
839 {
840 pin->SetAlt( wxEmptyString );
841 }
842 }
843 }
844 }
845
846 if( m_resetPinMapOverrides->IsChecked() )
847 {
848 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
849 symbol->SetPinMapOverride( PIN_MAP_INSTANCE_OVERRIDE(), &instance );
850 }
851
852 frame->GetCanvas()->GetView()->Update( symbol );
853
854 msg = getSymbolReferences( *symbol, symbol_change_info.m_LibId, &initialLibLinkName );
855 msg += wxS( ": OK" );
856 m_messagePanel->Report( msg, RPT_SEVERITY_ACTION );
857 matchesProcessed +=1;
858 }
859
860 return matchesProcessed;
861}
862
863
865 const wxString* aOldLibLinkName )
866{
867 wxString msg;
868 wxString references;
869 const LIB_ID& oldId = aSymbol.GetLibId();
870 wxString oldLibLinkName; // For report
871
872 if( aOldLibLinkName )
873 oldLibLinkName = *aOldLibLinkName;
874 else
875 oldLibLinkName = UnescapeString( oldId.Format() );
876
877 SCH_EDIT_FRAME* parent = dynamic_cast< SCH_EDIT_FRAME* >( GetParent() );
878
879 wxCHECK( parent, msg );
880
881 SCH_SHEET_LIST sheets = parent->Schematic().Hierarchy();
882
883 for( const SCH_SYMBOL_INSTANCE& instance : aSymbol.GetInstances() )
884 {
885 // Only include the symbol instances for the current project.
886 if( !sheets.HasPath( instance.m_Path ) )
887 continue;
888
889 if( references.IsEmpty() )
890 references = instance.m_Reference;
891 else
892 references += wxT( " " ) + instance.m_Reference;
893 }
894
895 if( m_mode == MODE::UPDATE )
896 {
897 if( aSymbol.GetInstances().size() == 1 )
898 {
899 msg.Printf( _( "Update symbol %s from '%s' to '%s'" ),
900 references,
901 oldLibLinkName,
902 UnescapeString( aNewId.Format() ) );
903 }
904 else
905 {
906 msg.Printf( _( "Update symbols %s from '%s' to '%s'" ),
907 references,
908 oldLibLinkName,
909 UnescapeString( aNewId.Format() ) );
910 }
911 }
912 else // mode is MODE::CHANGE
913 {
914 if( aSymbol.GetInstances().size() == 1 )
915 {
916 msg.Printf( _( "Change symbol %s from '%s' to '%s'" ),
917 references,
918 oldLibLinkName,
919 UnescapeString( aNewId.Format() ) );
920 }
921 else
922 {
923 msg.Printf( _( "Change symbols %s from '%s' to '%s'" ),
924 references,
925 oldLibLinkName,
926 UnescapeString( aNewId.Format() ) );
927 }
928 }
929
930 return msg;
931}
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:221
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:539
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:389
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:342
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:119
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.
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:228
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:138
FIELD_T GetId() const
Definition sch_field.h:142
void SetCanAutoplace(bool aCanPlace)
Definition sch_field.h:240
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:239
void SetText(const wxString &aText) override
void SetNameShown(bool aShown=true)
Definition sch_field.h:229
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:165
void SetPrivate(bool aPrivate)
Definition sch_item.h:252
int GetUnit() const
Definition sch_item.h:237
bool IsPrivate() const
Definition sch_item.h:253
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:118
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:75
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:134
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:164
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:68
@ AUTOPLACE_MANUAL
Definition sch_item.h:71
@ AUTOPLACE_AUTO
Definition sch_item.h:70
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: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
KIBIS_PIN * pin
@ SCH_SYMBOL_T
Definition typeinfo.h:168
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683