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
645 for( const auto& [ symbol, symbol_change_info ] : symbols )
646 {
647 // Remember initial link before changing for diags purpose
648 wxString initialLibLinkName = UnescapeString( symbol->GetLibId().Format() );
649
650 LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol_change_info.m_LibId );
651
652 wxCHECK2( libSymbol, continue );
653
654 if( symbol_change_info.m_LibId != symbol->GetLibId() )
655 symbol->SetLibId( symbol_change_info.m_LibId );
656
657 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
658 SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
659
660 symbol->SetLibSymbol( flattenedSymbol.release() );
661
662 if( m_resetAttributes->GetValue() )
663 {
664 // Fetch the attributes from the *flattened* library symbol. They are not supported
665 // in derived symbols.
666 symbol->SetExcludedFromSim( symbol->GetLibSymbolRef()->GetExcludedFromSim() );
667 symbol->SetExcludedFromBOM( symbol->GetLibSymbolRef()->GetExcludedFromBOM() );
668 symbol->SetExcludedFromBoard( symbol->GetLibSymbolRef()->GetExcludedFromBoard() );
669 }
670
671 if( m_resetPinTextVisibility->GetValue() )
672 {
673 symbol->SetShowPinNames( symbol->GetLibSymbolRef()->GetShowPinNames() );
674 symbol->SetShowPinNumbers( symbol->GetLibSymbolRef()->GetShowPinNumbers() );
675 }
676
677 bool removeExtras = m_removeExtraBox->GetValue();
678 bool resetVis = m_resetFieldVisibilities->GetValue();
679 bool resetEffects = m_resetFieldEffects->GetValue();
680 bool resetPositions = m_resetFieldPositions->GetValue();
681
682 for( int ii = (int) symbol->GetFields().size() - 1; ii >= 0; ii-- )
683 {
684 SCH_FIELD& field = symbol->GetFields()[ii];
685 SCH_FIELD* libField = nullptr;
686 bool doUpdate = field.IsPrivate();
687
688 // Mandatory fields always exist in m_updateFields, but these names can be translated.
689 // so use GetCanonicalName().
690 doUpdate |= alg::contains( m_updateFields, field.GetCanonicalName() );
691
692 if( !doUpdate )
693 continue;
694
695 if( field.IsMandatory() )
696 libField = symbol->GetLibSymbolRef()->GetField( field.GetId() );
697 else
698 libField = symbol->GetLibSymbolRef()->GetField( field.GetName() );
699
700 if( libField )
701 {
702 field.SetPrivate( libField->IsPrivate() );
703
704 bool resetText = libField->GetText().IsEmpty() ? m_resetEmptyFields->GetValue()
705 : m_resetFieldText->GetValue();
706
707 if( resetText )
708 {
709 if( field.GetId() == FIELD_T::REFERENCE )
710 {
711 wxString prefix = UTIL::GetRefDesPrefix( libField->GetText() );
712
713 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
714 {
715 wxString ref = symbol->GetRef( &instance );
716 int number = UTIL::GetRefDesNumber( ref );
717
718 if( number >= 0 )
719 ref.Printf( wxS( "%s%d" ), prefix, number );
720 else
721 ref = UTIL::GetRefDesUnannotated( prefix );
722
723 symbol->SetRef( &instance, ref );
724 }
725 }
726 else if( field.GetId() == FIELD_T::VALUE )
727 {
728 if( !symbol->IsPower() || m_resetCustomPower->IsChecked() )
729 symbol->SetValueFieldText( UnescapeString( libField->GetText() ) );
730 }
731 else
732 {
733 field.SetText( libField->GetText() );
734 }
735 }
736
737 if( resetVis )
738 field.SetVisible( libField->IsVisible() );
739
740 if( resetEffects )
741 {
742 // Careful: the visible bit and position are also set by SetAttributes()
743 bool visible = field.IsVisible();
744 VECTOR2I pos = field.GetPosition();
745
746 field.SetAttributes( *libField );
747
748 field.SetVisible( visible );
749 field.SetPosition( pos );
750 field.SetNameShown( libField->IsNameShown() );
751 field.SetCanAutoplace( libField->CanAutoplace() );
752 }
753
754 if( resetPositions )
755 field.SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
756 }
757 else if( !field.IsMandatory() && removeExtras )
758 {
759 symbol->RemoveField( field.GetName() );
760 }
761 }
762
763 std::vector<SCH_FIELD*> libFields;
764 symbol->GetLibSymbolRef()->GetFields( libFields );
765
766 for( SCH_FIELD* libField : libFields )
767 {
768 if( libField->IsMandatory() )
769 continue;
770
771 if( !alg::contains( m_updateFields, libField->GetCanonicalName() ) )
772 continue;
773
774 if( !symbol->GetField( libField->GetName() ) )
775 {
776 SCH_FIELD* schField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, libField->GetName() ) );
777
778 // SetAttributes() also covers text angle, size, italic and bold
779 schField->SetAttributes( *libField );
780 schField->SetVisible( libField->IsVisible() );
781 schField->SetText( libField->GetText() );
782 schField->SetTextPos( symbol->GetPosition() + libField->GetTextPos() );
783 schField->SetPrivate( libField->IsPrivate() );
784 }
785
786 if( resetPositions && frame->eeconfig()->m_AutoplaceFields.enable )
787 {
788 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
789
790 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
791 symbol->AutoplaceFields( screen, fieldsAutoplaced );
792 }
793 }
794
795 symbol->SetSchSymbolLibraryName( wxEmptyString );
796 screen->Append( symbol );
797
798 if( resetPositions )
799 {
800 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
801
802 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
803 symbol->AutoplaceFields( screen, fieldsAutoplaced );
804 }
805
806 // Clear alternate pins as required.
807 for( const SCH_SHEET_PATH& instance : symbol_change_info.m_Instances )
808 {
809 for( SCH_PIN* pin : symbol->GetPins( &instance ) )
810 {
811 if( !pin->GetAlt().IsEmpty() )
812 {
813 // There is a bug that allows the alternate pin name to be set to the default pin
814 // name which causes library symbol comparison errors. Clear the alternate pin
815 // name in this case even if the reset option is not checked. Also clear the
816 // alternate pin name if it no longer exists in the alternate pin map.
817 if( m_resetAlternatePin->IsChecked()
818 || ( pin->GetAlt() == pin->GetBaseName() )
819 || ( pin->GetAlternates().count( pin->GetAlt() ) == 0 ) )
820 {
821 pin->SetAlt( wxEmptyString );
822 }
823 }
824 }
825 }
826
827 frame->GetCanvas()->GetView()->Update( symbol );
828
829 msg = getSymbolReferences( *symbol, symbol_change_info.m_LibId, &initialLibLinkName );
830 msg += wxS( ": OK" );
831 m_messagePanel->Report( msg, RPT_SEVERITY_ACTION );
832 matchesProcessed +=1;
833 }
834
835 return matchesProcessed;
836}
837
838
840 const wxString* aOldLibLinkName )
841{
842 wxString msg;
843 wxString references;
844 const LIB_ID& oldId = aSymbol.GetLibId();
845 wxString oldLibLinkName; // For report
846
847 if( aOldLibLinkName )
848 oldLibLinkName = *aOldLibLinkName;
849 else
850 oldLibLinkName = UnescapeString( oldId.Format() );
851
852 SCH_EDIT_FRAME* parent = dynamic_cast< SCH_EDIT_FRAME* >( GetParent() );
853
854 wxCHECK( parent, msg );
855
856 SCH_SHEET_LIST sheets = parent->Schematic().Hierarchy();
857
858 for( const SCH_SYMBOL_INSTANCE& instance : aSymbol.GetInstances() )
859 {
860 // Only include the symbol instances for the current project.
861 if( !sheets.HasPath( instance.m_Path ) )
862 continue;
863
864 if( references.IsEmpty() )
865 references = instance.m_Reference;
866 else
867 references += wxT( " " ) + instance.m_Reference;
868 }
869
870 if( m_mode == MODE::UPDATE )
871 {
872 if( aSymbol.GetInstances().size() == 1 )
873 {
874 msg.Printf( _( "Update symbol %s from '%s' to '%s'" ),
875 references,
876 oldLibLinkName,
877 UnescapeString( aNewId.Format() ) );
878 }
879 else
880 {
881 msg.Printf( _( "Update symbols %s from '%s' to '%s'" ),
882 references,
883 oldLibLinkName,
884 UnescapeString( aNewId.Format() ) );
885 }
886 }
887 else // mode is MODE::CHANGE
888 {
889 if( aSymbol.GetInstances().size() == 1 )
890 {
891 msg.Printf( _( "Change symbol %s from '%s' to '%s'" ),
892 references,
893 oldLibLinkName,
894 UnescapeString( aNewId.Format() ) );
895 }
896 else
897 {
898 msg.Printf( _( "Change symbols %s from '%s' to '%s'" ),
899 references,
900 oldLibLinkName,
901 UnescapeString( aNewId.Format() ) );
902 }
903 }
904
905 return msg;
906}
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
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: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.
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.
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:76
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:135
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:165
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
wxString getLibIdValue(const wxTextCtrl *aCtrl)
#define _(s)
@ FRAME_SYMBOL_CHOOSER
Definition frame_type.h: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