KiCad PCB EDA Suite
Loading...
Searching...
No Matches
symbol_editor.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) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <pgm_base.h>
27#include <clipboard.h>
28#include <confirm.h>
29#include <kidialog.h>
30#include <kiway.h>
31#include <widgets/wx_infobar.h>
33#include <symbol_edit_frame.h>
34#include <template_fieldnames.h>
37#include <symbol_tree_pane.h>
39#include <richio.h>
40#include <widgets/lib_tree.h>
44#include <eda_list_dialog.h>
45#include <wx/clipbrd.h>
46#include <wx/filedlg.h>
47#include <wx/log.h>
48#include <project_sch.h>
49#include <string_utils.h>
50#include "symbol_saveas_type.h"
54
55
57{
58 wxString title;
59
61 {
63 title = wxT( "*" );
64
65 title += m_reference;
66 title += wxS( " " ) + _( "[from schematic]" );
67 }
68 else if( GetCurSymbol() )
69 {
71 title = wxT( "*" );
72
73 title += UnescapeString( GetCurSymbol()->GetLibId().Format() );
74
75 if( m_libMgr && m_libMgr->LibraryExists( GetCurLib() ) && m_libMgr->IsLibraryReadOnly( GetCurLib() ) )
76 title += wxS( " " ) + _( "[Read Only Library]" );
77 }
78 else
79 {
80 title = _( "[no symbol loaded]" );
81 }
82
83 title += wxT( " \u2014 " ) + _( "Symbol Editor" );
84 SetTitle( title );
85}
86
87
88void SYMBOL_EDIT_FRAME::SelectActiveLibrary( const wxString& aLibrary )
89{
90 wxString selectedLib = aLibrary;
91
92 if( selectedLib.empty() )
93 selectedLib = SelectLibrary( _( "Select Symbol Library" ), _( "Library:" ) );
94
95 if( !selectedLib.empty() )
96 SetCurLib( selectedLib );
97
99}
100
101
103{
104 if( GetCurSymbol() )
105 {
107 {
108 SCH_EDIT_FRAME* schframe = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
109
110 if( !schframe ) // happens when the schematic editor has been closed
111 {
112 DisplayErrorMessage( this, _( "No schematic currently open." ) );
113 return false;
114 }
115 else
116 {
118 GetScreen()->SetContentModified( false );
119 return true;
120 }
121 }
122 else
123 {
124 const wxString& libName = GetCurSymbol()->GetLibId().GetLibNickname();
125
126 if( m_libMgr->IsLibraryReadOnly( libName ) )
127 {
128 wxString msg = wxString::Format( _( "Symbol library '%s' is not writable." ),
129 libName );
130 wxString msg2 = _( "You must save to a different location." );
131
132 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) == wxID_OK )
133 return saveLibrary( libName, true );
134 }
135 else
136 {
137 return saveLibrary( libName, false );
138 }
139 }
140 }
141
142 return false;
143}
144
145
146bool SYMBOL_EDIT_FRAME::LoadSymbol( const LIB_ID& aLibId, int aUnit, int aBodyStyle )
147{
148 LIB_ID libId = aLibId;
151
152 // Some libraries can't be edited, so load the underlying chosen symbol
153 if( auto optRow = manager.GetRow( LIBRARY_TABLE_TYPE::SYMBOL, aLibId.GetLibNickname() );
154 optRow.has_value() )
155 {
156 const LIBRARY_TABLE_ROW* row = *optRow;
157 SCH_IO_MGR::SCH_FILE_T type = SCH_IO_MGR::EnumFromStr( row->Type() );
158
159 if( type == SCH_IO_MGR::SCH_DATABASE
160 || type == SCH_IO_MGR::SCH_CADSTAR_ARCHIVE
161 || type == SCH_IO_MGR::SCH_HTTP )
162 {
163 try
164 {
165 LIB_SYMBOL* readOnlySym = adapter->LoadSymbol( aLibId );
166
167 if( readOnlySym && readOnlySym->GetSourceLibId().IsValid() )
168 libId = readOnlySym->GetSourceLibId();
169 }
170 catch( const IO_ERROR& ioe )
171 {
172 wxString msg;
173
174 msg.Printf( _( "Error loading symbol %s from library '%s'." ),
175 aLibId.GetUniStringLibId(), aLibId.GetUniStringLibItemName() );
176 DisplayErrorMessage( this, msg, ioe.What() );
177 return false;
178 }
179 }
180 }
181
183 && GetCurSymbol()->GetLibId() == libId
184 && GetUnit() == aUnit
185 && GetBodyStyle() == aBodyStyle )
186 {
187 return true;
188 }
189
191 {
192 if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
193 [&]() -> bool
194 {
195 return saveCurrentSymbol();
196 } ) )
197 {
198 return false;
199 }
200 }
201
203
204 if( LoadSymbolFromCurrentLib( libId.GetLibItemName(), aUnit, aBodyStyle ) )
205 {
206 m_treePane->GetLibTree()->SelectLibId( libId );
207 m_treePane->GetLibTree()->ExpandLibId( libId );
208
209 m_centerItemOnIdle = libId;
210 Bind( wxEVT_IDLE, &SYMBOL_EDIT_FRAME::centerItemIdleHandler, this );
211 setSymWatcher( &libId );
212
213 return true;
214 }
215
216 return false;
217}
218
219
221{
222 m_treePane->GetLibTree()->CenterLibId( m_centerItemOnIdle );
223 Unbind( wxEVT_IDLE, &SYMBOL_EDIT_FRAME::centerItemIdleHandler, this );
224}
225
226
227bool SYMBOL_EDIT_FRAME::LoadSymbolFromCurrentLib( const wxString& aSymbolName, int aUnit,
228 int aBodyStyle )
229{
230 LIB_SYMBOL* symbol = nullptr;
231
232 try
233 {
234 symbol = PROJECT_SCH::SymbolLibAdapter( &Prj() )->LoadSymbol( GetCurLib(), aSymbolName );
235 }
236 catch( const IO_ERROR& ioe )
237 {
238 wxString msg;
239
240 msg.Printf( _( "Error loading symbol %s from library '%s'." ),
241 aSymbolName,
242 GetCurLib() );
243 DisplayErrorMessage( this, msg, ioe.What() );
244 return false;
245 }
246
247 if( !symbol || !LoadOneLibrarySymbolAux( symbol, GetCurLib(), aUnit, aBodyStyle ) )
248 return false;
249
250 // Enable synchronized pin edit mode for symbols with interchangeable units
252
255
257
258 return true;
259}
260
261
262bool SYMBOL_EDIT_FRAME::LoadOneLibrarySymbolAux( LIB_SYMBOL* aEntry, const wxString& aLibrary,
263 int aUnit, int aBodyStyle )
264{
265 bool rebuildMenuAndToolbar = false;
266
267 if( !aEntry || aLibrary.empty() )
268 return false;
269
270 if( aEntry->GetName().IsEmpty() )
271 {
272 wxLogWarning( "Symbol in library '%s' has empty name field.", aLibrary );
273 return false;
274 }
275
277
278 // Symbols from the schematic are edited in place and not managed by the library manager.
280 {
281 delete m_symbol;
282 m_symbol = nullptr;
283
284 SCH_SCREEN* screen = GetScreen();
285 delete screen;
288 rebuildMenuAndToolbar = true;
289 }
290
291 LIB_SYMBOL* lib_symbol = m_libMgr->GetBufferedSymbol( aEntry->GetName(), aLibrary );
292 wxCHECK( lib_symbol, false );
293
294 m_unit = aUnit > 0 ? aUnit : 1;
295 m_bodyStyle = aBodyStyle > 0 ? aBodyStyle : 1;
296
297 // The buffered screen for the symbol
298 SCH_SCREEN* symbol_screen = m_libMgr->GetScreen( lib_symbol->GetName(), aLibrary );
299
300 SetScreen( symbol_screen );
301 SetCurSymbol( new LIB_SYMBOL( *lib_symbol ), true );
302 SetCurLib( aLibrary );
303
304 if( rebuildMenuAndToolbar )
305 {
308 GetInfoBar()->Dismiss();
309 }
310
311 UpdateTitle();
313
315
316 if( !IsSymbolFromSchematic() )
317 {
318 LIB_ID libId = GetCurSymbol()->GetLibId();
319 setSymWatcher( &libId );
320 }
321
322 // Let tools add things to the view if necessary
323 if( m_toolManager )
325
327
328 // Display the document information based on the entry selected just in
329 // case the entry is an alias.
331 Refresh();
332
333 return true;
334}
335
336
338{
339 saveAllLibraries( false );
340 m_treePane->GetLibTree()->RefreshLibTree();
341}
342
343
344void SYMBOL_EDIT_FRAME::CreateNewSymbol( const wxString& aInheritFrom )
345{
347
348 wxString lib = getTargetLib();
349
350 if( !m_libMgr->LibraryExists( lib ) )
351 {
352 lib = SelectLibrary( _( "New Symbol" ), _( "Create symbol in library:" ) );
353
354 if( !m_libMgr->LibraryExists( lib ) )
355 return;
356 }
357
358 const auto validator =
359 [&]( wxString newName ) -> bool
360 {
361 if( newName.IsEmpty() )
362 {
363 wxMessageBox( _( "Symbol must have a name." ) );
364 return false;
365 }
366
367 if( !lib.empty() && m_libMgr->SymbolNameInUse( newName, lib ) )
368 {
369 wxString msg;
370
371 msg.Printf( _( "Symbol '%s' already exists in library '%s'." ),
372 UnescapeString( newName ),
373 lib );
374
375 KIDIALOG errorDlg( this, msg, _( "Confirmation" ),
376 wxOK | wxCANCEL | wxICON_WARNING );
377
378 errorDlg.SetOKLabel( _( "Overwrite" ) );
379
380 return errorDlg.ShowModal() == wxID_OK;
381 }
382
383 return true;
384 };
385
386 wxArrayString symbolNamesInLib;
387 m_libMgr->GetSymbolNames( lib, symbolNamesInLib );
388
389 DIALOG_LIB_NEW_SYMBOL dlg( this, symbolNamesInLib, aInheritFrom, validator );
390
391 dlg.SetMinSize( dlg.GetSize() );
392
393 if( dlg.ShowModal() == wxID_CANCEL )
394 return;
395
397
398 props.name = dlg.GetName();
400 props.reference = dlg.GetReference();
401 props.unitCount = dlg.GetUnitCount();
402 props.pinNameInside = dlg.GetPinNameInside();
404 props.powerSymbol = dlg.GetPowerSymbol();
405 props.showPinNumber = dlg.GetShowPinNumber();
406 props.showPinName = dlg.GetShowPinName();
408 props.includeInBom = dlg.GetIncludeInBom();
409 props.includeOnBoard = dlg.GetIncludeOnBoard();
411 props.keepFootprint = dlg.GetKeepFootprint();
412 props.keepDatasheet = dlg.GetKeepDatasheet();
415
416 m_libMgr->CreateNewSymbol( lib, props );
417 SyncLibraries( false );
418 LoadSymbol( props.name, lib, 1 );
419}
420
421
423{
424 wxString libName;
425
426 if( IsLibraryTreeShown() )
428
429 if( libName.empty() )
430 {
432 }
433 else if( m_libMgr->IsLibraryReadOnly( libName ) )
434 {
435 wxString msg = wxString::Format( _( "Symbol library '%s' is not writable." ),
436 libName );
437 wxString msg2 = _( "You must save to a different location." );
438
439 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) == wxID_OK )
440 saveLibrary( libName, true );
441 }
442 else
443 {
444 saveLibrary( libName, false );
445 }
446
447 if( IsLibraryTreeShown() )
448 m_treePane->GetLibTree()->RefreshLibTree();
449
450 UpdateTitle();
451}
452
453
455{
456 const wxString& libName = GetTargetLibId().GetLibNickname();
457
458 if( !libName.IsEmpty() )
459 {
460 saveLibrary( libName, true );
461 m_treePane->GetLibTree()->RefreshLibTree();
462 }
463}
464
465
467{
468 saveSymbolCopyAs( aOpenCopy );
469
470 m_treePane->GetLibTree()->RefreshLibTree();
471}
472
473
483static std::vector<std::shared_ptr<LIB_SYMBOL>> GetParentChain( const LIB_SYMBOL& aSymbol, bool aIncludeLeaf = true )
484{
485 std::vector<std::shared_ptr<LIB_SYMBOL>> chain;
486 std::shared_ptr<LIB_SYMBOL> sym = aSymbol.SharedPtr();
487
488 if( aIncludeLeaf )
489 chain.push_back( sym );
490
491 while( sym->IsDerived() )
492 {
493 std::shared_ptr<LIB_SYMBOL> parent = sym->GetParent().lock();
494 chain.push_back( parent );
495 sym = parent;
496 }
497
498 return chain;
499}
500
501
511static std::pair<bool, bool> CheckSavingIntoOwnInheritance( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr,
512 LIB_SYMBOL& aSymbol,
513 const wxString& aNewSymbolName,
514 const wxString& aNewLibraryName )
515{
516 const wxString& oldLibraryName = aSymbol.GetLibId().GetLibNickname();
517
518 // Cannot be intersecting if in different libs
519 if( aNewLibraryName != oldLibraryName )
520 return { false, false };
521
522 // Or if the target symbol doesn't exist
523 if( !aLibMgr.SymbolNameInUse( aNewSymbolName, aNewLibraryName ) )
524 return { false, false };
525
526 bool inAncestry = false;
527 bool inDescendents = false;
528
529 {
530 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChainFromUs = GetParentChain( aSymbol, true );
531
532 // Ignore the leaf symbol (0) - that must match
533 for( size_t i = 1; i < parentChainFromUs.size(); ++i )
534 {
535 // Attempting to overwrite a symbol in the parental chain
536 if( parentChainFromUs[i]->GetName() == aNewSymbolName )
537 {
538 inAncestry = true;
539 break;
540 }
541 }
542 }
543
544 {
545 LIB_SYMBOL* targetSymbol = aLibMgr.GetSymbol( aNewSymbolName, aNewLibraryName );
546 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChainFromTarget = GetParentChain( *targetSymbol, true );
547 const wxString oldSymbolName = aSymbol.GetName();
548
549 // Ignore the leaf symbol - it'll match if we're saving the symbol
550 // to the same name, and that would be OK
551 for( size_t i = 1; i < parentChainFromTarget.size(); ++i )
552 {
553 if( parentChainFromTarget[i]->GetName() == oldSymbolName )
554 {
555 inDescendents = true;
556 break;
557 }
558 }
559 }
560
561 return { inAncestry, inDescendents };
562}
563
564
572static std::vector<wxString> CheckForParentalChainConflicts( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr,
573 LIB_SYMBOL& aSymbol,
574 bool aFlattenSymbol,
575 const wxString& newSymbolName,
576 const wxString& newLibraryName )
577{
578 std::vector<wxString> conflicts;
579 const wxString& oldLibraryName = aSymbol.GetLibId().GetLibNickname();
580
581 if( newLibraryName == oldLibraryName || aFlattenSymbol )
582 {
583 // Saving into the same library - the only conflict could be the symbol itself
584 // Different library and flattening - ditto
585 if( aLibMgr.SymbolNameInUse( newSymbolName, newLibraryName ) )
586 conflicts.push_back( newSymbolName );
587 }
588 else
589 {
590 // In a different library with parents - check the whole chain
591 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain = GetParentChain( aSymbol, true );
592
593 for( size_t i = 0; i < parentChain.size(); ++i )
594 {
595 if( i == 0 )
596 {
597 // This is the leaf symbol which the user actually named
598 if( aLibMgr.SymbolNameInUse( newSymbolName, newLibraryName ) )
599 conflicts.push_back( newSymbolName );
600 }
601 else
602 {
603 std::shared_ptr<LIB_SYMBOL> chainSymbol = parentChain[i];
604
605 if( aLibMgr.SymbolNameInUse( chainSymbol->GetName(), newLibraryName ) )
606 conflicts.push_back( chainSymbol->GetName() );
607 }
608 }
609 }
610
611 return conflicts;
612}
613
614
622{
623public:
625 {
626 // Just overwrite any existing symbols in the target library
628 // Add a suffix until we find a name that doesn't conflict
630 // Could have a mode that asks for every one, be then we'll need a fancier
631 // SAVE_SYMBOL_AS_DIALOG subdialog with Overwrite/Rename/Prompt/Cancel
632 // PROMPT
633 };
634
635 SYMBOL_SAVE_AS_HANDLER( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr, CONFLICT_STRATEGY aStrategy, bool aValueFollowsName ) :
636 m_libMgr( aLibMgr ),
637 m_strategy( aStrategy ),
638 m_valueFollowsName( aValueFollowsName )
639 {
640 }
641
642 bool DoSave( LIB_SYMBOL& symbol, const wxString& aNewSymName, const wxString& aNewLibName, bool aFlattenSymbol )
643 {
644 std::unique_ptr<LIB_SYMBOL> flattenedSymbol; // for ownership
645 std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain;
646
647 const bool sameLib = aNewLibName == symbol.GetLibId().GetLibNickname().wx_str();
648
649 if( aFlattenSymbol )
650 {
651 // If we're not copying parent symbols, we need to flatten the symbol
652 // and only save that.
653 flattenedSymbol = symbol.Flatten();
654 wxCHECK( flattenedSymbol, false );
655
656 parentChain.push_back( flattenedSymbol->SharedPtr() );
657 }
658 else if( sameLib )
659 {
660 // If we're saving into the same library, we don't need to check the parental chain
661 // because we can just keep the same parent symbol
662 parentChain.push_back( symbol.SharedPtr() );
663 }
664 else
665 {
666 // Need to copy all parent symbols
667 parentChain = GetParentChain( symbol, true );
668 }
669
670 std::vector<wxString> newNames;
671
672 // Iterate backwards (i.e. from the root down)
673 for( int i = (int) parentChain.size() - 1; i >= 0; --i )
674 {
675 std::shared_ptr<LIB_SYMBOL>& oldSymbol = parentChain[i];
676 LIB_SYMBOL new_symbol( *oldSymbol );
677
678 wxString newName;
679 if( i == 0 )
680 {
681 // This is the leaf symbol which the user actually named
682 newName = aNewSymName;
683 }
684 else
685 {
686 // Somewhere in the inheritance chain, use the conflict resolution strategy
687 newName = oldSymbol->GetName();
688 }
689
690 newName = resolveConflict( newName, aNewLibName );
691 new_symbol.SetName( newName );
692
694 new_symbol.GetValueField().SetText( newName );
695
696 if( i == (int) parentChain.size() - 1 )
697 {
698 // This is the root symbol
699 // Nothing extra to do, it's just a simple symbol with no parents
700 }
701 else
702 {
703 // Get the buffered new copy in the new library (with the name we gave it)
704 LIB_SYMBOL* newParent = m_libMgr.GetSymbol( newNames.back(), aNewLibName );
705
706 // We should have stored this already, why didn't we get it back?
707 wxASSERT( newParent );
708 new_symbol.SetParent( newParent );
709 }
710
711 newNames.push_back( newName );
712 m_libMgr.UpdateSymbol( &new_symbol, aNewLibName );
713 }
714
715 return true;
716 }
717
718private:
719 wxString resolveConflict( const wxString& proposed, const wxString& aNewLibName ) const
720 {
721 switch( m_strategy )
722 {
724 {
725 // In an overwrite strategy, we don't care about conflicts
726 return proposed;
727 }
729 {
730 // In a rename strategy, we need to find a name that doesn't conflict
731 int suffix = 1;
732
733 while( true )
734 {
735 wxString newName = wxString::Format( "%s_%d", proposed, suffix );
736
737 if( !m_libMgr.SymbolNameInUse( newName, aNewLibName ) )
738 return newName;
739
740 ++suffix;
741 }
742 break;
743 }
744 // No default
745 }
746
747 wxFAIL_MSG( "Invalid conflict strategy" );
748 return "";
749 }
750
754};
755
756
763
764
766{
767public:
768 using SymLibNameValidator = std::function<int( const wxString& libName, const wxString& symbolName )>;
769
777
779 PARAMS& aParams,
780 SymLibNameValidator aValidator,
781 const std::vector<wxString>& aParentSymbolNames ) :
782 EDA_LIST_DIALOG( aParent, _( "Save Symbol As" ), false ),
783 m_validator( std::move( aValidator ) ),
784 m_params( aParams )
785 {
786 wxArrayString headers;
787 std::vector<wxArrayString> itemsToDisplay;
788
789 if( aParentSymbolNames.size() )
790 {
791 // This is a little trick to word - when saving to another library, "copy parents" makes sense,
792 // but when in the same library, the parents will be untouched in any case.
793 const wxString aParentNames = AccumulateDescriptions( aParentSymbolNames );
794 AddExtraCheckbox(
795 wxString::Format( "Flatten/remove symbol inheritance (current parent symbols: %s)", aParentNames ),
796 &m_params.m_FlattenSymbol );
797 }
798
799 aParent->GetLibraryItemsForListDialog( headers, itemsToDisplay );
800 initDialog( headers, itemsToDisplay, m_params.m_LibraryName );
801
802 SetListLabel( _( "Save in library:" ) );
803 SetOKLabel( _( "Save" ) );
804
805 wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
806
807 wxStaticText* label = new wxStaticText( this, wxID_ANY, _( "Name:" ) );
808 bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
809
810 m_symbolNameCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString );
811 bNameSizer->Add( m_symbolNameCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
812
813 wxButton* newLibraryButton = new wxButton( this, ID_MAKE_NEW_LIBRARY, _( "New Library..." ) );
814 m_ButtonsSizer->Prepend( 80, 20 );
815 m_ButtonsSizer->Prepend( newLibraryButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 );
816
817 GetSizer()->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
818
819 Bind( wxEVT_BUTTON,
820 [this]( wxCommandEvent& )
821 {
822 EndModal( ID_MAKE_NEW_LIBRARY );
824
825 // Move nameTextCtrl to the head of the tab-order
826 if( GetChildren().DeleteObject( m_symbolNameCtrl ) )
827 GetChildren().Insert( m_symbolNameCtrl );
828
830
832
833 Layout();
834 GetSizer()->Fit( this );
835
836 Centre();
837 }
838
839protected:
840 wxString getSymbolName() const
841 {
842 wxString symbolName = m_symbolNameCtrl->GetValue();
843 symbolName.Trim( true );
844 symbolName.Trim( false );
845 symbolName.Replace( " ", "_" );
846 return EscapeString( symbolName, CTX_LIBID );
847 }
848
849 bool TransferDataToWindow() override
850 {
851 m_symbolNameCtrl->SetValue( UnescapeString( m_params.m_SymbolName ) );
852 return true;
853 }
854
856 {
857 // This updates m_params.m_FlattenSymbol
858 // Do this now, so the validator can use it
860
861 m_params.m_SymbolName = getSymbolName();
862 m_params.m_LibraryName = GetTextSelection();
863
864 int ret = m_validator( m_params.m_LibraryName, m_params.m_SymbolName );
865
866 if( ret == wxID_CANCEL )
867 return false;
868
869 if( ret == ID_OVERWRITE_CONFLICTS )
871 else if( ret == ID_RENAME_CONFLICTS )
873
874 return true;
875 }
876
877private:
878 wxTextCtrl* m_symbolNameCtrl;
881};
882
883
885{
886 LIB_SYMBOL* symbol = getTargetSymbol();
887
888 if( !symbol )
889 return;
890
891 LIB_ID old_lib_id = symbol->GetLibId();
892 wxString symbolName = old_lib_id.GetLibItemName();
893 wxString libraryName = old_lib_id.GetLibNickname();
894 bool valueFollowsName = symbol->GetValueField().GetText() == symbolName;
895 wxString msg;
896 bool done = false;
897 bool flattenSymbol = false;
898
899 // This is the function that will be called when the user clicks OK in the dialog and checks
900 // if the proposed name has problems, and asks for clarification.
901 const auto dialogValidatorFunc =
902 [&]( const wxString& newLib, const wxString& newName ) -> int
903 {
904 if( newLib.IsEmpty() )
905 {
906 wxMessageBox( _( "A library must be specified." ) );
907 return wxID_CANCEL;
908 }
909
910 if( newName.IsEmpty() )
911 {
912 wxMessageBox( _( "Symbol must have a name." ) );
913 return wxID_CANCEL;
914 }
915
916 if( m_libMgr->IsLibraryReadOnly( newLib ) )
917 {
918 msg = wxString::Format( _( "Library '%s' is read-only. Choose a "
919 "different library to save the symbol '%s' to." ),
920 newLib,
921 UnescapeString( newName ) );
922 wxMessageBox( msg );
923 return wxID_CANCEL;
924 }
925
930 const auto& [inAncestry, inDescendents] = CheckSavingIntoOwnInheritance( *m_libMgr, *symbol,
931 newName, newLib );
932
933 if( inAncestry )
934 {
935 msg = wxString::Format( _( "Symbol '%s' cannot replace another symbol '%s' "
936 "that it descends from" ),
937 symbolName,
938 UnescapeString( newName ) );
939 wxMessageBox( msg );
940 return wxID_CANCEL;
941 }
942
943 if( inDescendents )
944 {
945 msg = wxString::Format( _( "Symbol '%s' cannot replace another symbol '%s' "
946 "that is a descendent of it." ),
947 symbolName,
948 UnescapeString( newName ) );
949 wxMessageBox( msg );
950 return wxID_CANCEL;
951 }
952
953 const std::vector<wxString> conflicts =
954 CheckForParentalChainConflicts( *m_libMgr, *symbol, flattenSymbol, newName, newLib );
955
956 if( conflicts.size() == 1 && conflicts.front() == newName )
957 {
958 // The simplest case is when the symbol itself has a conflict
959 msg = wxString::Format( _( "Symbol '%s' already exists in library '%s'. "
960 "Do you want to overwrite it?" ),
961 UnescapeString( newName ),
962 newLib );
963
964 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
965 errorDlg.SetOKLabel( _( "Overwrite" ) );
966
967 return errorDlg.ShowModal() == wxID_OK ? ID_OVERWRITE_CONFLICTS : (int) wxID_CANCEL;
968 }
969 else if( !conflicts.empty() )
970 {
971 // If there are conflicts in the parental chain, we need to ask the user
972 // if they want to overwrite all of them.
973 // A more complex UI might allow the user to re-parent the symbol to an
974 // existing symbol in the target lib, or rename all the parents somehow.
975 msg = wxString::Format( _( "The following symbols in the inheritance chain of "
976 "'%s' already exist in library '%s':\n" ),
977 UnescapeString( symbolName ),
978 newLib );
979
980 for( const wxString& conflict : conflicts )
981 msg += wxString::Format( " %s\n", conflict );
982
983 msg += _( "\nDo you want to overwrite all of them, or rename the new symbols?" );
984
985 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
986 errorDlg.SetYesNoCancelLabels( _( "Overwrite All" ), _( "Rename All" ), _( "Cancel" ) );
987
988 switch( errorDlg.ShowModal() )
989 {
990 case wxID_YES: return ID_OVERWRITE_CONFLICTS;
991 case wxID_NO: return ID_RENAME_CONFLICTS;
992 default: return wxID_CANCEL;
993 }
994 }
995
996 return wxID_OK;
997 };
998
1000
1001 std::vector<wxString> parentSymbolNames;
1002 if( symbol->IsDerived() )
1003 {
1004 // The parents are everything but the leaf symbol
1005 std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain = GetParentChain( *symbol, false );
1006
1007 for( const auto& parent : parentChain )
1008 parentSymbolNames.push_back( parent->GetName() );
1009 }
1010
1012 symbolName,
1013 libraryName,
1014 flattenSymbol,
1015 strategy,
1016 };
1017
1018 // Keep asking the user for a new name until they give a valid one or cancel the operation
1019 while( !done )
1020 {
1021 SAVE_SYMBOL_AS_DIALOG dlg( this, params, dialogValidatorFunc, parentSymbolNames );
1022
1023 int ret = dlg.ShowModal();
1024
1025 switch( ret )
1026 {
1027 case wxID_CANCEL:
1028 return;
1029
1030 case wxID_OK: // No conflicts
1033 {
1034 done = true;
1035 break;
1036 }
1038 {
1039 wxFileName newLibrary( AddLibraryFile( true ) );
1040 params.m_LibraryName = newLibrary.GetName();
1041
1042 // Go round again to ask for the symbol name
1043 break;
1044 }
1045
1046 default:
1047 break;
1048 }
1049 }
1050
1051 SYMBOL_SAVE_AS_HANDLER saver( *m_libMgr, params.m_ConflictStrategy, valueFollowsName );
1052
1053 saver.DoSave( *symbol, params.m_SymbolName, params.m_LibraryName, params.m_FlattenSymbol );
1054
1055 SyncLibraries( false );
1056
1057 if( aOpenCopy )
1058 LoadSymbol( params.m_SymbolName, params.m_LibraryName, 1 );
1059}
1060
1061
1063{
1064 wxString msg;
1065 LIB_SYMBOL* symbol = getTargetSymbol();
1066
1067 if( !symbol )
1068 {
1069 ShowInfoBarError( _( "There is no symbol selected to save." ) );
1070 return;
1071 }
1072
1073 wxFileName fn;
1074
1075 fn.SetName( symbol->GetName().Lower() );
1077
1078 wxFileDialog dlg( this, _( "Export Symbol" ), m_mruPath, fn.GetFullName(),
1080
1081 if( dlg.ShowModal() == wxID_CANCEL )
1082 return;
1083
1085
1086 fn = dlg.GetPath();
1087 fn.MakeAbsolute();
1088
1089 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
1090
1091 wxString libraryName;
1092 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = symbol->Flatten();
1093
1094 for( const wxString& candidate : m_libMgr->GetLibraryNames() )
1095 {
1096 if( auto uri = manager.GetFullURI( LIBRARY_TABLE_TYPE::SYMBOL, candidate, true ); uri )
1097 {
1098 if( *uri == fn.GetFullPath() )
1099 libraryName = candidate;
1100 }
1101 }
1102
1103 if( !libraryName.IsEmpty() )
1104 {
1105 SYMBOL_SAVE_AS_HANDLER saver( *m_libMgr, strategy, false );
1106
1107 if( m_libMgr->IsLibraryReadOnly( libraryName ) )
1108 {
1109 msg = wxString::Format( _( "Library '%s' is read-only." ), libraryName );
1110 DisplayError( this, msg );
1111 return;
1112 }
1113
1114 if( m_libMgr->SymbolNameInUse( symbol->GetName(), libraryName ) )
1115 {
1116 msg = wxString::Format( _( "Symbol '%s' already exists in library '%s'." ),
1117 symbol->GetName(), libraryName );
1118
1119 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1120 errorDlg.SetOKLabel( _( "Overwrite" ) );
1121 errorDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1122
1123 if( errorDlg.ShowModal() == wxID_CANCEL )
1124 return;
1125 }
1126
1127 saver.DoSave( *flattenedSymbol, symbol->GetName(), libraryName, false );
1128
1129 SyncLibraries( false );
1130 return;
1131 }
1132
1133 LIB_SYMBOL* old_symbol = nullptr;
1134 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() );
1135
1136 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1137 pluginType = SCH_IO_MGR::SCH_KICAD;
1138
1139 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pluginType ) );
1140
1141 if( fn.FileExists() )
1142 {
1143 try
1144 {
1145 old_symbol = pi->LoadSymbol( fn.GetFullPath(), symbol->GetName() );
1146 }
1147 catch( const IO_ERROR& ioe )
1148 {
1149 msg.Printf( _( "Error occurred attempting to load symbol library file '%s'." ),
1150 fn.GetFullPath() );
1151 DisplayErrorMessage( this, msg, ioe.What() );
1152 return;
1153 }
1154
1155 if( old_symbol )
1156 {
1157 msg.Printf( _( "Symbol %s already exists in library '%s'." ),
1158 UnescapeString( symbol->GetName() ),
1159 fn.GetFullName() );
1160
1161 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1162 errorDlg.SetOKLabel( _( "Overwrite" ) );
1163 errorDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1164
1165 if( errorDlg.ShowModal() == wxID_CANCEL )
1166 return;
1167 }
1168 }
1169
1170 if( !fn.IsDirWritable() )
1171 {
1172 msg.Printf( _( "Insufficient permissions to save library '%s'." ), fn.GetFullPath() );
1173 DisplayError( this, msg );
1174 return;
1175 }
1176
1177 try
1178 {
1179 if( !fn.FileExists() )
1180 pi->CreateLibrary( fn.GetFullPath() );
1181
1182 // The flattened symbol is most likely what the user would want. As some point in
1183 // the future as more of the symbol library inheritance is implemented, this may have
1184 // to be changes to save symbols of inherited symbols.
1185 pi->SaveSymbol( fn.GetFullPath(), flattenedSymbol.release() );
1186 }
1187 catch( const IO_ERROR& ioe )
1188 {
1189 msg.Printf( _( "Failed to create symbol library file '%s'." ), fn.GetFullPath() );
1190 DisplayErrorMessage( this, msg, ioe.What() );
1191 msg.Printf( _( "Error creating symbol library '%s'." ), fn.GetFullName() );
1192 SetStatusText( msg );
1193 return;
1194 }
1195
1196 m_mruPath = fn.GetPath();
1197
1198 msg.Printf( _( "Symbol %s saved to library '%s'." ),
1199 UnescapeString( symbol->GetName() ),
1200 fn.GetFullPath() );
1201 SetStatusText( msg );
1202}
1203
1204
1206{
1207 wxCHECK( m_symbol, /* void */ );
1208
1209 wxString lib = GetCurLib();
1210
1211 if( !lib.IsEmpty() && aOldName && *aOldName != m_symbol->GetName() )
1212 {
1213 // Test the current library for name conflicts
1214 if( m_libMgr->SymbolNameInUse( m_symbol->GetName(), lib ) )
1215 {
1216 wxString msg = wxString::Format( _( "Symbol name '%s' already in use." ),
1217 UnescapeString( m_symbol->GetName() ) );
1218
1219 DisplayErrorMessage( this, msg );
1220 m_symbol->SetName( *aOldName );
1221 }
1222 else
1223 {
1224 m_libMgr->UpdateSymbolAfterRename( m_symbol, *aOldName, lib );
1225 }
1226
1227 // Reselect the renamed symbol
1228 m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, m_symbol->GetName() ) );
1229 }
1230
1232 UpdateTitle();
1233
1234 // N.B. The view needs to be rebuilt first as the Symbol Properties change may invalidate
1235 // the view pointers by rebuilting the field table
1236 RebuildView();
1238
1239 OnModify();
1240}
1241
1242
1244{
1245 std::vector<LIB_ID> toDelete = GetSelectedLibIds();
1246
1247 if( toDelete.empty() )
1248 toDelete.emplace_back( GetTargetLibId() );
1249
1250 for( LIB_ID& libId : toDelete )
1251 {
1252 if( m_libMgr->IsSymbolModified( libId.GetLibItemName(), libId.GetLibNickname() )
1253 && !IsOK( this, wxString::Format( _( "The symbol '%s' has been modified.\n"
1254 "Do you want to remove it from the library?" ),
1255 libId.GetUniStringLibItemName() ) ) )
1256 {
1257 continue;
1258 }
1259
1260 wxArrayString derived;
1261
1262 if( m_libMgr->GetDerivedSymbolNames( libId.GetLibItemName(), libId.GetLibNickname(), derived ) > 0 )
1263 {
1264 wxString msg = _( "Deleting a base symbol will delete all symbols derived from it.\n\n" );
1265
1266 msg += libId.GetLibItemName().wx_str() + _( " (base)\n" );
1267
1268 for( const wxString& name : derived )
1269 msg += name + wxT( "\n" );
1270
1271 KICAD_MESSAGE_DIALOG_BASE dlg( this, msg, _( "Warning" ), wxYES_NO | wxICON_WARNING | wxCENTER );
1272 dlg.SetExtendedMessage( wxT( " " ) );
1273 dlg.SetYesNoLabels( _( "Delete All Listed Symbols" ), _( "Cancel" ) );
1274
1275 if( dlg.ShowModal() == wxID_NO )
1276 continue;
1277 }
1278
1279 if( GetCurSymbol() )
1280 {
1281 for( const std::shared_ptr<LIB_SYMBOL>& symbol : GetParentChain( *GetCurSymbol() ) )
1282 {
1283 if( symbol->GetLibId() == libId )
1284 {
1285 emptyScreen();
1286 break;
1287 }
1288 }
1289 }
1290
1291 m_libMgr->RemoveSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1292 }
1293
1294 m_treePane->GetLibTree()->RefreshLibTree();
1295}
1296
1297
1299{
1300 std::vector<LIB_ID> symbols;
1301
1302 if( GetTreeLIBIDs( symbols ) == 0 )
1303 return;
1304
1305 STRING_FORMATTER formatter;
1306
1307 for( LIB_ID& libId : symbols )
1308 {
1309 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(),
1310 libId.GetLibNickname() );
1311
1312 if( !symbol )
1313 continue;
1314
1315 std::unique_ptr<LIB_SYMBOL> tmp = symbol->Flatten();
1316 SCH_IO_KICAD_SEXPR::FormatLibSymbol( tmp.get(), formatter );
1317 }
1318
1319 std::string prettyData = formatter.GetString();
1320 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES );
1321
1322 wxLogNull doNotLog; // disable logging of failed clipboard actions
1323
1324 auto clipboard = wxTheClipboard;
1325 wxClipboardLocker clipboardLock( clipboard );
1326
1327 if( !clipboardLock || !clipboard->IsOpened() )
1328 return;
1329
1330 auto data = new wxTextDataObject( wxString( prettyData.c_str(), wxConvUTF8 ) );
1331 clipboard->SetData( data );
1332
1333 clipboard->Flush();
1334}
1335
1336
1337void SYMBOL_EDIT_FRAME::DuplicateSymbol( bool aFromClipboard )
1338{
1339 LIB_ID libId = GetTargetLibId();
1340 wxString lib = libId.GetLibNickname();
1341
1342 if( !m_libMgr->LibraryExists( lib ) )
1343 return;
1344
1345 std::vector<LIB_SYMBOL*> newSymbols;
1346
1347 if( aFromClipboard )
1348 {
1349 std::string clipboardData = GetClipboardUTF8();
1350
1351 try
1352 {
1353 newSymbols = SCH_IO_KICAD_SEXPR::ParseLibSymbols( clipboardData, "Clipboard" );
1354 }
1355 catch( IO_ERROR& e )
1356 {
1357 wxLogMessage( wxS( "Can not paste: %s" ), e.Problem() );
1358 }
1359 }
1360 else if( LIB_SYMBOL* srcSymbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(), lib ) )
1361 {
1362 newSymbols.emplace_back( new LIB_SYMBOL( *srcSymbol ) );
1363
1364 // Derive from same parent.
1365 if( srcSymbol->IsDerived() )
1366 {
1367 if( std::shared_ptr<LIB_SYMBOL> srcParent = srcSymbol->GetParent().lock() )
1368 newSymbols.back()->SetParent( srcParent.get() );
1369 }
1370 }
1371
1372 if( newSymbols.empty() )
1373 return;
1374
1375 for( LIB_SYMBOL* symbol : newSymbols )
1376 {
1377 ensureUniqueName( symbol, lib );
1378 m_libMgr->UpdateSymbol( symbol, lib );
1379
1380 LoadOneLibrarySymbolAux( symbol, lib, GetUnit(), GetBodyStyle() );
1381 }
1382
1383 SyncLibraries( false );
1384 m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newSymbols[0]->GetName() ) );
1385
1386 for( LIB_SYMBOL* symbol : newSymbols )
1387 delete symbol;
1388}
1389
1390
1391void SYMBOL_EDIT_FRAME::ensureUniqueName( LIB_SYMBOL* aSymbol, const wxString& aLibrary )
1392{
1393 if( aSymbol )
1394 {
1395 int i = 1;
1396 wxString newName = aSymbol->GetName();
1397
1398 // Append a number to the name until the name is unique in the library.
1399 while( m_libMgr->SymbolNameInUse( newName, aLibrary ) )
1400 newName.Printf( "%s_%d", aSymbol->GetName(), i++ );
1401
1402 aSymbol->SetName( newName );
1403 }
1404}
1405
1406
1407void SYMBOL_EDIT_FRAME::Revert( bool aConfirm )
1408{
1409 LIB_ID libId = GetTargetLibId();
1410 const wxString& libName = libId.GetLibNickname();
1411
1412 // Empty if this is the library itself that is selected.
1413 const wxString& symbolName = libId.GetLibItemName();
1414
1415 wxString msg = wxString::Format( _( "Revert '%s' to last version saved?" ),
1416 symbolName.IsEmpty() ? libName : symbolName );
1417
1418 if( aConfirm && !ConfirmRevertDialog( this, msg ) )
1419 return;
1420
1421 bool reload_currentSymbol = false;
1422 wxString curr_symbolName = symbolName;
1423
1424 if( GetCurSymbol() )
1425 {
1426 // the library itself is reverted: the current symbol will be reloaded only if it is
1427 // owned by this library
1428 if( symbolName.IsEmpty() )
1429 {
1430 LIB_ID curr_libId = GetCurSymbol()->GetLibId();
1431 reload_currentSymbol = libName == curr_libId.GetLibNickname().wx_str();
1432
1433 if( reload_currentSymbol )
1434 curr_symbolName = curr_libId.GetUniStringLibItemName();
1435 }
1436 else
1437 {
1438 reload_currentSymbol = IsCurrentSymbol( libId );
1439 }
1440 }
1441
1442 int unit = m_unit;
1443
1444 if( reload_currentSymbol )
1445 emptyScreen();
1446
1447 if( symbolName.IsEmpty() )
1448 {
1449 m_libMgr->RevertLibrary( libName );
1450 }
1451 else
1452 {
1453 libId = m_libMgr->RevertSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1454
1455 m_treePane->GetLibTree()->SelectLibId( libId );
1456 m_libMgr->ClearSymbolModified( libId.GetLibItemName(), libId.GetLibNickname() );
1457 }
1458
1459 if( reload_currentSymbol && m_libMgr->SymbolExists( curr_symbolName, libName ) )
1460 LoadSymbol( curr_symbolName, libName, unit );
1461
1462 m_treePane->Refresh();
1463}
1464
1465
1467{
1468 wxCHECK_RET( m_libMgr, "Library manager object not created." );
1469
1470 Revert( false );
1471 m_libMgr->RevertAll();
1472}
1473
1474
1475void SYMBOL_EDIT_FRAME::LoadSymbol( const wxString& aAlias, const wxString& aLibrary, int aUnit )
1476{
1478 {
1479 if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
1480 [&]() -> bool
1481 {
1482 return saveCurrentSymbol();
1483 } ) )
1484 {
1485 return;
1486 }
1487 }
1488
1489 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( aAlias, aLibrary );
1490
1491 if( !symbol )
1492 {
1493 DisplayError( this, wxString::Format( _( "Symbol %s not found in library '%s'." ),
1494 aAlias,
1495 aLibrary ) );
1496 m_treePane->GetLibTree()->RefreshLibTree();
1497 return;
1498 }
1499
1500 // Optimize default edit options for this symbol
1501 // Usually if units are locked, graphic items are specific to each unit
1502 // and if units are interchangeable, graphic items are common to units
1504 tools->SetDrawSpecificUnit( symbol->UnitsLocked() );
1505
1506 LoadOneLibrarySymbolAux( symbol, aLibrary, aUnit, 0 );
1507}
1508
1509
1510bool SYMBOL_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile )
1511{
1512 wxFileName fn;
1513 wxString msg;
1515 SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::SCH_FILE_T::SCH_KICAD;
1516 PROJECT& prj = Prj();
1517
1519
1521
1522 if( !aNewFile && ( aLibrary.empty() || !adapter->HasLibrary( aLibrary ) ) )
1523 {
1524 ShowInfoBarError( _( "No library specified." ) );
1525 return false;
1526 }
1527
1528 if( aNewFile )
1529 {
1530 SEARCH_STACK* search = PROJECT_SCH::SchSearchS( &prj );
1531
1532 // Get a new name for the library
1533 wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
1534
1535 if( !default_path )
1536 default_path = search->LastVisitedPath();
1537
1538 fn.SetName( aLibrary );
1540
1541 wxString wildcards = FILEEXT::KiCadSymbolLibFileWildcard();
1542
1543 wxFileDialog dlg( this, wxString::Format( _( "Save Library '%s' As..." ), aLibrary ), default_path,
1544 fn.GetFullName(), wildcards, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1545
1546 SYMBOL_LIBRARY_SAVE_AS_FILEDLG_HOOK saveAsHook( type );
1547 dlg.SetCustomizeHook( saveAsHook );
1548
1549 if( dlg.ShowModal() == wxID_CANCEL )
1550 return false;
1551
1552 fn = dlg.GetPath();
1553
1554 prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() );
1555
1556 if( fn.GetExt().IsEmpty() )
1558
1559 type = saveAsHook.GetOption();
1560 }
1561 else
1562 {
1563 std::optional<LIBRARY_TABLE_ROW*> optRow = adapter->GetRow( aLibrary );
1564 wxCHECK( optRow, false );
1565
1566 fn = LIBRARY_MANAGER::GetFullURI( *optRow, true );
1568
1569 if( fileType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1570 fileType = SCH_IO_MGR::SCH_KICAD;
1571 }
1572
1573 // Verify the user has write privileges before attempting to save the library file.
1574 if( !aNewFile && m_libMgr->IsLibraryReadOnly( aLibrary ) )
1575 return false;
1576
1577 ClearMsgPanel();
1578
1579 // Copy .kicad_symb file to .bak.
1580 if( !backupFile( fn, "bak" ) )
1581 return false;
1582
1583 if( !m_libMgr->SaveLibrary( aLibrary, fn.GetFullPath(), fileType ) )
1584 {
1585 msg.Printf( _( "Failed to save changes to symbol library file '%s'." ),
1586 fn.GetFullPath() );
1587 DisplayErrorMessage( this, _( "Error Saving Library" ), msg );
1588 return false;
1589 }
1590
1591 if( !aNewFile )
1592 {
1593 m_libMgr->ClearLibraryModified( aLibrary );
1594
1595 // Update the library modification time so that we don't reload based on the watcher
1596 if( aLibrary == getTargetLib() )
1597 SetSymModificationTime( fn.GetModificationTime() );
1598 }
1599 else
1600 {
1601 bool resyncLibTree = false;
1602 wxString originalLibNickname = getTargetLib();
1603 wxString forceRefresh;
1604
1605 switch( type )
1606 {
1608 resyncLibTree = replaceLibTableEntry( originalLibNickname, fn.GetFullPath() );
1609 forceRefresh = originalLibNickname;
1610 break;
1611
1613 resyncLibTree = addLibTableEntry( fn.GetFullPath() );
1614 break;
1615
1617 resyncLibTree = addLibTableEntry( fn.GetFullPath(), LIBRARY_TABLE_SCOPE::PROJECT );
1618 break;
1619
1620 default:
1621 break;
1622 }
1623
1624 if( resyncLibTree )
1625 {
1627 SyncLibraries( true, false, forceRefresh );
1629 }
1630 }
1631
1632 ClearMsgPanel();
1633 msg.Printf( _( "Symbol library file '%s' saved." ), fn.GetFullPath() );
1635
1636 return true;
1637}
1638
1639
1640bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
1641{
1642 wxString msg, msg2;
1643 bool doSave = true;
1644 int dirtyCount = 0;
1645 bool applyToAll = false;
1646 bool retv = true;
1647
1648 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1649 {
1650 if( m_libMgr->IsLibraryModified( libNickname ) )
1651 dirtyCount++;
1652 }
1653
1654 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1655 {
1656 if( m_libMgr->IsLibraryModified( libNickname ) )
1657 {
1658 if( aRequireConfirmation && !applyToAll )
1659 {
1660 msg.Printf( _( "Save changes to '%s' before closing?" ), libNickname );
1661
1662 switch( UnsavedChangesDialog( this, msg, dirtyCount > 1 ? &applyToAll : nullptr ) )
1663 {
1664 case wxID_YES: doSave = true; break;
1665 case wxID_NO: doSave = false; break;
1666 default:
1667 case wxID_CANCEL: return false;
1668 }
1669 }
1670
1671 if( doSave )
1672 {
1673 // If saving under existing name fails then do a Save As..., and if that
1674 // fails then cancel close action.
1675 if( m_libMgr->IsLibraryReadOnly( libNickname ) )
1676 {
1677 msg.Printf( _( "Symbol library '%s' is not writable." ), libNickname );
1678 msg2 = _( "You must save to a different location." );
1679
1680 if( dirtyCount == 1 )
1681 {
1682 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) != wxID_OK )
1683 {
1684 retv = false;
1685 continue;
1686 }
1687 }
1688 else
1689 {
1690 m_infoBar->Dismiss();
1691 m_infoBar->ShowMessageFor( msg + wxS( " " ) + msg2,
1692 2000, wxICON_EXCLAMATION );
1693
1694 while( m_infoBar->IsShownOnScreen() )
1695 wxSafeYield();
1696
1697 retv = false;
1698 continue;
1699 }
1700 }
1701 else if( saveLibrary( libNickname, false ) )
1702 {
1703 continue;
1704 }
1705
1706 if( !saveLibrary( libNickname, true ) )
1707 retv = false;
1708 }
1709 }
1710 }
1711
1712 UpdateTitle();
1713 return retv;
1714}
1715
1716
1718{
1720
1721 if( !m_symbol )
1722 return;
1723
1724 wxString msg = m_symbol->GetName();
1725
1726 AppendMsgPanel( _( "Name" ), UnescapeString( msg ), 8 );
1727
1728 if( m_symbol->IsDerived() )
1729 {
1730 std::shared_ptr<LIB_SYMBOL> parent = m_symbol->GetParent().lock();
1731
1732 msg = parent ? parent->GetName() : _( "Undefined!" );
1733 AppendMsgPanel( _( "Parent" ), UnescapeString( msg ), 8 );
1734 }
1735
1736 if( m_symbol->IsGlobalPower() )
1737 msg = _( "Power Symbol" );
1738 else if( m_symbol->IsLocalPower() )
1739 msg = _( "Power Symbol (Local)" );
1740 else
1741 msg = _( "Symbol" );
1742
1743 AppendMsgPanel( _( "Type" ), msg, 8 );
1744 AppendMsgPanel( _( "Description" ), m_symbol->GetDescription(), 8 );
1745 AppendMsgPanel( _( "Keywords" ), m_symbol->GetKeyWords() );
1746 AppendMsgPanel( _( "Datasheet" ), m_symbol->GetDatasheetField().GetText() );
1747}
const char * name
static TOOL_ACTION cancelInteractive
Definition actions.h:72
static TOOL_ACTION zoomFitScreen
Definition actions.h:141
void SetContentModified(bool aModified=true)
Definition base_screen.h:59
wxString GetParentSymbolName() const
wxString GetName() const override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:82
void SetupStandardButtons(std::map< int, wxString > aLabels={})
int ShowModal() override
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
WX_INFOBAR * m_infoBar
virtual void RecreateToolbars()
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
void ReCreateMenuBar()
Recreate the menu bar.
WX_INFOBAR * GetInfoBar()
virtual void ClearMsgPanel()
Clear all messages from the message panel.
void AppendMsgPanel(const wxString &aTextUpper, const wxString &aTextLower, int aPadding=6)
Append a message to the message panel.
void SetOKLabel(const wxString &aLabel)
void initDialog(const wxArrayString &aItemHeaders, const std::vector< wxArrayString > &aItemList, const wxString &aPreselectText)
wxString GetTextSelection(int aColumn=0)
Return the selected text from aColumn in the wxListCtrl in the dialog.
void SetListLabel(const wxString &aLabel)
void GetExtraCheckboxValues()
Fills in the value pointers from the checkboxes after the dialog has run.
EDA_LIST_DIALOG(wxWindow *aParent, const wxString &aTitle, const wxArrayString &aItemHeaders, const std::vector< wxArrayString > &aItemList, const wxString &aPreselectText=wxEmptyString, bool aSortList=true)
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
virtual const wxString Problem() const
what was the problem?
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:42
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:55
int ShowModal() override
Definition kidialog.cpp:93
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition view.cpp:1561
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:403
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
std::optional< LIBRARY_TABLE_ROW * > GetRow(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
const wxString & Type() const
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:172
wxString GetUniStringLibId() const
Definition lib_id.h:148
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:112
const wxString GetUniStringLibNickname() const
Definition lib_id.h:88
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
Symbol library management helper that is specific to the symbol library editor frame.
Define a library symbol object.
Definition lib_symbol.h:85
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:155
bool UnitsLocked() const
Check whether symbol units are interchangeable.
Definition lib_symbol.h:291
bool IsDerived() const
Definition lib_symbol.h:206
LIB_ID GetSourceLibId() const
Definition lib_symbol.h:158
void SetParent(LIB_SYMBOL *aParent=nullptr)
wxString GetName() const override
Definition lib_symbol.h:148
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:336
std::shared_ptr< LIB_SYMBOL > SharedPtr() const
http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/sp_techniques.html#weak_without_shared.
Definition lib_symbol.h:95
bool IsMultiUnit() const override
Definition lib_symbol.h:746
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
virtual void SetName(const wxString &aName)
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:130
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
static SEARCH_STACK * SchSearchS(PROJECT *aProject)
Accessor for Eeschema search stack.
Container for project specific data.
Definition project.h:66
@ SCH_LIB_PATH
Definition project.h:221
virtual void SetRString(RSTRING_T aStringId, const wxString &aString)
Store a "retained string", which is any session and project specific string identified in enum RSTRIN...
Definition project.cpp:337
virtual const wxString & GetRString(RSTRING_T aStringId)
Return a "retained string", which is any session and project specific string identified in enum RSTRI...
Definition project.cpp:348
bool TransferDataFromWindow() override
std::function< int(const wxString &libName, const wxString &symbolName)> SymLibNameValidator
bool TransferDataToWindow() override
SymLibNameValidator m_validator
SAVE_SYMBOL_AS_DIALOG(SYMBOL_EDIT_FRAME *aParent, PARAMS &aParams, SymLibNameValidator aValidator, const std::vector< wxString > &aParentSymbolNames)
wxString getSymbolName() const
wxTextCtrl * m_symbolNameCtrl
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void GetLibraryItemsForListDialog(wxArrayString &aHeaders, std::vector< wxArrayString > &aItemsToDisplay)
wxString SelectLibrary(const wxString &aDialogTitle, const wxString &aListLabel, const std::vector< std::pair< wxString, bool * > > &aExtraCheckboxes={})
Display a list of loaded libraries and allows the user to select a library.
void SetSymModificationTime(const wxDateTime &aTime)
Set the modification time of the symbol library table file.
void setSymWatcher(const LIB_ID *aSymbol)
Creates (or removes) a watcher on the specified symbol library.
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
Schematic editor (Eeschema) main window.
void SaveSymbolToSchematic(const LIB_SYMBOL &aSymbol, const KIID &aSchematicSymbolUUID)
Update a schematic symbol from a LIB_SYMBOL.
void SetText(const wxString &aText) override
static void FormatLibSymbol(LIB_SYMBOL *aPart, OUTPUTFORMATTER &aFormatter)
static std::vector< LIB_SYMBOL * > ParseLibSymbols(std::string &aSymbolText, std::string aSource, int aFileVersion=SEXPR_SCHEMATIC_FILE_VERSION)
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the #SCH_FILE_T from the corresponding plugin type name: "kicad", "legacy",...
static SCH_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
Return a plugin type given a symbol library using the file extension of aLibPath.
Look for files in a number of paths.
const wxString LastVisitedPath(const wxString &aSubPathToSearch=wxEmptyString)
A quirky function inherited from old code that seems to serve particular needs in the UI.
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:450
const std::string & GetString()
Definition richio.h:473
The symbol library editor main window.
void ClearMsgPanel() override
Clear all messages from the message panel.
void UpdateAfterSymbolProperties(wxString *aOldName=nullptr)
void SaveAll()
Save all modified symbols and libraries.
bool IsLibraryTreeShown() const override
wxString getTargetLib() const
bool IsCurrentSymbol(const LIB_ID &aLibId) const
Restore the empty editor screen, without any symbol or library selected.
bool backupFile(const wxFileName &aOriginalFile, const wxString &aBackupExt)
Return currently edited symbol.
void RebuildSymbolUnitAndBodyStyleLists()
int GetTreeLIBIDs(std::vector< LIB_ID > &aSelection) const
LIB_ID GetTreeLIBID(int *aUnit=nullptr) const
Return the LIB_ID of the library or symbol selected in the symbol tree.
LIB_SYMBOL_LIBRARY_MANAGER * m_libMgr
wxString GetCurLib() const
The nickname of the current library being edited and empty string if none.
void Save()
Save the selected symbol or library.
void LoadSymbol(const wxString &aLibrary, const wxString &aSymbol, int Unit)
bool m_SyncPinEdit
Set to true to synchronize pins at the same position when editing symbols with multiple units or mult...
bool addLibTableEntry(const wxString &aLibFile, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::GLOBAL)
Add aLibFile to the symbol library table defined by aScope.
void Revert(bool aConfirm=true)
Revert unsaved changes in a symbol, restoring to the last saved state.
void centerItemIdleHandler(wxIdleEvent &aEvent)
bool replaceLibTableEntry(const wxString &aLibNickname, const wxString &aLibFile)
Replace the file path of the symbol library table entry aLibNickname with aLibFile.
bool IsSymbolFromSchematic() const
void SetScreen(BASE_SCREEN *aScreen) override
void DuplicateSymbol(bool aFromClipboard)
Insert a duplicate symbol.
SCH_SCREEN * m_dummyScreen
< Helper screen used when no symbol is loaded
void saveSymbolCopyAs(bool aOpenCopy)
void SetCurSymbol(LIB_SYMBOL *aSymbol, bool aUpdateZoom)
Take ownership of aSymbol and notes that it is the one currently being edited.
KIID m_schematicSymbolUUID
RefDes of the symbol (only valid if symbol was loaded from schematic)
std::vector< LIB_ID > GetSelectedLibIds() const
void SyncLibraries(bool aShowProgress, bool aPreloadCancelled=false, const wxString &aForceRefresh=wxEmptyString)
Synchronize the library manager to the symbol library table, and then the symbol tree to the library ...
LIB_SYMBOL * GetCurSymbol() const
Return the current symbol being edited or NULL if none selected.
void UpdateSymbolMsgPanelInfo()
Display the documentation of the selected symbol.
LIB_ID GetTargetLibId() const override
Return either the symbol selected in the symbol tree (if context menu is active) or the symbol on the...
bool saveLibrary(const wxString &aLibrary, bool aNewFile)
Save the changes to the current library.
void SelectActiveLibrary(const wxString &aLibrary=wxEmptyString)
Set the current active library to aLibrary.
int m_bodyStyle
Flag if the symbol being edited was loaded directly from a schematic.
bool saveAllLibraries(bool aRequireConfirmation)
Save the current symbol.
void UpdateMsgPanel() override
Redraw the message panel.
void CreateNewSymbol(const wxString &newName=wxEmptyString)
Create a new symbol in the selected library.
wxString SetCurLib(const wxString &aLibNickname)
Set the current library nickname and returns the old library nickname.
void UpdateTitle()
Update the main window title bar with the current library name and read only status of the library.
bool LoadSymbolFromCurrentLib(const wxString &aSymbolName, int aUnit=0, int aBodyStyle=0)
Load a symbol from the current active library, optionally setting the selected unit and convert.
SYMBOL_TREE_PANE * m_treePane
bool LoadOneLibrarySymbolAux(LIB_SYMBOL *aLibEntry, const wxString &aLibrary, int aUnit, int aBodyStyle)
Create a copy of aLibEntry into memory.
bool saveCurrentSymbol()
Store the currently modified symbol in the library manager buffer.
void SaveSymbolCopyAs(bool aOpenCopy)
Save the currently selected symbol to a new name and/or location.
wxString AddLibraryFile(bool aCreateNew)
Create or add an existing library to the symbol library table.
void ensureUniqueName(LIB_SYMBOL *aSymbol, const wxString &aLibrary)
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current symbol.
void SaveLibraryAs()
Save the currently selected library to a new file.
bool IsContentModified() const override
Get if any symbols or libraries have been modified but not saved.
LIB_SYMBOL * getTargetSymbol() const
Return either the library selected in the symbol tree, if context menu is active or the library that ...
An interface to the global shared library manager that is schematic-specific and linked to one projec...
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
bool SymbolNameInUse(const wxString &aName, const wxString &aLibrary)
Return true if the symbol name is already in use in the specified library.
LIB_SYMBOL * GetSymbol(const wxString &aSymbolName, const wxString &aLibrary) const
Return either an alias of a working LIB_SYMBOL copy, or alias of the original symbol if there is no w...
This is a class that handles state involved in saving a symbol copy as a new symbol.
CONFLICT_STRATEGY m_strategy
wxString resolveConflict(const wxString &proposed, const wxString &aNewLibName) const
SYMBOL_SAVE_AS_HANDLER(LIB_SYMBOL_LIBRARY_MANAGER &aLibMgr, CONFLICT_STRATEGY aStrategy, bool aValueFollowsName)
LIB_SYMBOL_LIBRARY_MANAGER & m_libMgr
bool DoSave(LIB_SYMBOL &symbol, const wxString &aNewSymName, const wxString &aNewLibName, bool aFlattenSymbol)
TOOL_MANAGER * m_toolManager
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:80
wxString wx_str() const
Definition utf8.cpp:45
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
std::string GetClipboardUTF8()
Return the information currently stored in the system clipboard.
Definition clipboard.cpp:58
int OKOrCancelDialog(wxWindow *aParent, const wxString &aWarning, const wxString &aMessage, const wxString &aDetailedMessage, const wxString &aOKLabel, const wxString &aCancelLabel, bool *aApplyToAll)
Display a warning dialog with aMessage and returns the user response.
Definition confirm.cpp:150
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:259
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition confirm.cpp:131
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
int UnsavedChangesDialog(wxWindow *parent, const wxString &aMessage, bool *aApplyToAll)
A specialized version of HandleUnsavedChanges which handles an apply-to-all checkbox.
Definition confirm.cpp:64
bool ConfirmRevertDialog(wxWindow *parent, const wxString &aMessage)
Display a confirmation dialog for a revert action.
Definition confirm.cpp:118
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG_BASE
Definition confirm.h:46
#define _(s)
@ FRAME_SCH
Definition frame_type.h:34
static const std::string KiCadSymbolLibFileExtension
static wxString KiCadSymbolLibFileWildcard()
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
PROJECT & Prj()
Definition kicad.cpp:623
void Prettify(std::string &aSource, FORMAT_MODE aMode)
Pretty-prints s-expression text according to KiCad format rules.
@ ALL
All except INITIAL_ADD.
Definition view_item.h:59
STL namespace.
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:946
see class PGM_BASE
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition ptree.cpp:198
KIWAY Kiway(KFCTL_STANDALONE)
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
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:...
@ CTX_LIBID
SYMBOL_SAVE_AS_HANDLER::CONFLICT_STRATEGY m_ConflictStrategy
SAVE_AS_IDS
@ ID_OVERWRITE_CONFLICTS
@ ID_RENAME_CONFLICTS
@ ID_MAKE_NEW_LIBRARY
static std::vector< wxString > CheckForParentalChainConflicts(LIB_SYMBOL_LIBRARY_MANAGER &aLibMgr, LIB_SYMBOL &aSymbol, bool aFlattenSymbol, const wxString &newSymbolName, const wxString &newLibraryName)
Get a list of all the symbols in the parental chain of a symbol that have conflicts when transposed t...
static std::vector< std::shared_ptr< LIB_SYMBOL > > GetParentChain(const LIB_SYMBOL &aSymbol, bool aIncludeLeaf=true)
Get a list of all the symbols in the parental chain of a symbol, with the "leaf" symbol at the start ...
static std::pair< bool, bool > CheckSavingIntoOwnInheritance(LIB_SYMBOL_LIBRARY_MANAGER &aLibMgr, LIB_SYMBOL &aSymbol, const wxString &aNewSymbolName, const wxString &aNewLibraryName)
Check if a planned overwrite would put a symbol into it's own inheritance chain.
SYMBOL_SAVEAS_TYPE
const SHAPE_LINE_CHAIN chain
Definition of file extensions used in Kicad.