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 along
20 * with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <algorithm>
24
25#include <bitmaps.h>
26#include <connection_graph.h>
27#include <string_utils.h> // WildCompareString
28#include <kiway.h>
29#include <refdes_utils.h>
30#include <core/kicad_algo.h>
32#include <sch_symbol.h>
33#include <sch_edit_frame.h>
34#include <sch_screen.h>
35#include <schematic.h>
36#include <template_fieldnames.h>
39#include <sch_commit.h>
40
41bool g_selectRefDes = false;
42bool g_selectValue = false;
43
44
47 m_symbol( aSymbol),
48 m_mode( aMode )
49{
50 wxASSERT( aParent );
51
52 if( m_mode == MODE::UPDATE )
53 {
54 m_newIdSizer->Show( false );
55 }
56 else
57 {
58 m_matchAll->SetLabel( _( "Change all symbols in schematic" ) );
59 SetTitle( _( "Change Symbols" ) );
60 m_matchSizer->FindItem( m_matchAll )->Show( false );
61
62 m_matchByReference->SetLabel( _( "Change symbols matching reference designator:" ) );
63 m_matchByValue->SetLabel( _( "Change symbols matching value:" ) );
64 m_matchById->SetLabel( _( "Change symbols matching library identifier:" ) );
65
66 m_updateFieldsSizer->GetStaticBox()->SetLabel( _( "Update Fields" ) );
67 m_removeExtraBox->SetLabel( _( "Remove fields if not in new symbol" ) );
68 m_resetEmptyFields->SetLabel( _( "Reset fields if empty in new symbol" ) );
69 m_resetFieldText->SetLabel( _( "Update field text" ) );
70 m_resetFieldVisibilities->SetLabel( _( "Update field visibilities" ) );
71 m_resetFieldEffects->SetLabel( _( "Update field sizes and styles" ) );
72 m_resetFieldPositions->SetLabel( _( "Update field positions" ) );
73 m_resetAttributes->SetLabel( _( "Update symbol attributes" ) );
74 m_resetPinTextVisibility->SetLabel( _( "Update pin name/number visibilities" ) );
75 m_resetAlternatePin->SetLabel( _( "Reset alternate pin functions" ) );
76 m_resetCustomPower->SetLabel( _( "Reset custom power symbols" ) );
77
78 if( m_symbol )
79 m_matchBySelection->SetLabel( _( "Change selected symbol(s)" ) );
80 }
81
82 if( !m_symbol )
83 m_matchSizer->FindItem( m_matchBySelection )->Show( false );
84
87
88 m_matchSizer->SetEmptyCellSize( wxSize( 0, 0 ) );
89 m_matchSizer->Layout();
90
91 for( FIELD_T fieldId : MANDATORY_FIELDS )
92 {
93 int listIdx = (int) m_fieldsBox->GetCount();
94
95 m_fieldsBox->Append( GetDefaultFieldName( fieldId, DO_TRANSLATE ) );
96
97 // List boxes aren't currently handled in DIALOG_SHIM's control-state-save/restore
98 if( fieldId == FIELD_T::REFERENCE )
99 m_fieldsBox->Check( listIdx, g_selectRefDes );
100 else if( fieldId == FIELD_T::VALUE )
101 m_fieldsBox->Check( listIdx, g_selectValue );
102 else
103 m_fieldsBox->Check( listIdx, true );
104
105 m_mandatoryFieldListIndexes[fieldId] = listIdx;
106 }
107
109
110 // initialize controls based on m_mode in case there is no saved state yet
111 m_removeExtraBox->SetValue( false );
112 m_resetEmptyFields->SetValue( false );
113 m_resetFieldText->SetValue( true );
114 m_resetCustomPower->SetValue( false );
115 m_resetFieldVisibilities->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
116 m_resetFieldEffects->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
117 m_resetFieldPositions->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
118 m_resetAttributes->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
119 m_resetPinTextVisibility->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
120 m_resetAlternatePin->SetValue( ( m_mode == MODE::CHANGE ) ? true : false );
121
122 m_messagePanel->SetLazyUpdate( true );
123 m_messagePanel->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
124
125 // DIALOG_SHIM needs a unique hash_key because classname is not sufficient
126 // because the update and change versions of this dialog have different controls.
127 m_hash_key = TO_UTF8( GetTitle() );
128
129 wxString okLabel = m_mode == MODE::CHANGE ? _( "Change" ) : _( "Update" );
130
131 SetupStandardButtons( { { wxID_OK, okLabel },
132 { wxID_CANCEL, _( "Close" ) } } );
133
134 // Now all widgets have the size fixed, call FinishDialogSettings
136}
137
138
140{
141 if( m_symbol )
142 {
143 SCH_SHEET_PATH* currentSheet = &m_symbol->Schematic()->CurrentSheet();
144
145 m_specifiedReference->ChangeValue( m_symbol->GetRef( currentSheet ) );
146 m_specifiedValue->ChangeValue( UnescapeString( m_symbol->GetField( FIELD_T::VALUE )->GetText() ) );
147 m_specifiedId->ChangeValue( UnescapeString( m_symbol->GetLibId().Format() ) );
148 }
149
150 if( m_symbol && m_symbol->IsSelected() )
151 m_matchBySelection->SetValue( true );
152 else if( m_mode == MODE::UPDATE )
153 m_matchAll->SetValue( true );
154 else
155 m_matchByReference->SetValue( true );
156
157 return true;
158}
159
160
161void DIALOG_CHANGE_SYMBOLS::onMatchByAll( wxCommandEvent& aEvent )
162{
164}
165
166
167void DIALOG_CHANGE_SYMBOLS::onMatchBySelected( wxCommandEvent& aEvent )
168{
170}
171
172
173void DIALOG_CHANGE_SYMBOLS::onMatchByReference( wxCommandEvent& aEvent )
174{
176 m_specifiedReference->SetFocus();
177}
178
179
180void DIALOG_CHANGE_SYMBOLS::onMatchByValue( wxCommandEvent& aEvent )
181{
183 m_specifiedValue->SetFocus();
184}
185
186
187void DIALOG_CHANGE_SYMBOLS::onMatchById( wxCommandEvent& aEvent )
188{
190 m_specifiedId->SetFocus();
191}
192
193
195{
197 event.Skip(); // Mandatory in wxFocusEvent
198}
199
200
202{
204 event.Skip(); // Mandatory in wxFocusEvent
205}
206
207
209{
211 event.Skip(); // Mandatory in wxFocusEvent
212}
213
214
216{
217 // List boxes aren't currently handled in DIALOG_SHIM's control-state-save/restore
220}
221
222
223wxString getLibIdValue( const wxTextCtrl* aCtrl )
224{
225 wxString rawValue = aCtrl->GetValue();
226 wxString itemName;
227 wxString libName = rawValue.BeforeFirst( ':', &itemName );
228
229 return EscapeString( libName, CTX_LIBID ) + ':' + EscapeString( itemName, CTX_LIBID );
230}
231
232
234{
235 wxString newName = getLibIdValue( m_specifiedId );
236
237 if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_SYMBOL_CHOOSER, true, this ) )
238 {
239 if( frame->ShowModal( &newName, this ) )
240 {
241 m_specifiedId->SetValue( UnescapeString( newName ) );
243 }
244
245 frame->Destroy();
246 }
247}
248
249
251{
252 wxString newName = getLibIdValue( m_newId );
253
254 if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_SYMBOL_CHOOSER, true, this ) )
255 {
256 if( frame->ShowModal( &newName, this ) )
257 {
258 m_newId->SetValue( UnescapeString( newName ) );
260 }
261
262 frame->Destroy();
263 }
264}
265
266
268{
269 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
270
271 wxCHECK( frame, /* void */ );
272
273 // Load non-mandatory fields from all matching symbols and their library symbols
274 std::set<wxString> fieldNames;
275
276 for( SCH_SHEET_PATH& instance : frame->Schematic().Hierarchy() )
277 {
278 SCH_SCREEN* screen = instance.LastScreen();
279
280 wxCHECK2( screen, continue );
281
282 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
283 {
284 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
285
286 wxCHECK2( symbol, continue );
287
288 if( !isMatch( symbol, &instance ) )
289 continue;
290
291 for( SCH_FIELD& field : symbol->GetFields() )
292 {
293 if( !field.IsMandatory() && !field.IsPrivate() )
294 fieldNames.insert( field.GetName() );
295 }
296
297 if( m_mode == MODE::UPDATE && symbol->GetLibId().IsValid() )
298 {
299 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol->GetLibId() );
300
301 if( libSymbol )
302 {
303 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
304 std::vector<SCH_FIELD*> orderedLibFields;
305
306 flattenedSymbol->GetFields( orderedLibFields );
307
308 for( SCH_FIELD* libField : orderedLibFields )
309 {
310 if( !libField->IsMandatory() && !libField->IsPrivate() )
311 fieldNames.insert( libField->GetName() );
312 }
313 }
314 }
315 }
316 }
317
318 // Load non-mandatory fields from the change-to library symbol
319 if( m_mode == MODE::CHANGE )
320 {
321 LIB_ID newId;
322
323 newId.Parse( getLibIdValue( m_newId ) );
324
325 if( newId.IsValid() )
326 {
327 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( newId );
328
329 if( libSymbol )
330 {
331 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
332 std::vector<SCH_FIELD*> orderedLibFields;
333
334 flattenedSymbol->GetFields( orderedLibFields );
335
336 for( SCH_FIELD* libField : orderedLibFields )
337 {
338 if( !libField->IsMandatory() && !libField->IsPrivate() )
339 fieldNames.insert( libField->GetName() );
340 }
341 }
342 }
343 }
344
345 // Update the listbox widget
346 wxArrayInt checkedItems;
347 wxArrayString checkedNames;
348
349 m_fieldsBox->GetCheckedItems( checkedItems );
350
351 for( int ii : checkedItems )
352 checkedNames.push_back( m_fieldsBox->GetString( ii ) );
353
354 bool allChecked = true;
355
356 for( int ii = 0; ii < (int) m_fieldsBox->GetCount(); ++ii )
357 {
358 if( !m_fieldsBox->IsChecked( ii )
361 {
362 allChecked = false;
363 }
364 }
365
366 auto isMandatoryField =
367 [&]( int listbox_idx )
368 {
369 for( FIELD_T fieldId : MANDATORY_FIELDS )
370 {
371 if( m_mandatoryFieldListIndexes[fieldId] == listbox_idx )
372 return true;
373 }
374
375 return false;
376 };
377
378 for( int ii = (int) m_fieldsBox->GetCount() - 1; ii >= 0; --ii )
379 {
380 if( isMandatoryField( ii ) )
381 continue;
382
383 m_fieldsBox->Delete( ii );
384 }
385
386 for( const wxString& fieldName : fieldNames )
387 {
388 m_fieldsBox->Append( fieldName );
389
390 if( allChecked || alg::contains( checkedNames, fieldName ) )
391 m_fieldsBox->Check( m_fieldsBox->GetCount() - 1, true );
392 }
393}
394
395
397{
398 for( unsigned i = 0; i < m_fieldsBox->GetCount(); ++i )
399 m_fieldsBox->Check( i, aSelect );
400}
401
402
404{
405 m_removeExtraBox->SetValue( aCheck );
406 m_resetEmptyFields->SetValue( aCheck );
407 m_resetFieldText->SetValue( aCheck );
408 m_resetFieldVisibilities->SetValue( aCheck );
409 m_resetFieldEffects->SetValue( aCheck );
410 m_resetFieldPositions->SetValue( aCheck );
411 m_resetPinTextVisibility->SetValue( aCheck );
412 m_resetAlternatePin->SetValue( aCheck );
413 m_resetAttributes->SetValue( aCheck );
414 m_resetCustomPower->SetValue( aCheck );
415}
416
417
418void DIALOG_CHANGE_SYMBOLS::onOkButtonClicked( wxCommandEvent& aEvent )
419{
420 SCH_EDIT_FRAME* parent = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
421
422 wxCHECK( parent, /* void */ );
423
424 wxBusyCursor dummy;
425 SCH_COMMIT commit( parent );
426
427 m_messagePanel->Clear();
428 m_messagePanel->Flush( false );
429
430 // Create the set of fields to be updated. Use non translated (canonical) names
431 // for mandatory fields
432 m_updateFields.clear();
433
434 for( unsigned ii = 0; ii < m_fieldsBox->GetCount(); ++ii )
435 {
436 if( m_fieldsBox->IsChecked( ii ) )
437 m_updateFields.insert( m_fieldsBox->GetString( ii ) );
438 }
439
440 for( FIELD_T fieldId : MANDATORY_FIELDS )
441 {
442 if( m_fieldsBox->IsChecked( m_mandatoryFieldListIndexes[fieldId] ) )
443 m_updateFields.insert( GetCanonicalFieldName( fieldId ) );
444 }
445
446 if( processMatchingSymbols( &commit) )
447 commit.Push( m_mode == MODE::CHANGE ? _( "Change Symbols" ) : _( "Update Symbols" ) );
448
449 m_messagePanel->Flush( false );
450}
451
452
454{
455 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
456
457 wxCHECK( frame, false );
458
459 if( !aSymbol )
460 return false;
461
462 if( m_matchAll->GetValue() )
463 {
464 return true;
465 }
466 else if( m_matchBySelection->GetValue() )
467 {
468 return aSymbol == m_symbol || aSymbol->IsSelected();
469 }
470 else if( m_matchByReference->GetValue() )
471 {
472 return WildCompareString( m_specifiedReference->GetValue(),
473 UnescapeString( aSymbol->GetRef( aInstance, false ) ),
474 false );
475 }
476 else if( m_matchByValue->GetValue() )
477 {
478 return WildCompareString( m_specifiedValue->GetValue(),
480 false );
481 }
482 else if( m_matchById )
483 {
484 LIB_ID id;
485
487 return aSymbol->GetLibId() == id;
488 }
489
490 return false;
491}
492
493
495{
496 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
497
498 wxCHECK( frame, false );
499
500 LIB_ID newId;
501 int matchesProcessed = 0;
502 SCH_SYMBOL* symbol = nullptr;
503
504 if( m_mode == MODE::CHANGE )
505 {
506 newId.Parse( getLibIdValue( m_newId ) );
507
508 if( !newId.IsValid() )
509 return false;
510 }
511
512 std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO> symbols;
513
514 for( SCH_SHEET_PATH& instance : frame->Schematic().Hierarchy() )
515 {
516 SCH_SCREEN* screen = instance.LastScreen();
517
518 wxCHECK2( screen, continue );
519
520 // Fetch all the symbols that meet the change criteria.
521 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
522 {
523 symbol = static_cast<SCH_SYMBOL*>( item );
524
525 wxCHECK2( symbol, continue );
526
527 if( !isMatch( symbol, &instance ) )
528 continue;
529
530 if( m_mode == MODE::UPDATE )
531 newId = symbol->GetLibId();
532
533 auto it = symbols.find( symbol );
534
535 if( it == symbols.end() )
536 {
538
539 info.m_Instances.emplace_back( instance );
540 info.m_LibId = newId;
541 symbols.insert( { symbol, info } );
542 }
543 else
544 {
545 it->second.m_Instances.emplace_back( instance );
546 }
547 }
548 }
549
550 if( symbols.size() > 0 )
551 matchesProcessed += processSymbols( aCommit, symbols );
552 else
553 m_messagePanel->Report( _( "*** No symbols matching criteria found ***" ), RPT_SEVERITY_ERROR );
554
556
557 return matchesProcessed;
558}
559
560
562 SYMBOL_CHANGE_INFO>& aSymbols )
563{
564 wxCHECK( !aSymbols.empty(), 0 );
565
566 int matchesProcessed = 0;
567 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
568 wxString msg;
569
570 wxCHECK( frame, 0 );
571
572 std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO> symbols = aSymbols;
573 std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO>::iterator it = symbols.begin();
574
575 // Remove all symbols that don't have a valid library symbol link or enough units to
576 // satisfy the library symbol update.
577 while( it != symbols.end() )
578 {
579 SCH_SYMBOL* symbol = it->first;
580
581 wxCHECK2( symbol, ++it; continue );
582
583 if( !it->second.m_LibId.IsValid() )
584 {
585 msg = getSymbolReferences( *symbol, it->second.m_LibId );
586 msg << wxT( ": " ) << _( "*** symbol lib id not valid ***" );
587 m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
588 it = symbols.erase( it );
589 continue;
590 }
591
592 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( it->second.m_LibId );
593
594 if( !libSymbol )
595 {
596 msg = getSymbolReferences( *symbol, it->second.m_LibId );
597 msg << wxT( ": " ) << _( "*** symbol not found ***" );
598 m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
599 it = symbols.erase( it );
600 continue;
601 }
602
603 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
604
605 if( flattenedSymbol->GetUnitCount() < symbol->GetUnit() )
606 {
607 msg = getSymbolReferences( *symbol, it->second.m_LibId );
608 msg << wxT( ": " ) << _( "*** new symbol has too few units ***" );
609 m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
610 it = symbols.erase( it );
611 }
612 else
613 {
614 ++it;
615 }
616 }
617
618 // Removing the symbol needs to be done before the LIB_SYMBOL is changed to prevent stale
619 // library symbols in the schematic file.
620 for( const auto& [ symbol, symbol_change_info ] : symbols )
621 {
622 wxCHECK( symbol && !symbol_change_info.m_Instances.empty(), 0 );
623
624 SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
625
626 wxCHECK( screen, 0 );
627
628 screen->Remove( symbol );
629 SCH_SYMBOL* symbol_copy = static_cast<SCH_SYMBOL*>( symbol->Clone() );
630 aCommit->Modified( symbol, symbol_copy, screen );
631
632 CONNECTION_GRAPH* connectionGraph = screen->Schematic()->ConnectionGraph();
633
634 // When we replace the lib symbol below, we free the associated pins if the new symbol has
635 // fewer than the original. This will cause the connection graph to be out of date unless
636 // we replace references in the graph to the old symbol/pins with references to the ones
637 // stored in the undo stack.
638 if( connectionGraph )
639 connectionGraph->ExchangeItem( symbol, symbol_copy );
640 }
641
642 for( const auto& [ symbol, symbol_change_info ] : symbols )
643 {
644 // Remember initial link before changing for diags purpose
645 wxString initialLibLinkName = UnescapeString( symbol->GetLibId().Format() );
646
647 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol_change_info.m_LibId );
648
649 wxCHECK2( libSymbol, continue );
650
651 if( symbol_change_info.m_LibId != symbol->GetLibId() )
652 symbol->SetLibId( symbol_change_info.m_LibId );
653
654 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
655 SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
656
657 symbol->SetLibSymbol( flattenedSymbol.release() );
658
659 if( m_resetAttributes->GetValue() )
660 {
661 // Fetch the attributes from the *flattened* library symbol. They are not supported
662 // in derived symbols.
663 symbol->SetExcludedFromSim( symbol->GetLibSymbolRef()->GetExcludedFromSim() );
664 symbol->SetExcludedFromBOM( symbol->GetLibSymbolRef()->GetExcludedFromBOM() );
665 symbol->SetExcludedFromBoard( symbol->GetLibSymbolRef()->GetExcludedFromBoard() );
666 }
667
668 if( m_resetPinTextVisibility->GetValue() )
669 {
670 symbol->SetShowPinNames( symbol->GetLibSymbolRef()->GetShowPinNames() );
671 symbol->SetShowPinNumbers( symbol->GetLibSymbolRef()->GetShowPinNumbers() );
672 }
673
674 bool removeExtras = m_removeExtraBox->GetValue();
675 bool resetVis = m_resetFieldVisibilities->GetValue();
676 bool resetEffects = m_resetFieldEffects->GetValue();
677 bool resetPositions = m_resetFieldPositions->GetValue();
678
679 for( int ii = (int) symbol->GetFields().size() - 1; ii >= 0; ii-- )
680 {
681 SCH_FIELD& field = symbol->GetFields()[ii];
682 SCH_FIELD* libField = nullptr;
683 bool doUpdate = field.IsPrivate();
684
685 // Mandatory fields always exist in m_updateFields, but these names can be translated.
686 // so use GetCanonicalName().
687 doUpdate |= alg::contains( m_updateFields, field.GetCanonicalName() );
688
689 if( !doUpdate )
690 continue;
691
692 if( field.IsMandatory() )
693 libField = symbol->GetLibSymbolRef()->GetField( field.GetId() );
694 else
695 libField = symbol->GetLibSymbolRef()->GetField( field.GetName() );
696
697 if( libField )
698 {
699 field.SetPrivate( libField->IsPrivate() );
700
701 bool resetText = libField->GetText().IsEmpty() ? m_resetEmptyFields->GetValue()
702 : m_resetFieldText->GetValue();
703
704 if( resetText )
705 {
706 if( field.GetId() == FIELD_T::REFERENCE )
707 {
708 wxString prefix = UTIL::GetRefDesPrefix( libField->GetText() );
709
710 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
711 {
712 wxString ref = symbol->GetRef( &instance );
713 int number = UTIL::GetRefDesNumber( ref );
714
715 if( number >= 0 )
716 ref.Printf( wxS( "%s%d" ), prefix, number );
717 else
718 ref = UTIL::GetRefDesUnannotated( prefix );
719
720 symbol->SetRef( &instance, ref );
721 }
722 }
723 else if( field.GetId() == FIELD_T::VALUE )
724 {
725 if( !symbol->IsPower() || m_resetCustomPower->IsChecked() )
726 symbol->SetValueFieldText( UnescapeString( libField->GetText() ) );
727 }
728 else
729 {
730 field.SetText( libField->GetText() );
731 }
732 }
733
734 if( resetVis )
735 field.SetVisible( libField->IsVisible() );
736
737 if( resetEffects )
738 {
739 // Careful: the visible bit and position are also set by SetAttributes()
740 bool visible = field.IsVisible();
741 VECTOR2I pos = field.GetPosition();
742
743 field.SetAttributes( *libField );
744
745 field.SetVisible( visible );
746 field.SetPosition( pos );
747 field.SetNameShown( libField->IsNameShown() );
748 field.SetCanAutoplace( libField->CanAutoplace() );
749 }
750
751 if( resetPositions )
752 field.SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
753 }
754 else if( !field.IsMandatory() && removeExtras )
755 {
756 symbol->RemoveField( field.GetName() );
757 }
758 }
759
760 std::vector<SCH_FIELD*> libFields;
761 symbol->GetLibSymbolRef()->GetFields( libFields );
762
763 for( SCH_FIELD* libField : libFields )
764 {
765 if( libField->IsMandatory() )
766 continue;
767
768 if( !alg::contains( m_updateFields, libField->GetCanonicalName() ) )
769 continue;
770
771 if( !symbol->GetField( libField->GetName() ) )
772 {
773 SCH_FIELD* schField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, libField->GetName() ) );
774
775 // SetAttributes() also covers text angle, size, italic and bold
776 schField->SetAttributes( *libField );
777 schField->SetVisible( libField->IsVisible() );
778 schField->SetText( libField->GetText() );
779 schField->SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
780 schField->SetPrivate( libField->IsPrivate() );
781 }
782
783 if( resetPositions && frame->eeconfig()->m_AutoplaceFields.enable )
784 {
785 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
786
787 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
788 symbol->AutoplaceFields( screen, fieldsAutoplaced );
789 }
790 }
791
792 symbol->SetSchSymbolLibraryName( wxEmptyString );
793 screen->Append( symbol );
794
795 if( resetPositions )
796 {
797 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
798
799 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
800 symbol->AutoplaceFields( screen, fieldsAutoplaced );
801 }
802
803 // Clear alternate pins as required.
804 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
805 {
806 for( SCH_PIN* pin : symbol->GetPins( &instance ) )
807 {
808 if( !pin->GetAlt().IsEmpty() )
809 {
810 // There is a bug that allows the alternate pin name to be set to the default pin
811 // name which causes library symbol comparison errors. Clear the alternate pin
812 // name in this case even if the reset option is not checked. Also clear the
813 // alternate pin name if it no longer exists in the alternate pin map.
814 if( m_resetAlternatePin->IsChecked()
815 || ( pin->GetAlt() == pin->GetBaseName() )
816 || ( pin->GetAlternates().count( pin->GetAlt() ) == 0 ) )
817 {
818 pin->SetAlt( wxEmptyString );
819 }
820 }
821 }
822 }
823
824 frame->GetCanvas()->GetView()->Update( symbol );
825
826 msg = getSymbolReferences( *symbol, symbol_change_info.m_LibId, &initialLibLinkName );
827 msg += wxS( ": OK" );
828 m_messagePanel->Report( msg, RPT_SEVERITY_ACTION );
829 matchesProcessed +=1;
830 }
831
832 return matchesProcessed;
833}
834
835
837 const wxString* aOldLibLinkName )
838{
839 wxString msg;
840 wxString references;
841 const LIB_ID& oldId = aSymbol.GetLibId();
842 wxString oldLibLinkName; // For report
843
844 if( aOldLibLinkName )
845 oldLibLinkName = *aOldLibLinkName;
846 else
847 oldLibLinkName = UnescapeString( oldId.Format() );
848
849 SCH_EDIT_FRAME* parent = dynamic_cast< SCH_EDIT_FRAME* >( GetParent() );
850
851 wxCHECK( parent, msg );
852
853 SCH_SHEET_LIST sheets = parent->Schematic().Hierarchy();
854
855 for( const SCH_SYMBOL_INSTANCE& instance : aSymbol.GetInstances() )
856 {
857 // Only include the symbol instances for the current project.
858 if( !sheets.HasPath( instance.m_Path ) )
859 continue;
860
861 if( references.IsEmpty() )
862 references = instance.m_Reference;
863 else
864 references += wxT( " " ) + instance.m_Reference;
865 }
866
867 if( m_mode == MODE::UPDATE )
868 {
869 if( aSymbol.GetInstances().size() == 1 )
870 {
871 msg.Printf( _( "Update symbol %s from '%s' to '%s'" ),
872 references,
873 oldLibLinkName,
874 UnescapeString( aNewId.Format() ) );
875 }
876 else
877 {
878 msg.Printf( _( "Update symbols %s from '%s' to '%s'" ),
879 references,
880 oldLibLinkName,
881 UnescapeString( aNewId.Format() ) );
882 }
883 }
884 else // mode is MODE::CHANGE
885 {
886 if( aSymbol.GetInstances().size() == 1 )
887 {
888 msg.Printf( _( "Change symbol %s from '%s' to '%s'" ),
889 references,
890 oldLibLinkName,
891 UnescapeString( aNewId.Format() ) );
892 }
893 else
894 {
895 msg.Printf( _( "Change symbols %s from '%s' to '%s'" ),
896 references,
897 oldLibLinkName,
898 UnescapeString( aNewId.Format() ) );
899 }
900 }
901
902 return msg;
903}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
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:156
Calculate the connectivity of a schematic and generates netlists.
void ExchangeItem(SCH_ITEM *aOldItem, SCH_ITEM *aNewItem)
Replace all references to #aOldItem with #aNewItem in the graph.
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:127
const VECTOR2I & GetTextPos() const
Definition eda_text.h:272
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:97
virtual bool IsVisible() const
Definition eda_text.h:186
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:579
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:434
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:387
AUTOPLACE_FIELDS m_AutoplaceFields
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
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:60
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:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:52
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:172
UTF8 Format() const
Definition lib_id.cpp:119
Define a library symbol object.
Definition lib_symbol.h:85
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
CONNECTION_GRAPH * ConnectionGraph() const
Definition schematic.h:183
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:202
FIELD_T GetId() const
Definition sch_field.h:116
void SetCanAutoplace(bool aCanPlace)
Definition sch_field.h:214
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:213
void SetText(const wxString &aText) override
void SetNameShown(bool aShown=true)
Definition sch_field.h:203
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
void SetPrivate(bool aPrivate)
Definition sch_item.h:249
int GetUnit() const
Definition sch_item.h:238
bool IsPrivate() const
Definition sch_item.h:250
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:117
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
SCHEMATIC * Schematic() const
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.
bool g_selectRefDes
wxString getLibIdValue(const wxTextCtrl *aCtrl)
bool g_selectValue
#define _(s)
@ FRAME_SYMBOL_CHOOSER
Definition frame_type.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:100
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
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
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)
@ SCH_SYMBOL_T
Definition typeinfo.h:174
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695