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