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