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 <kiplatform/ui.h>
50#include <string_utils.h>
51#include "symbol_saveas_type.h"
55
56
58{
59 wxString title;
60
62 {
64 title = wxT( "*" );
65
66 title += m_reference;
67 title += wxS( " " ) + _( "[from schematic]" );
68 }
69 else if( GetCurSymbol() )
70 {
72 title = wxT( "*" );
73
74 title += UnescapeString( GetCurSymbol()->GetLibId().Format() );
75
76 if( m_libMgr && m_libMgr->LibraryExists( GetCurLib() ) && m_libMgr->IsLibraryReadOnly( GetCurLib() ) )
77 title += wxS( " " ) + _( "[Read Only Library]" );
78 }
79 else
80 {
81 title = _( "[no symbol loaded]" );
82 }
83
84 title += wxT( " \u2014 " ) + _( "Symbol Editor" );
85 SetTitle( title );
86}
87
88
89void SYMBOL_EDIT_FRAME::SelectActiveLibrary( const wxString& aLibrary )
90{
91 wxString selectedLib = aLibrary;
92
93 if( selectedLib.empty() )
94 selectedLib = SelectLibrary( _( "Select Symbol Library" ), _( "Library:" ) );
95
96 if( !selectedLib.empty() )
97 SetCurLib( selectedLib );
98
100}
101
102
104{
105 if( GetCurSymbol() )
106 {
108 {
109 SCH_EDIT_FRAME* schframe = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
110
111 if( !schframe ) // happens when the schematic editor has been closed
112 {
113 DisplayErrorMessage( this, _( "No schematic currently open." ) );
114 return false;
115 }
116 else
117 {
119 GetScreen()->SetContentModified( false );
120 return true;
121 }
122 }
123 else
124 {
125 const wxString& libName = GetCurSymbol()->GetLibId().GetLibNickname();
126
127 if( m_libMgr->IsLibraryReadOnly( libName ) )
128 {
129 wxString msg = wxString::Format( _( "Symbol library '%s' is not writable." ),
130 libName );
131 wxString msg2 = _( "You must save to a different location." );
132
133 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) == wxID_OK )
134 return saveLibrary( libName, true );
135 }
136 else
137 {
138 return saveLibrary( libName, false );
139 }
140 }
141 }
142
143 return false;
144}
145
146
147bool SYMBOL_EDIT_FRAME::LoadSymbol( const LIB_ID& aLibId, int aUnit, int aBodyStyle )
148{
149 LIB_ID libId = aLibId;
152
153 // Some libraries can't be edited, so load the underlying chosen symbol
154 if( auto optRow = manager.GetRow( LIBRARY_TABLE_TYPE::SYMBOL, aLibId.GetLibNickname() );
155 optRow.has_value() )
156 {
157 const LIBRARY_TABLE_ROW* row = *optRow;
158 SCH_IO_MGR::SCH_FILE_T type = SCH_IO_MGR::EnumFromStr( row->Type() );
159
160 if( type == SCH_IO_MGR::SCH_DATABASE
161 || type == SCH_IO_MGR::SCH_CADSTAR_ARCHIVE
162 || type == SCH_IO_MGR::SCH_HTTP )
163 {
164 try
165 {
166 LIB_SYMBOL* readOnlySym = adapter->LoadSymbol( aLibId );
167
168 if( readOnlySym && readOnlySym->GetSourceLibId().IsValid() )
169 libId = readOnlySym->GetSourceLibId();
170 }
171 catch( const IO_ERROR& ioe )
172 {
173 wxString msg;
174
175 msg.Printf( _( "Error loading symbol %s from library '%s'." ),
176 aLibId.GetUniStringLibId(), aLibId.GetUniStringLibItemName() );
177 DisplayErrorMessage( this, msg, ioe.What() );
178 return false;
179 }
180 }
181 }
182
184 && GetCurSymbol()->GetLibId() == libId
185 && GetUnit() == aUnit
186 && GetBodyStyle() == aBodyStyle )
187 {
188 return true;
189 }
190
192 {
193 if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
194 [&]() -> bool
195 {
196 return saveCurrentSymbol();
197 } ) )
198 {
199 return false;
200 }
201 }
202
204
205 if( LoadSymbolFromCurrentLib( libId.GetLibItemName(), aUnit, aBodyStyle ) )
206 {
207 m_treePane->GetLibTree()->SelectLibId( libId );
208 m_treePane->GetLibTree()->ExpandLibId( libId );
209
210 m_centerItemOnIdle = libId;
211 Bind( wxEVT_IDLE, &SYMBOL_EDIT_FRAME::centerItemIdleHandler, this );
212 setSymWatcher( &libId );
213
214 return true;
215 }
216
217 return false;
218}
219
220
222{
223 m_treePane->GetLibTree()->CenterLibId( m_centerItemOnIdle );
224 Unbind( wxEVT_IDLE, &SYMBOL_EDIT_FRAME::centerItemIdleHandler, this );
225}
226
227
228bool SYMBOL_EDIT_FRAME::LoadSymbolFromCurrentLib( const wxString& aSymbolName, int aUnit,
229 int aBodyStyle )
230{
231 LIB_SYMBOL* symbol = nullptr;
232
233 try
234 {
235 symbol = PROJECT_SCH::SymbolLibAdapter( &Prj() )->LoadSymbol( GetCurLib(), aSymbolName );
236 }
237 catch( const IO_ERROR& ioe )
238 {
239 wxString msg;
240
241 msg.Printf( _( "Error loading symbol %s from library '%s'." ),
242 aSymbolName,
243 GetCurLib() );
244 DisplayErrorMessage( this, msg, ioe.What() );
245 return false;
246 }
247
248 if( !symbol || !LoadOneLibrarySymbolAux( symbol, GetCurLib(), aUnit, aBodyStyle ) )
249 return false;
250
251 // Enable synchronized pin edit mode for symbols with interchangeable units
253
256
258
259 return true;
260}
261
262
263bool SYMBOL_EDIT_FRAME::LoadOneLibrarySymbolAux( LIB_SYMBOL* aEntry, const wxString& aLibrary,
264 int aUnit, int aBodyStyle )
265{
266 bool rebuildMenuAndToolbar = false;
267
268 if( !aEntry || aLibrary.empty() )
269 return false;
270
271 if( aEntry->GetName().IsEmpty() )
272 {
273 wxLogWarning( "Symbol in library '%s' has empty name field.", aLibrary );
274 return false;
275 }
276
278
279 // Symbols from the schematic are edited in place and not managed by the library manager.
281 {
282 delete m_symbol;
283 m_symbol = nullptr;
284
285 SCH_SCREEN* screen = GetScreen();
286 delete screen;
289 rebuildMenuAndToolbar = true;
290 }
291
292 LIB_SYMBOL* lib_symbol = m_libMgr->GetBufferedSymbol( aEntry->GetName(), aLibrary );
293 wxCHECK( lib_symbol, false );
294
295 m_unit = aUnit > 0 ? aUnit : 1;
296 m_bodyStyle = aBodyStyle > 0 ? aBodyStyle : 1;
297
298 // The buffered screen for the symbol
299 SCH_SCREEN* symbol_screen = m_libMgr->GetScreen( lib_symbol->GetName(), aLibrary );
300
301 SetScreen( symbol_screen );
302 SetCurSymbol( new LIB_SYMBOL( *lib_symbol ), true );
303 SetCurLib( aLibrary );
304
305 if( rebuildMenuAndToolbar )
306 {
309 GetInfoBar()->Dismiss();
310 }
311
312 UpdateTitle();
314
316
317 if( !IsSymbolFromSchematic() )
318 {
319 LIB_ID libId = GetCurSymbol()->GetLibId();
320 setSymWatcher( &libId );
321 }
322
323 // Let tools add things to the view if necessary
324 if( m_toolManager )
326
328
329 // Display the document information based on the entry selected just in
330 // case the entry is an alias.
332 Refresh();
333
334 return true;
335}
336
337
339{
340 saveAllLibraries( false );
341 m_treePane->GetLibTree()->RefreshLibTree();
342}
343
344
345void SYMBOL_EDIT_FRAME::CreateNewSymbol( const wxString& aInheritFrom )
346{
348
349 wxString lib = getTargetLib();
350
351 if( !m_libMgr->LibraryExists( lib ) )
352 {
353 lib = SelectLibrary( _( "New Symbol" ), _( "Create symbol in library:" ) );
354
355 if( !m_libMgr->LibraryExists( lib ) )
356 return;
357 }
358
359 const auto validator =
360 [&]( wxString newName ) -> bool
361 {
362 if( newName.IsEmpty() )
363 {
364 wxMessageBox( _( "Symbol must have a name." ) );
365 return false;
366 }
367
368 if( !lib.empty() && m_libMgr->SymbolNameInUse( newName, lib ) )
369 {
370 wxString msg;
371
372 msg.Printf( _( "Symbol '%s' already exists in library '%s'." ),
373 UnescapeString( newName ),
374 lib );
375
376 KIDIALOG errorDlg( this, msg, _( "Confirmation" ),
377 wxOK | wxCANCEL | wxICON_WARNING );
378
379 errorDlg.SetOKLabel( _( "Overwrite" ) );
380
381 return errorDlg.ShowModal() == wxID_OK;
382 }
383
384 return true;
385 };
386
387 wxArrayString symbolNamesInLib;
388 m_libMgr->GetSymbolNames( lib, symbolNamesInLib );
389
390 DIALOG_LIB_NEW_SYMBOL dlg( this, symbolNamesInLib, aInheritFrom, validator );
391
392 dlg.SetMinSize( dlg.GetSize() );
393
394 if( dlg.ShowModal() == wxID_CANCEL )
395 return;
396
398
399 props.name = dlg.GetName();
401 props.reference = dlg.GetReference();
402 props.unitCount = dlg.GetUnitCount();
403 props.pinNameInside = dlg.GetPinNameInside();
405 props.powerSymbol = dlg.GetPowerSymbol();
406 props.showPinNumber = dlg.GetShowPinNumber();
407 props.showPinName = dlg.GetShowPinName();
409 props.includeInBom = dlg.GetIncludeInBom();
410 props.includeOnBoard = dlg.GetIncludeOnBoard();
412 props.keepFootprint = dlg.GetKeepFootprint();
413 props.keepDatasheet = dlg.GetKeepDatasheet();
416
417 m_libMgr->CreateNewSymbol( lib, props );
418 SyncLibraries( false );
419 LoadSymbol( props.name, lib, 1 );
420}
421
422
424{
425 wxString libName;
426
427 if( IsLibraryTreeShown() )
429
430 if( libName.empty() )
431 {
433 }
434 else if( m_libMgr->IsLibraryReadOnly( libName ) )
435 {
436 wxString msg = wxString::Format( _( "Symbol library '%s' is not writable." ),
437 libName );
438 wxString msg2 = _( "You must save to a different location." );
439
440 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) == wxID_OK )
441 saveLibrary( libName, true );
442 }
443 else
444 {
445 saveLibrary( libName, false );
446 }
447
448 if( IsLibraryTreeShown() )
449 m_treePane->GetLibTree()->RefreshLibTree();
450
451 UpdateTitle();
452}
453
454
456{
457 const wxString& libName = GetTargetLibId().GetLibNickname();
458
459 if( !libName.IsEmpty() )
460 {
461 saveLibrary( libName, true );
462 m_treePane->GetLibTree()->RefreshLibTree();
463 }
464}
465
466
468{
469 saveSymbolCopyAs( aOpenCopy );
470
471 m_treePane->GetLibTree()->RefreshLibTree();
472}
473
474
484static std::vector<std::shared_ptr<LIB_SYMBOL>> GetParentChain( const LIB_SYMBOL& aSymbol, bool aIncludeLeaf = true )
485{
486 std::vector<std::shared_ptr<LIB_SYMBOL>> chain;
487 std::shared_ptr<LIB_SYMBOL> sym = aSymbol.SharedPtr();
488
489 if( aIncludeLeaf )
490 chain.push_back( sym );
491
492 while( sym->IsDerived() )
493 {
494 std::shared_ptr<LIB_SYMBOL> parent = sym->GetParent().lock();
495 chain.push_back( parent );
496 sym = parent;
497 }
498
499 return chain;
500}
501
502
512static std::pair<bool, bool> CheckSavingIntoOwnInheritance( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr,
513 LIB_SYMBOL& aSymbol,
514 const wxString& aNewSymbolName,
515 const wxString& aNewLibraryName )
516{
517 const wxString& oldLibraryName = aSymbol.GetLibId().GetLibNickname();
518
519 // Cannot be intersecting if in different libs
520 if( aNewLibraryName != oldLibraryName )
521 return { false, false };
522
523 // Or if the target symbol doesn't exist
524 if( !aLibMgr.SymbolNameInUse( aNewSymbolName, aNewLibraryName ) )
525 return { false, false };
526
527 bool inAncestry = false;
528 bool inDescendents = false;
529
530 {
531 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChainFromUs = GetParentChain( aSymbol, true );
532
533 // Ignore the leaf symbol (0) - that must match
534 for( size_t i = 1; i < parentChainFromUs.size(); ++i )
535 {
536 // Attempting to overwrite a symbol in the parental chain
537 if( parentChainFromUs[i]->GetName() == aNewSymbolName )
538 {
539 inAncestry = true;
540 break;
541 }
542 }
543 }
544
545 {
546 LIB_SYMBOL* targetSymbol = aLibMgr.GetSymbol( aNewSymbolName, aNewLibraryName );
547 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChainFromTarget = GetParentChain( *targetSymbol, true );
548 const wxString oldSymbolName = aSymbol.GetName();
549
550 // Ignore the leaf symbol - it'll match if we're saving the symbol
551 // to the same name, and that would be OK
552 for( size_t i = 1; i < parentChainFromTarget.size(); ++i )
553 {
554 if( parentChainFromTarget[i]->GetName() == oldSymbolName )
555 {
556 inDescendents = true;
557 break;
558 }
559 }
560 }
561
562 return { inAncestry, inDescendents };
563}
564
565
573static std::vector<wxString> CheckForParentalChainConflicts( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr,
574 LIB_SYMBOL& aSymbol,
575 bool aFlattenSymbol,
576 const wxString& newSymbolName,
577 const wxString& newLibraryName )
578{
579 std::vector<wxString> conflicts;
580 const wxString& oldLibraryName = aSymbol.GetLibId().GetLibNickname();
581
582 if( newLibraryName == oldLibraryName || aFlattenSymbol )
583 {
584 // Saving into the same library - the only conflict could be the symbol itself
585 // Different library and flattening - ditto
586 if( aLibMgr.SymbolNameInUse( newSymbolName, newLibraryName ) )
587 conflicts.push_back( newSymbolName );
588 }
589 else
590 {
591 // In a different library with parents - check the whole chain
592 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain = GetParentChain( aSymbol, true );
593
594 for( size_t i = 0; i < parentChain.size(); ++i )
595 {
596 if( i == 0 )
597 {
598 // This is the leaf symbol which the user actually named
599 if( aLibMgr.SymbolNameInUse( newSymbolName, newLibraryName ) )
600 conflicts.push_back( newSymbolName );
601 }
602 else
603 {
604 std::shared_ptr<LIB_SYMBOL> chainSymbol = parentChain[i];
605
606 if( aLibMgr.SymbolNameInUse( chainSymbol->GetName(), newLibraryName ) )
607 conflicts.push_back( chainSymbol->GetName() );
608 }
609 }
610 }
611
612 return conflicts;
613}
614
615
623{
624public:
626 {
627 // Just overwrite any existing symbols in the target library
629 // Add a suffix until we find a name that doesn't conflict
631 // Could have a mode that asks for every one, be then we'll need a fancier
632 // SAVE_SYMBOL_AS_DIALOG subdialog with Overwrite/Rename/Prompt/Cancel
633 // PROMPT
634 };
635
636 SYMBOL_SAVE_AS_HANDLER( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr, CONFLICT_STRATEGY aStrategy, bool aValueFollowsName ) :
637 m_libMgr( aLibMgr ),
638 m_strategy( aStrategy ),
639 m_valueFollowsName( aValueFollowsName )
640 {
641 }
642
643 bool DoSave( LIB_SYMBOL& symbol, const wxString& aNewSymName, const wxString& aNewLibName, bool aFlattenSymbol )
644 {
645 std::unique_ptr<LIB_SYMBOL> flattenedSymbol; // for ownership
646 std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain;
647
648 const bool sameLib = aNewLibName == symbol.GetLibId().GetLibNickname().wx_str();
649
650 if( aFlattenSymbol )
651 {
652 // If we're not copying parent symbols, we need to flatten the symbol
653 // and only save that.
654 flattenedSymbol = symbol.Flatten();
655 wxCHECK( flattenedSymbol, false );
656
657 parentChain.push_back( flattenedSymbol->SharedPtr() );
658 }
659 else if( sameLib )
660 {
661 // If we're saving into the same library, we don't need to check the parental chain
662 // because we can just keep the same parent symbol
663 parentChain.push_back( symbol.SharedPtr() );
664 }
665 else
666 {
667 // Need to copy all parent symbols
668 parentChain = GetParentChain( symbol, true );
669 }
670
671 std::vector<wxString> newNames;
672
673 // Iterate backwards (i.e. from the root down)
674 for( int i = (int) parentChain.size() - 1; i >= 0; --i )
675 {
676 std::shared_ptr<LIB_SYMBOL>& oldSymbol = parentChain[i];
677 LIB_SYMBOL new_symbol( *oldSymbol );
678
679 wxString newName;
680 if( i == 0 )
681 {
682 // This is the leaf symbol which the user actually named
683 newName = aNewSymName;
684 }
685 else
686 {
687 // Somewhere in the inheritance chain, use the conflict resolution strategy
688 newName = oldSymbol->GetName();
689 }
690
691 newName = resolveConflict( newName, aNewLibName );
692 new_symbol.SetName( newName );
693
695 new_symbol.GetValueField().SetText( newName );
696
697 if( i == (int) parentChain.size() - 1 )
698 {
699 // This is the root symbol
700 // Nothing extra to do, it's just a simple symbol with no parents
701 }
702 else
703 {
704 // Get the buffered new copy in the new library (with the name we gave it)
705 LIB_SYMBOL* newParent = m_libMgr.GetSymbol( newNames.back(), aNewLibName );
706
707 // We should have stored this already, why didn't we get it back?
708 wxASSERT( newParent );
709 new_symbol.SetParent( newParent );
710 }
711
712 newNames.push_back( newName );
713 m_libMgr.UpdateSymbol( &new_symbol, aNewLibName );
714 }
715
716 return true;
717 }
718
719private:
720 wxString resolveConflict( const wxString& proposed, const wxString& aNewLibName ) const
721 {
722 switch( m_strategy )
723 {
725 {
726 // In an overwrite strategy, we don't care about conflicts
727 return proposed;
728 }
730 {
731 // In a rename strategy, we need to find a name that doesn't conflict
732 int suffix = 1;
733
734 while( true )
735 {
736 wxString newName = wxString::Format( "%s_%d", proposed, suffix );
737
738 if( !m_libMgr.SymbolNameInUse( newName, aNewLibName ) )
739 return newName;
740
741 ++suffix;
742 }
743 break;
744 }
745 // No default
746 }
747
748 wxFAIL_MSG( "Invalid conflict strategy" );
749 return "";
750 }
751
755};
756
757
764
765
767{
768public:
769 using SymLibNameValidator = std::function<int( const wxString& libName, const wxString& symbolName )>;
770
778
780 PARAMS& aParams,
781 SymLibNameValidator aValidator,
782 const std::vector<wxString>& aParentSymbolNames ) :
783 EDA_LIST_DIALOG( aParent, _( "Save Symbol As" ), false ),
784 m_validator( std::move( aValidator ) ),
785 m_params( aParams )
786 {
787 wxArrayString headers;
788 std::vector<wxArrayString> itemsToDisplay;
789
790 if( aParentSymbolNames.size() )
791 {
792 // This is a little trick to word - when saving to another library, "copy parents" makes sense,
793 // but when in the same library, the parents will be untouched in any case.
794 const wxString aParentNames = AccumulateDescriptions( aParentSymbolNames );
795 AddExtraCheckbox(
796 wxString::Format( "Flatten/remove symbol inheritance (current parent symbols: %s)", aParentNames ),
797 &m_params.m_FlattenSymbol );
798 }
799
800 aParent->GetLibraryItemsForListDialog( headers, itemsToDisplay );
801 initDialog( headers, itemsToDisplay, m_params.m_LibraryName );
802
803 SetListLabel( _( "Save in library:" ) );
804 SetOKLabel( _( "Save" ) );
805
806 wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
807
808 wxStaticText* label = new wxStaticText( this, wxID_ANY, _( "Name:" ) );
809 bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
810
811 m_symbolNameCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString );
812 bNameSizer->Add( m_symbolNameCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
813
814 wxButton* newLibraryButton = new wxButton( this, ID_MAKE_NEW_LIBRARY, _( "New Library..." ) );
815 m_ButtonsSizer->Prepend( 80, 20 );
816 m_ButtonsSizer->Prepend( newLibraryButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 );
817
818 GetSizer()->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
819
820 Bind( wxEVT_BUTTON,
821 [this]( wxCommandEvent& )
822 {
823 EndModal( ID_MAKE_NEW_LIBRARY );
825
826 // Move nameTextCtrl to the head of the tab-order
827 if( GetChildren().DeleteObject( m_symbolNameCtrl ) )
828 GetChildren().Insert( m_symbolNameCtrl );
829
831
833
834 Layout();
835 GetSizer()->Fit( this );
836
837 Centre();
838 }
839
840protected:
841 wxString getSymbolName() const
842 {
843 wxString symbolName = m_symbolNameCtrl->GetValue();
844 symbolName.Trim( true );
845 symbolName.Trim( false );
846 symbolName.Replace( " ", "_" );
847 return EscapeString( symbolName, CTX_LIBID );
848 }
849
850 bool TransferDataToWindow() override
851 {
852 m_symbolNameCtrl->SetValue( UnescapeString( m_params.m_SymbolName ) );
853 return true;
854 }
855
857 {
858 // This updates m_params.m_FlattenSymbol
859 // Do this now, so the validator can use it
861
862 m_params.m_SymbolName = getSymbolName();
863 m_params.m_LibraryName = GetTextSelection();
864
865 int ret = m_validator( m_params.m_LibraryName, m_params.m_SymbolName );
866
867 if( ret == wxID_CANCEL )
868 return false;
869
870 if( ret == ID_OVERWRITE_CONFLICTS )
872 else if( ret == ID_RENAME_CONFLICTS )
874
875 return true;
876 }
877
878private:
879 wxTextCtrl* m_symbolNameCtrl;
882};
883
884
886{
887 LIB_SYMBOL* symbol = getTargetSymbol();
888
889 if( !symbol )
890 return;
891
892 LIB_ID old_lib_id = symbol->GetLibId();
893 wxString symbolName = old_lib_id.GetLibItemName();
894 wxString libraryName = old_lib_id.GetLibNickname();
895 bool valueFollowsName = symbol->GetValueField().GetText() == symbolName;
896 wxString msg;
897 bool done = false;
898 bool flattenSymbol = false;
899
900 // This is the function that will be called when the user clicks OK in the dialog and checks
901 // if the proposed name has problems, and asks for clarification.
902 const auto dialogValidatorFunc =
903 [&]( const wxString& newLib, const wxString& newName ) -> int
904 {
905 if( newLib.IsEmpty() )
906 {
907 wxMessageBox( _( "A library must be specified." ) );
908 return wxID_CANCEL;
909 }
910
911 if( newName.IsEmpty() )
912 {
913 wxMessageBox( _( "Symbol must have a name." ) );
914 return wxID_CANCEL;
915 }
916
917 if( m_libMgr->IsLibraryReadOnly( newLib ) )
918 {
919 msg = wxString::Format( _( "Library '%s' is read-only. Choose a "
920 "different library to save the symbol '%s' to." ),
921 newLib,
922 UnescapeString( newName ) );
923 wxMessageBox( msg );
924 return wxID_CANCEL;
925 }
926
931 const auto& [inAncestry, inDescendents] = CheckSavingIntoOwnInheritance( *m_libMgr, *symbol,
932 newName, newLib );
933
934 if( inAncestry )
935 {
936 msg = wxString::Format( _( "Symbol '%s' cannot replace another symbol '%s' "
937 "that it descends from" ),
938 symbolName,
939 UnescapeString( newName ) );
940 wxMessageBox( msg );
941 return wxID_CANCEL;
942 }
943
944 if( inDescendents )
945 {
946 msg = wxString::Format( _( "Symbol '%s' cannot replace another symbol '%s' "
947 "that is a descendent of it." ),
948 symbolName,
949 UnescapeString( newName ) );
950 wxMessageBox( msg );
951 return wxID_CANCEL;
952 }
953
954 const std::vector<wxString> conflicts =
955 CheckForParentalChainConflicts( *m_libMgr, *symbol, flattenSymbol, newName, newLib );
956
957 if( conflicts.size() == 1 && conflicts.front() == newName )
958 {
959 // The simplest case is when the symbol itself has a conflict
960 msg = wxString::Format( _( "Symbol '%s' already exists in library '%s'. "
961 "Do you want to overwrite it?" ),
962 UnescapeString( newName ),
963 newLib );
964
965 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
966 errorDlg.SetOKLabel( _( "Overwrite" ) );
967
968 return errorDlg.ShowModal() == wxID_OK ? ID_OVERWRITE_CONFLICTS : (int) wxID_CANCEL;
969 }
970 else if( !conflicts.empty() )
971 {
972 // If there are conflicts in the parental chain, we need to ask the user
973 // if they want to overwrite all of them.
974 // A more complex UI might allow the user to re-parent the symbol to an
975 // existing symbol in the target lib, or rename all the parents somehow.
976 msg = wxString::Format( _( "The following symbols in the inheritance chain of "
977 "'%s' already exist in library '%s':\n" ),
978 UnescapeString( symbolName ),
979 newLib );
980
981 for( const wxString& conflict : conflicts )
982 msg += wxString::Format( " %s\n", conflict );
983
984 msg += _( "\nDo you want to overwrite all of them, or rename the new symbols?" );
985
986 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
987 errorDlg.SetYesNoCancelLabels( _( "Overwrite All" ), _( "Rename All" ), _( "Cancel" ) );
988
989 switch( errorDlg.ShowModal() )
990 {
991 case wxID_YES: return ID_OVERWRITE_CONFLICTS;
992 case wxID_NO: return ID_RENAME_CONFLICTS;
993 default: return wxID_CANCEL;
994 }
995 }
996
997 return wxID_OK;
998 };
999
1001
1002 std::vector<wxString> parentSymbolNames;
1003 if( symbol->IsDerived() )
1004 {
1005 // The parents are everything but the leaf symbol
1006 std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain = GetParentChain( *symbol, false );
1007
1008 for( const auto& parent : parentChain )
1009 parentSymbolNames.push_back( parent->GetName() );
1010 }
1011
1013 symbolName,
1014 libraryName,
1015 flattenSymbol,
1016 strategy,
1017 };
1018
1019 // Keep asking the user for a new name until they give a valid one or cancel the operation
1020 while( !done )
1021 {
1022 SAVE_SYMBOL_AS_DIALOG dlg( this, params, dialogValidatorFunc, parentSymbolNames );
1023
1024 int ret = dlg.ShowModal();
1025
1026 switch( ret )
1027 {
1028 case wxID_CANCEL:
1029 return;
1030
1031 case wxID_OK: // No conflicts
1034 {
1035 done = true;
1036 break;
1037 }
1039 {
1040 wxFileName newLibrary( AddLibraryFile( true ) );
1041 params.m_LibraryName = newLibrary.GetName();
1042
1043 // Go round again to ask for the symbol name
1044 break;
1045 }
1046
1047 default:
1048 break;
1049 }
1050 }
1051
1052 SYMBOL_SAVE_AS_HANDLER saver( *m_libMgr, params.m_ConflictStrategy, valueFollowsName );
1053
1054 saver.DoSave( *symbol, params.m_SymbolName, params.m_LibraryName, params.m_FlattenSymbol );
1055
1056 SyncLibraries( false );
1057
1058 if( aOpenCopy )
1059 LoadSymbol( params.m_SymbolName, params.m_LibraryName, 1 );
1060}
1061
1062
1064{
1065 wxString msg;
1066 LIB_SYMBOL* symbol = getTargetSymbol();
1067
1068 if( !symbol )
1069 {
1070 ShowInfoBarError( _( "There is no symbol selected to save." ) );
1071 return;
1072 }
1073
1074 wxFileName fn;
1075
1076 fn.SetName( symbol->GetName().Lower() );
1078
1079 wxFileDialog dlg( this, _( "Export Symbol" ), m_mruPath, fn.GetFullName(),
1081
1083
1084 if( dlg.ShowModal() == wxID_CANCEL )
1085 return;
1086
1088
1089 fn = dlg.GetPath();
1090 fn.MakeAbsolute();
1091
1092 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
1093
1094 wxString libraryName;
1095 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = symbol->Flatten();
1096
1097 for( const wxString& candidate : m_libMgr->GetLibraryNames() )
1098 {
1099 if( auto uri = manager.GetFullURI( LIBRARY_TABLE_TYPE::SYMBOL, candidate, true ); uri )
1100 {
1101 if( *uri == fn.GetFullPath() )
1102 libraryName = candidate;
1103 }
1104 }
1105
1106 if( !libraryName.IsEmpty() )
1107 {
1108 SYMBOL_SAVE_AS_HANDLER saver( *m_libMgr, strategy, false );
1109
1110 if( m_libMgr->IsLibraryReadOnly( libraryName ) )
1111 {
1112 msg = wxString::Format( _( "Library '%s' is read-only." ), libraryName );
1113 DisplayError( this, msg );
1114 return;
1115 }
1116
1117 if( m_libMgr->SymbolNameInUse( symbol->GetName(), libraryName ) )
1118 {
1119 msg = wxString::Format( _( "Symbol '%s' already exists in library '%s'." ),
1120 symbol->GetName(), libraryName );
1121
1122 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1123 errorDlg.SetOKLabel( _( "Overwrite" ) );
1124 errorDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1125
1126 if( errorDlg.ShowModal() == wxID_CANCEL )
1127 return;
1128 }
1129
1130 saver.DoSave( *flattenedSymbol, symbol->GetName(), libraryName, false );
1131
1132 SyncLibraries( false );
1133 return;
1134 }
1135
1136 LIB_SYMBOL* old_symbol = nullptr;
1137 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() );
1138
1139 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1140 pluginType = SCH_IO_MGR::SCH_KICAD;
1141
1142 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pluginType ) );
1143
1144 if( fn.FileExists() )
1145 {
1146 try
1147 {
1148 old_symbol = pi->LoadSymbol( fn.GetFullPath(), symbol->GetName() );
1149 }
1150 catch( const IO_ERROR& ioe )
1151 {
1152 msg.Printf( _( "Error occurred attempting to load symbol library file '%s'." ),
1153 fn.GetFullPath() );
1154 DisplayErrorMessage( this, msg, ioe.What() );
1155 return;
1156 }
1157
1158 if( old_symbol )
1159 {
1160 msg.Printf( _( "Symbol %s already exists in library '%s'." ),
1161 UnescapeString( symbol->GetName() ),
1162 fn.GetFullName() );
1163
1164 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1165 errorDlg.SetOKLabel( _( "Overwrite" ) );
1166 errorDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1167
1168 if( errorDlg.ShowModal() == wxID_CANCEL )
1169 return;
1170 }
1171 }
1172
1173 if( !fn.IsDirWritable() )
1174 {
1175 msg.Printf( _( "Insufficient permissions to save library '%s'." ), fn.GetFullPath() );
1176 DisplayError( this, msg );
1177 return;
1178 }
1179
1180 try
1181 {
1182 if( !fn.FileExists() )
1183 pi->CreateLibrary( fn.GetFullPath() );
1184
1185 // The flattened symbol is most likely what the user would want. As some point in
1186 // the future as more of the symbol library inheritance is implemented, this may have
1187 // to be changes to save symbols of inherited symbols.
1188 pi->SaveSymbol( fn.GetFullPath(), flattenedSymbol.release() );
1189 }
1190 catch( const IO_ERROR& ioe )
1191 {
1192 msg.Printf( _( "Failed to create symbol library file '%s'." ), fn.GetFullPath() );
1193 DisplayErrorMessage( this, msg, ioe.What() );
1194 msg.Printf( _( "Error creating symbol library '%s'." ), fn.GetFullName() );
1195 SetStatusText( msg );
1196 return;
1197 }
1198
1199 m_mruPath = fn.GetPath();
1200
1201 msg.Printf( _( "Symbol %s saved to library '%s'." ),
1202 UnescapeString( symbol->GetName() ),
1203 fn.GetFullPath() );
1204 SetStatusText( msg );
1205}
1206
1207
1209{
1210 wxCHECK( m_symbol, /* void */ );
1211
1212 wxString lib = GetCurLib();
1213
1214 if( !lib.IsEmpty() && aOldName && *aOldName != m_symbol->GetName() )
1215 {
1216 // Test the current library for name conflicts
1217 if( m_libMgr->SymbolNameInUse( m_symbol->GetName(), lib ) )
1218 {
1219 wxString msg = wxString::Format( _( "Symbol name '%s' already in use." ),
1220 UnescapeString( m_symbol->GetName() ) );
1221
1222 DisplayErrorMessage( this, msg );
1223 m_symbol->SetName( *aOldName );
1224 }
1225 else
1226 {
1227 m_libMgr->UpdateSymbolAfterRename( m_symbol, *aOldName, lib );
1228 }
1229
1230 // Reselect the renamed symbol
1231 m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, m_symbol->GetName() ) );
1232 }
1233
1235 UpdateTitle();
1236
1237 // N.B. The view needs to be rebuilt first as the Symbol Properties change may invalidate
1238 // the view pointers by rebuilting the field table
1239 RebuildView();
1241
1242 OnModify();
1243}
1244
1245
1247{
1248 std::vector<LIB_ID> toDelete = GetSelectedLibIds();
1249
1250 if( toDelete.empty() )
1251 toDelete.emplace_back( GetTargetLibId() );
1252
1253 for( LIB_ID& libId : toDelete )
1254 {
1255 if( m_libMgr->IsSymbolModified( libId.GetLibItemName(), libId.GetLibNickname() )
1256 && !IsOK( this, wxString::Format( _( "The symbol '%s' has been modified.\n"
1257 "Do you want to remove it from the library?" ),
1258 libId.GetUniStringLibItemName() ) ) )
1259 {
1260 continue;
1261 }
1262
1263 wxArrayString derived;
1264
1265 if( m_libMgr->GetDerivedSymbolNames( libId.GetLibItemName(), libId.GetLibNickname(), derived ) > 0 )
1266 {
1267 wxString msg = _( "Deleting a base symbol will delete all symbols derived from it.\n\n" );
1268
1269 msg += libId.GetLibItemName().wx_str() + _( " (base)\n" );
1270
1271 for( const wxString& name : derived )
1272 msg += name + wxT( "\n" );
1273
1274 KICAD_MESSAGE_DIALOG dlg( this, msg, _( "Warning" ), wxYES_NO | wxICON_WARNING | wxCENTER );
1275 dlg.SetExtendedMessage( wxT( " " ) );
1276 dlg.SetYesNoLabels( _( "Delete All Listed Symbols" ), _( "Cancel" ) );
1277
1278 if( dlg.ShowModal() == wxID_NO )
1279 continue;
1280 }
1281
1282 if( GetCurSymbol() )
1283 {
1284 for( const std::shared_ptr<LIB_SYMBOL>& symbol : GetParentChain( *GetCurSymbol() ) )
1285 {
1286 if( symbol->GetLibId() == libId )
1287 {
1288 emptyScreen();
1289 break;
1290 }
1291 }
1292 }
1293
1294 m_libMgr->RemoveSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1295 }
1296
1297 m_treePane->GetLibTree()->RefreshLibTree();
1298}
1299
1300
1302{
1303 std::vector<LIB_ID> symbols;
1304
1305 if( GetTreeLIBIDs( symbols ) == 0 )
1306 return;
1307
1308 STRING_FORMATTER formatter;
1309
1310 for( LIB_ID& libId : symbols )
1311 {
1312 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(),
1313 libId.GetLibNickname() );
1314
1315 if( !symbol )
1316 continue;
1317
1318 std::unique_ptr<LIB_SYMBOL> tmp = symbol->Flatten();
1319 SCH_IO_KICAD_SEXPR::FormatLibSymbol( tmp.get(), formatter );
1320 }
1321
1322 std::string prettyData = formatter.GetString();
1323 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES );
1324
1325 wxLogNull doNotLog; // disable logging of failed clipboard actions
1326
1327 auto clipboard = wxTheClipboard;
1328 wxClipboardLocker clipboardLock( clipboard );
1329
1330 if( !clipboardLock || !clipboard->IsOpened() )
1331 return;
1332
1333 auto data = new wxTextDataObject( wxString( prettyData.c_str(), wxConvUTF8 ) );
1334 clipboard->SetData( data );
1335
1336 clipboard->Flush();
1337}
1338
1339
1340void SYMBOL_EDIT_FRAME::DuplicateSymbol( bool aFromClipboard )
1341{
1342 LIB_ID libId = GetTargetLibId();
1343 wxString lib = libId.GetLibNickname();
1344
1345 if( !m_libMgr->LibraryExists( lib ) )
1346 return;
1347
1348 std::vector<LIB_SYMBOL*> newSymbols;
1349
1350 if( aFromClipboard )
1351 {
1352 std::string clipboardData = GetClipboardUTF8();
1353
1354 try
1355 {
1356 newSymbols = SCH_IO_KICAD_SEXPR::ParseLibSymbols( clipboardData, "Clipboard" );
1357 }
1358 catch( IO_ERROR& e )
1359 {
1360 wxLogMessage( wxS( "Can not paste: %s" ), e.Problem() );
1361 }
1362 }
1363 else if( LIB_SYMBOL* srcSymbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(), lib ) )
1364 {
1365 newSymbols.emplace_back( new LIB_SYMBOL( *srcSymbol ) );
1366
1367 // Derive from same parent.
1368 if( srcSymbol->IsDerived() )
1369 {
1370 if( std::shared_ptr<LIB_SYMBOL> srcParent = srcSymbol->GetParent().lock() )
1371 newSymbols.back()->SetParent( srcParent.get() );
1372 }
1373 }
1374
1375 if( newSymbols.empty() )
1376 return;
1377
1378 for( LIB_SYMBOL* symbol : newSymbols )
1379 {
1380 ensureUniqueName( symbol, lib );
1381 m_libMgr->UpdateSymbol( symbol, lib );
1382
1383 LoadOneLibrarySymbolAux( symbol, lib, GetUnit(), GetBodyStyle() );
1384 }
1385
1386 SyncLibraries( false );
1387 m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newSymbols[0]->GetName() ) );
1388
1389 for( LIB_SYMBOL* symbol : newSymbols )
1390 delete symbol;
1391}
1392
1393
1394void SYMBOL_EDIT_FRAME::ensureUniqueName( LIB_SYMBOL* aSymbol, const wxString& aLibrary )
1395{
1396 if( aSymbol )
1397 {
1398 int i = 1;
1399 wxString newName = aSymbol->GetName();
1400
1401 // Append a number to the name until the name is unique in the library.
1402 while( m_libMgr->SymbolNameInUse( newName, aLibrary ) )
1403 newName.Printf( "%s_%d", aSymbol->GetName(), i++ );
1404
1405 aSymbol->SetName( newName );
1406 }
1407}
1408
1409
1410void SYMBOL_EDIT_FRAME::Revert( bool aConfirm )
1411{
1412 LIB_ID libId = GetTargetLibId();
1413 const wxString& libName = libId.GetLibNickname();
1414
1415 // Empty if this is the library itself that is selected.
1416 const wxString& symbolName = libId.GetLibItemName();
1417
1418 wxString msg = wxString::Format( _( "Revert '%s' to last version saved?" ),
1419 symbolName.IsEmpty() ? libName : symbolName );
1420
1421 if( aConfirm && !ConfirmRevertDialog( this, msg ) )
1422 return;
1423
1424 bool reload_currentSymbol = false;
1425 wxString curr_symbolName = symbolName;
1426
1427 if( GetCurSymbol() )
1428 {
1429 // the library itself is reverted: the current symbol will be reloaded only if it is
1430 // owned by this library
1431 if( symbolName.IsEmpty() )
1432 {
1433 LIB_ID curr_libId = GetCurSymbol()->GetLibId();
1434 reload_currentSymbol = libName == curr_libId.GetLibNickname().wx_str();
1435
1436 if( reload_currentSymbol )
1437 curr_symbolName = curr_libId.GetUniStringLibItemName();
1438 }
1439 else
1440 {
1441 reload_currentSymbol = IsCurrentSymbol( libId );
1442 }
1443 }
1444
1445 int unit = m_unit;
1446
1447 if( reload_currentSymbol )
1448 emptyScreen();
1449
1450 if( symbolName.IsEmpty() )
1451 {
1452 m_libMgr->RevertLibrary( libName );
1453 }
1454 else
1455 {
1456 libId = m_libMgr->RevertSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1457
1458 m_treePane->GetLibTree()->SelectLibId( libId );
1459 m_libMgr->ClearSymbolModified( libId.GetLibItemName(), libId.GetLibNickname() );
1460 }
1461
1462 if( reload_currentSymbol && m_libMgr->SymbolExists( curr_symbolName, libName ) )
1463 LoadSymbol( curr_symbolName, libName, unit );
1464
1465 m_treePane->Refresh();
1466}
1467
1468
1470{
1471 wxCHECK_RET( m_libMgr, "Library manager object not created." );
1472
1473 Revert( false );
1474 m_libMgr->RevertAll();
1475}
1476
1477
1478void SYMBOL_EDIT_FRAME::LoadSymbol( const wxString& aAlias, const wxString& aLibrary, int aUnit )
1479{
1481 {
1482 if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
1483 [&]() -> bool
1484 {
1485 return saveCurrentSymbol();
1486 } ) )
1487 {
1488 return;
1489 }
1490 }
1491
1492 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( aAlias, aLibrary );
1493
1494 if( !symbol )
1495 {
1496 DisplayError( this, wxString::Format( _( "Symbol %s not found in library '%s'." ),
1497 aAlias,
1498 aLibrary ) );
1499 m_treePane->GetLibTree()->RefreshLibTree();
1500 return;
1501 }
1502
1503 // Optimize default edit options for this symbol
1504 // Usually if units are locked, graphic items are specific to each unit
1505 // and if units are interchangeable, graphic items are common to units
1507 tools->SetDrawSpecificUnit( symbol->UnitsLocked() );
1508
1509 LoadOneLibrarySymbolAux( symbol, aLibrary, aUnit, 0 );
1510}
1511
1512
1513bool SYMBOL_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile )
1514{
1515 wxFileName fn;
1516 wxString msg;
1518 SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::SCH_FILE_T::SCH_KICAD;
1519 PROJECT& prj = Prj();
1520
1522
1524
1525 if( !aNewFile && ( aLibrary.empty() || !adapter->HasLibrary( aLibrary ) ) )
1526 {
1527 ShowInfoBarError( _( "No library specified." ) );
1528 return false;
1529 }
1530
1531 if( aNewFile )
1532 {
1533 SEARCH_STACK* search = PROJECT_SCH::SchSearchS( &prj );
1534
1535 // Get a new name for the library
1536 wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
1537
1538 if( !default_path )
1539 default_path = search->LastVisitedPath();
1540
1541 fn.SetName( aLibrary );
1543
1544 wxString wildcards = FILEEXT::KiCadSymbolLibFileWildcard();
1545
1546 wxFileDialog dlg( this, wxString::Format( _( "Save Library '%s' As..." ), aLibrary ), default_path,
1547 fn.GetFullName(), wildcards, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1548
1549 SYMBOL_LIBRARY_SAVE_AS_FILEDLG_HOOK saveAsHook( type );
1550 dlg.SetCustomizeHook( saveAsHook );
1551
1553
1554 if( dlg.ShowModal() == wxID_CANCEL )
1555 return false;
1556
1557 fn = dlg.GetPath();
1558
1559 prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() );
1560
1561 if( fn.GetExt().IsEmpty() )
1563
1564 type = saveAsHook.GetOption();
1565 }
1566 else
1567 {
1568 std::optional<LIBRARY_TABLE_ROW*> optRow = adapter->GetRow( aLibrary );
1569 wxCHECK( optRow, false );
1570
1571 fn = LIBRARY_MANAGER::GetFullURI( *optRow, true );
1573
1574 if( fileType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1575 fileType = SCH_IO_MGR::SCH_KICAD;
1576 }
1577
1578 // Verify the user has write privileges before attempting to save the library file.
1579 if( !aNewFile && m_libMgr->IsLibraryReadOnly( aLibrary ) )
1580 return false;
1581
1582 ClearMsgPanel();
1583
1584 // Copy .kicad_symb file to .bak.
1585 if( !backupFile( fn, "bak" ) )
1586 return false;
1587
1588 if( !m_libMgr->SaveLibrary( aLibrary, fn.GetFullPath(), fileType ) )
1589 {
1590 msg.Printf( _( "Failed to save changes to symbol library file '%s'." ),
1591 fn.GetFullPath() );
1592 DisplayErrorMessage( this, _( "Error Saving Library" ), msg );
1593 return false;
1594 }
1595
1596 if( !aNewFile )
1597 {
1598 m_libMgr->ClearLibraryModified( aLibrary );
1599
1600 // Update the library modification time so that we don't reload based on the watcher
1601 if( aLibrary == getTargetLib() )
1602 SetSymModificationTime( fn.GetModificationTime() );
1603 }
1604 else
1605 {
1606 bool resyncLibTree = false;
1607 wxString originalLibNickname = getTargetLib();
1608 wxString forceRefresh;
1609
1610 switch( type )
1611 {
1613 resyncLibTree = replaceLibTableEntry( originalLibNickname, fn.GetFullPath() );
1614 forceRefresh = originalLibNickname;
1615 break;
1616
1618 resyncLibTree = addLibTableEntry( fn.GetFullPath() );
1619 break;
1620
1622 resyncLibTree = addLibTableEntry( fn.GetFullPath(), LIBRARY_TABLE_SCOPE::PROJECT );
1623 break;
1624
1625 default:
1626 break;
1627 }
1628
1629 if( resyncLibTree )
1630 {
1632 SyncLibraries( true, false, forceRefresh );
1634 }
1635 }
1636
1637 ClearMsgPanel();
1638 msg.Printf( _( "Symbol library file '%s' saved." ), fn.GetFullPath() );
1640
1641 return true;
1642}
1643
1644
1645bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
1646{
1647 wxString msg, msg2;
1648 bool doSave = true;
1649 int dirtyCount = 0;
1650 bool applyToAll = false;
1651 bool retv = true;
1652
1653 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1654 {
1655 if( m_libMgr->IsLibraryModified( libNickname ) )
1656 dirtyCount++;
1657 }
1658
1659 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1660 {
1661 if( m_libMgr->IsLibraryModified( libNickname ) )
1662 {
1663 if( aRequireConfirmation && !applyToAll )
1664 {
1665 msg.Printf( _( "Save changes to '%s' before closing?" ), libNickname );
1666
1667 switch( UnsavedChangesDialog( this, msg, dirtyCount > 1 ? &applyToAll : nullptr ) )
1668 {
1669 case wxID_YES: doSave = true; break;
1670 case wxID_NO: doSave = false; break;
1671 default:
1672 case wxID_CANCEL: return false;
1673 }
1674 }
1675
1676 if( doSave )
1677 {
1678 // If saving under existing name fails then do a Save As..., and if that
1679 // fails then cancel close action.
1680 if( m_libMgr->IsLibraryReadOnly( libNickname ) )
1681 {
1682 msg.Printf( _( "Symbol library '%s' is not writable." ), libNickname );
1683 msg2 = _( "You must save to a different location." );
1684
1685 if( dirtyCount == 1 )
1686 {
1687 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) != wxID_OK )
1688 {
1689 retv = false;
1690 continue;
1691 }
1692 }
1693 else
1694 {
1695 m_infoBar->Dismiss();
1696 m_infoBar->ShowMessageFor( msg + wxS( " " ) + msg2,
1697 2000, wxICON_EXCLAMATION );
1698
1699 while( m_infoBar->IsShownOnScreen() )
1700 wxSafeYield();
1701
1702 retv = false;
1703 continue;
1704 }
1705 }
1706 else if( saveLibrary( libNickname, false ) )
1707 {
1708 continue;
1709 }
1710
1711 if( !saveLibrary( libNickname, true ) )
1712 retv = false;
1713 }
1714 }
1715 }
1716
1717 UpdateTitle();
1718 return retv;
1719}
1720
1721
1723{
1725
1726 if( !m_symbol )
1727 return;
1728
1729 wxString msg = m_symbol->GetName();
1730
1731 AppendMsgPanel( _( "Name" ), UnescapeString( msg ), 8 );
1732
1733 if( m_symbol->IsDerived() )
1734 {
1735 std::shared_ptr<LIB_SYMBOL> parent = m_symbol->GetParent().lock();
1736
1737 msg = parent ? parent->GetName() : _( "Undefined!" );
1738 AppendMsgPanel( _( "Parent" ), UnescapeString( msg ), 8 );
1739 }
1740
1741 if( m_symbol->IsGlobalPower() )
1742 msg = _( "Power Symbol" );
1743 else if( m_symbol->IsLocalPower() )
1744 msg = _( "Power Symbol (Local)" );
1745 else
1746 msg = _( "Symbol" );
1747
1748 AppendMsgPanel( _( "Type" ), msg, 8 );
1749 AppendMsgPanel( _( "Description" ), m_symbol->GetDescription(), 8 );
1750 AppendMsgPanel( _( "Keywords" ), m_symbol->GetKeyWords() );
1751 AppendMsgPanel( _( "Datasheet" ), m_symbol->GetDatasheetField().GetText() );
1752}
const char * name
static TOOL_ACTION cancelInteractive
Definition actions.h:72
static TOOL_ACTION zoomFitScreen
Definition actions.h:142
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)
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:1572
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:83
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:152
bool UnitsLocked() const
Check whether symbol units are interchangeable.
Definition lib_symbol.h:287
bool IsDerived() const
Definition lib_symbol.h:203
LIB_ID GetSourceLibId() const
Definition lib_symbol.h:155
void SetParent(LIB_SYMBOL *aParent=nullptr)
wxString GetName() const override
Definition lib_symbol.h:145
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:332
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:92
bool IsMultiUnit() const override
Definition lib_symbol.h:770
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:134
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:65
@ SCH_LIB_PATH
Definition project.h:219
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:340
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:351
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.
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:116
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:422
const std::string & GetString()
Definition richio.h:445
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.
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
Definition confirm.h:52
#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:637
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
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:717
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.
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.