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