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>
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 <set>
46#include <wx/clipbrd.h>
47#include <wx/dirdlg.h>
48#include <wx/filedlg.h>
49#include <wx/log.h>
50#include <project_sch.h>
51#include <kiplatform/io.h>
52#include <kiplatform/ui.h>
53#include <string_utils.h>
54#include "symbol_saveas_type.h"
58
59
61{
62 SetTitle( _( "Symbol Editor" ) );
63}
64
65
67{
68 if( GetCurSymbol() )
69 {
71 {
72 SCH_EDIT_FRAME* schframe = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
73
74 if( !schframe ) // happens when the schematic editor has been closed
75 {
76 DisplayErrorMessage( this, _( "No schematic currently open." ) );
77 return false;
78 }
79 else
80 {
82 GetScreen()->SetContentModified( false );
83 return true;
84 }
85 }
86 else
87 {
88 const wxString& libName = GetCurSymbol()->GetLibId().GetLibNickname();
89
90 // A brand-new symbol has no library home yet, so its first save asks for one and
91 // promotes the unsaved tab to a library tab.
92 if( libName.IsEmpty() )
93 {
94 saveSymbolCopyAs( false );
95 return !GetScreen()->IsContentModified();
96 }
97
98 if( m_libMgr->IsLibraryReadOnly( libName ) )
99 {
100 wxString msg = wxString::Format( _( "Symbol library '%s' is not writable." ),
101 libName );
102 wxString msg2 = _( "You must save to a different location." );
103
104 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) == wxID_OK )
105 return saveLibrary( libName, SAVE_LIBRARY_AS::NEW );
106 }
107 else
108 {
109 return saveLibrary( libName, SAVE_LIBRARY_AS::ORIGINAL );
110 }
111 }
112 }
113
114 return false;
115}
116
117
118bool SYMBOL_EDIT_FRAME::LoadSymbol( const LIB_ID& aLibId, int aUnit, int aBodyStyle )
119{
120 LIB_ID libId = aLibId;
123
124 // Some libraries can't be edited, so load the underlying chosen symbol
125 if( auto optRow = manager.GetRow( LIBRARY_TABLE_TYPE::SYMBOL, aLibId.GetLibNickname() ); optRow.has_value() )
126 {
127 const LIBRARY_TABLE_ROW* row = *optRow;
128 SCH_IO_MGR::SCH_FILE_T type = SCH_IO_MGR::EnumFromStr( row->Type() );
129
130 if( type == SCH_IO_MGR::SCH_DATABASE
131 || type == SCH_IO_MGR::SCH_CADSTAR_ARCHIVE
132 || type == SCH_IO_MGR::SCH_HTTP )
133 {
134 try
135 {
136 LIB_SYMBOL* readOnlySym = adapter->LoadSymbol( aLibId );
137
138 if( readOnlySym && readOnlySym->GetSourceLibId().IsValid() )
139 libId = readOnlySym->GetSourceLibId();
140 }
141 catch( const IO_ERROR& ioe )
142 {
143 wxString msg;
144
145 msg.Printf( _( "Error loading symbol %s from library '%s'." ),
146 aLibId.GetUniStringLibId(),
147 aLibId.GetUniStringLibItemName() );
148 DisplayErrorMessage( this, msg, ioe.What() );
149 return false;
150 }
151 }
152 }
153
154 if( GetCurSymbol()
156 && GetCurSymbol()->GetLibId() == libId
157 && GetUnit() == aUnit
158 && GetBodyStyle() == aBodyStyle )
159 {
160 return true;
161 }
162
164 {
165 if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
166 [&]() -> bool
167 {
168 return saveCurrentSymbol();
169 } ) )
170 {
171 return false;
172 }
173 }
174
175 if( LoadSymbolFromLib( libId.GetLibNickname(), libId.GetLibItemName(), aUnit, aBodyStyle ) )
176 {
177 m_treePane->GetLibTree()->SelectLibId( libId );
178 m_treePane->GetLibTree()->ExpandLibId( libId );
179
180 m_centerItemOnIdle = libId;
181 Bind( wxEVT_IDLE, &SYMBOL_EDIT_FRAME::centerItemIdleHandler, this );
182 setSymWatcher( &libId );
183
184 return true;
185 }
186
187 return false;
188}
189
190
192{
193 m_treePane->GetLibTree()->CenterLibId( m_centerItemOnIdle );
194 Unbind( wxEVT_IDLE, &SYMBOL_EDIT_FRAME::centerItemIdleHandler, this );
195}
196
197
198bool SYMBOL_EDIT_FRAME::LoadSymbolFromLib( const wxString& aLibName, const wxString& aSymbolName, int aUnit,
199 int aBodyStyle )
200{
201 LIB_SYMBOL* symbol = nullptr;
202
203 try
204 {
205 symbol = PROJECT_SCH::SymbolLibAdapter( &Prj() )->LoadSymbol( aLibName, aSymbolName );
206 }
207 catch( const IO_ERROR& ioe )
208 {
209 wxString msg;
210
211 msg.Printf( _( "Error loading symbol %s from library '%s'." ),
212 UnescapeString( aSymbolName ),
213 UnescapeString( aLibName ) );
214 DisplayErrorMessage( this, msg, ioe.What() );
215 return false;
216 }
217
218 if( !symbol || !LoadOneLibrarySymbol( symbol, aLibName, aUnit, aBodyStyle ) )
219 return false;
220
222
224
225 return true;
226}
227
228
229bool SYMBOL_EDIT_FRAME::LoadOneLibrarySymbol( LIB_SYMBOL* aEntry, const wxString& aLibrary, int aUnit, int aBodyStyle )
230{
231 bool rebuildMenuAndToolbar = false;
232
233 if( !aEntry || aLibrary.empty() )
234 return false;
235
236 if( aEntry->GetName().IsEmpty() )
237 {
238 wxLogWarning( "Symbol in library '%s' has empty name field.", aLibrary );
239 return false;
240 }
241
243
244 // Switching away from a schematic-instance tab changes the available menu/toolbar actions. The
245 // instance tab keeps owning its working objects, so nothing is deleted here.
247 rebuildMenuAndToolbar = true;
248
249 LIB_SYMBOL* lib_symbol = m_libMgr->GetBufferedSymbol( aEntry->GetName(), aLibrary );
250 wxCHECK( lib_symbol, false );
251
252 m_unit = aUnit > 0 ? aUnit : 1;
253 m_bodyStyle = aBodyStyle > 0 ? aBodyStyle : 1;
254
255 // Open as a preview tab that the next library-open reuses until the symbol is edited.
256 bool wasCreated = false;
257 SYMBOL_EDITOR_TAB_CONTEXT* ctx = findOrCreateSymbolTab( aLibrary, lib_symbol->GetName(),
258 m_unit, m_bodyStyle, true,
259 &wasCreated );
260 wxCHECK( ctx, false );
261
262 if( rebuildMenuAndToolbar )
263 {
266 GetInfoBar()->Dismiss();
267 }
268
270
271 // Only a freshly-created tab gets a clean undo history; re-focusing preserves the live stack.
272 if( wasCreated )
274
275 if( !IsSymbolFromSchematic() )
276 {
277 LIB_ID libId = GetCurSymbol()->GetLibId();
278 setSymWatcher( &libId );
279 }
280
283
284 // Display the document information based on the entry selected just in
285 // case the entry is an alias.
287 Refresh();
288
289 return true;
290}
291
292
294{
295 saveAllLibraries( false );
296 m_treePane->GetLibTree()->RefreshLibTree();
297}
298
299
300void SYMBOL_EDIT_FRAME::CreateNewSymbol( const wxString& aInheritFrom )
301{
303
304 wxString lib = getTargetLib();
305
306 wxArrayString symbolNamesInLib;
307 wxArrayString derivedSymbols;
308
309 // With no target library there are no names to list or style; querying would create a bogus
310 // empty library buffer keyed by an empty nickname.
311 if( !lib.empty() )
312 {
313 m_libMgr->GetSymbolNames( lib, symbolNamesInLib, SYMBOL_NAME_FILTER::ALL );
314 m_libMgr->GetSymbolNames( lib, derivedSymbols, SYMBOL_NAME_FILTER::DERIVED_ONLY );
315 }
316
317 const auto validator =
318 [&]( wxString newName ) -> bool
319 {
320 if( newName.IsEmpty() )
321 {
322 wxMessageBox( _( "Symbol must have a name." ) );
323 return false;
324 }
325
326 if( !lib.empty() && m_libMgr->SymbolNameInUse( newName, lib ) )
327 {
328 wxString msg;
329
330 msg.Printf( _( "Symbol '%s' already exists in library '%s'." ),
331 UnescapeString( newName ),
332 lib );
333
334 KIDIALOG errorDlg( this, msg, _( "Confirmation" ),
335 wxOK | wxCANCEL | wxICON_WARNING );
336
337 errorDlg.SetOKLabel( _( "Overwrite" ) );
338
339 return errorDlg.ShowModal() == wxID_OK;
340 }
341
342 return true;
343 };
344
345 const auto styler =
346 [&]( const wxString& aItem ) -> int
347 {
348 for( wxString& candidate : derivedSymbols )
349 {
350 if( candidate.CmpNoCase( aItem ) == 0 )
351 return ITALIC;
352 }
353
354 return 0;
355 };
356
357 DIALOG_LIB_NEW_SYMBOL dlg( this, symbolNamesInLib, styler, aInheritFrom, validator );
358
359 dlg.SetMinSize( dlg.GetSize() );
360
361 if( dlg.ShowModal() == wxID_CANCEL )
362 return;
363
365
366 props.name = dlg.GetName();
368 props.reference = dlg.GetReference();
369 props.unitCount = dlg.GetUnitCount();
370 props.pinNameInside = dlg.GetPinNameInside();
372 props.powerSymbol = dlg.GetPowerSymbol();
373 props.showPinNumber = dlg.GetShowPinNumber();
374 props.showPinName = dlg.GetShowPinName();
376 props.includeInBom = dlg.GetIncludeInBom();
377 props.includeOnBoard = dlg.GetIncludeOnBoard();
379 props.keepFootprint = dlg.GetKeepFootprint();
380 props.keepDatasheet = dlg.GetKeepDatasheet();
383
384 if( lib.empty() )
385 {
386 // No library home yet: edit the new symbol in an unsaved tab and let the first save
387 // (which asks for a library) promote the tab. With no target library there is no source
388 // for a parent symbol, so the dialog's inheritance combo is empty and the symbol is a root.
389 std::unique_ptr<LIB_SYMBOL> newSymbol = LIB_SYMBOL_LIBRARY_MANAGER::CreateSymbol( props, nullptr );
390
391 SCH_SCREEN* screen = new SCH_SCREEN();
392 CreateUnsavedSymbolTab( newSymbol.release(), screen );
393
396 OnModify();
397 return;
398 }
399
400 m_libMgr->CreateNewSymbol( lib, props );
401 SyncLibraries( false );
402 LoadSymbol( props.name, lib, 1 );
403}
404
405
407{
408 wxString libName;
409
410 if( m_activeTab && m_activeTab->IsUnsaved() )
411 {
413 }
414 else
415 {
416 if( IsLibraryTreeShown() )
418
419 if( libName.empty() )
420 {
422 }
423 else if( m_libMgr->IsLibraryReadOnly( libName ) )
424 {
425 wxString msg = wxString::Format( _( "Symbol library '%s' is not writable." ),
426 libName );
427 wxString msg2 = _( "You must save to a different location." );
428
429 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) == wxID_OK )
431 }
432 else
433 {
435 }
436 }
437
438 if( IsLibraryTreeShown() )
439 m_treePane->GetLibTree()->RefreshLibTree();
440}
441
442
444{
445 const wxString& libName = GetTargetLibId().GetLibNickname();
446
447 if( !libName.IsEmpty() )
448 {
449 saveLibrary( libName, aSaveAsType );
450 m_treePane->GetLibTree()->RefreshLibTree();
451 }
452}
453
454
456{
457 saveSymbolCopyAs( aOpenCopy );
458
459 m_treePane->GetLibTree()->RefreshLibTree();
460}
461
462
472static std::vector<std::shared_ptr<LIB_SYMBOL>> GetParentChain( const LIB_SYMBOL& aSymbol, bool aIncludeLeaf = true )
473{
474 std::vector<std::shared_ptr<LIB_SYMBOL>> chain;
475 std::shared_ptr<LIB_SYMBOL> sym = aSymbol.SharedPtr();
476
477 if( aIncludeLeaf )
478 chain.push_back( sym );
479
480 while( sym->IsDerived() )
481 {
482 std::shared_ptr<LIB_SYMBOL> parent = sym->GetParent().lock();
483
484 // A symbol can report itself as derived while its parent pointer has already expired.
485 // Stop walking rather than push a null entry and dereference it on the next iteration.
486 if( !parent )
487 break;
488
489 chain.push_back( parent );
490 sym = parent;
491 }
492
493 return chain;
494}
495
496
506static std::pair<bool, bool> CheckSavingIntoOwnInheritance( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr,
507 LIB_SYMBOL& aSymbol,
508 const wxString& aNewSymbolName,
509 const wxString& aNewLibraryName )
510{
511 const wxString& oldLibraryName = aSymbol.GetLibId().GetLibNickname();
512
513 // Cannot be intersecting if in different libs
514 if( aNewLibraryName != oldLibraryName )
515 return { false, false };
516
517 // Or if the target symbol doesn't exist
518 if( !aLibMgr.SymbolNameInUse( aNewSymbolName, aNewLibraryName ) )
519 return { false, false };
520
521 bool inAncestry = false;
522 bool inDescendents = false;
523
524 {
525 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChainFromUs = GetParentChain( aSymbol, true );
526
527 // Ignore the leaf symbol (0) - that must match
528 for( size_t i = 1; i < parentChainFromUs.size(); ++i )
529 {
530 // Attempting to overwrite a symbol in the parental chain
531 if( parentChainFromUs[i]->GetName() == aNewSymbolName )
532 {
533 inAncestry = true;
534 break;
535 }
536 }
537 }
538
539 {
540 LIB_SYMBOL* targetSymbol = aLibMgr.GetSymbol( aNewSymbolName, aNewLibraryName );
541 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChainFromTarget = GetParentChain( *targetSymbol, true );
542 const wxString oldSymbolName = aSymbol.GetName();
543
544 // Ignore the leaf symbol - it'll match if we're saving the symbol
545 // to the same name, and that would be OK
546 for( size_t i = 1; i < parentChainFromTarget.size(); ++i )
547 {
548 if( parentChainFromTarget[i]->GetName() == oldSymbolName )
549 {
550 inDescendents = true;
551 break;
552 }
553 }
554 }
555
556 return { inAncestry, inDescendents };
557}
558
559
567static std::vector<wxString> CheckForParentalChainConflicts( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr,
568 LIB_SYMBOL& aSymbol,
569 bool aFlattenSymbol,
570 const wxString& newSymbolName,
571 const wxString& newLibraryName )
572{
573 std::vector<wxString> conflicts;
574 const wxString& oldLibraryName = aSymbol.GetLibId().GetLibNickname();
575
576 if( newLibraryName == oldLibraryName || aFlattenSymbol )
577 {
578 // Saving into the same library - the only conflict could be the symbol itself
579 // Different library and flattening - ditto
580 if( aLibMgr.SymbolNameInUse( newSymbolName, newLibraryName ) )
581 conflicts.push_back( newSymbolName );
582 }
583 else
584 {
585 // In a different library with parents - check the whole chain
586 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain = GetParentChain( aSymbol, true );
587
588 for( size_t i = 0; i < parentChain.size(); ++i )
589 {
590 if( i == 0 )
591 {
592 // This is the leaf symbol which the user actually named
593 if( aLibMgr.SymbolNameInUse( newSymbolName, newLibraryName ) )
594 conflicts.push_back( newSymbolName );
595 }
596 else
597 {
598 std::shared_ptr<LIB_SYMBOL> chainSymbol = parentChain[i];
599
600 if( aLibMgr.SymbolNameInUse( chainSymbol->GetName(), newLibraryName ) )
601 conflicts.push_back( chainSymbol->GetName() );
602 }
603 }
604 }
605
606 return conflicts;
607}
608
609
617{
618public:
620 {
621 // Just overwrite any existing symbols in the target library
623 // Add a suffix until we find a name that doesn't conflict
625 // Could have a mode that asks for every one, be then we'll need a fancier
626 // SAVE_SYMBOL_AS_DIALOG subdialog with Overwrite/Rename/Prompt/Cancel
627 // PROMPT
628 };
629
630 SYMBOL_SAVE_AS_HANDLER( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr, CONFLICT_STRATEGY aStrategy, bool aValueFollowsName ) :
631 m_libMgr( aLibMgr ),
632 m_strategy( aStrategy ),
633 m_valueFollowsName( aValueFollowsName )
634 {
635 }
636
637 bool DoSave( LIB_SYMBOL& symbol, const wxString& aNewSymName, const wxString& aNewLibName, bool aFlattenSymbol )
638 {
639 std::unique_ptr<LIB_SYMBOL> flattenedSymbol; // for ownership
640 std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain;
641
642 const bool sameLib = aNewLibName == symbol.GetLibId().GetLibNickname().wx_str();
643
644 if( aFlattenSymbol )
645 {
646 // If we're not copying parent symbols, we need to flatten the symbol
647 // and only save that.
648 flattenedSymbol = symbol.Flatten();
649 wxCHECK( flattenedSymbol, false );
650
651 parentChain.push_back( flattenedSymbol->SharedPtr() );
652 }
653 else if( sameLib )
654 {
655 // If we're saving into the same library, we don't need to check the parental chain
656 // because we can just keep the same parent symbol
657 parentChain.push_back( symbol.SharedPtr() );
658 }
659 else
660 {
661 // Need to copy all parent symbols
662 parentChain = GetParentChain( symbol, true );
663 }
664
665 std::vector<wxString> newNames;
666
667 // Iterate backwards (i.e. from the root down)
668 for( int i = (int) parentChain.size() - 1; i >= 0; --i )
669 {
670 std::shared_ptr<LIB_SYMBOL>& oldSymbol = parentChain[i];
671 LIB_SYMBOL new_symbol( *oldSymbol );
672
673 wxString newName;
674 if( i == 0 )
675 {
676 // This is the leaf symbol which the user actually named
677 newName = aNewSymName;
678 }
679 else
680 {
681 // Somewhere in the inheritance chain, use the conflict resolution strategy
682 newName = oldSymbol->GetName();
683 }
684
685 newName = resolveConflict( newName, aNewLibName );
686 new_symbol.SetName( newName );
687
689 new_symbol.GetValueField().SetText( newName );
690
691 if( i == (int) parentChain.size() - 1 )
692 {
693 // This is the root symbol
694 // Nothing extra to do, it's just a simple symbol with no parents
695 }
696 else
697 {
698 // Get the buffered new copy in the new library (with the name we gave it)
699 LIB_SYMBOL* newParent = m_libMgr.GetSymbol( newNames.back(), aNewLibName );
700
701 // We should have stored this already, why didn't we get it back?
702 wxASSERT( newParent );
703 new_symbol.SetParent( newParent );
704
705 // Keep the recorded parent name in sync with the (possibly renamed) buffered
706 // parent so serialization has a valid fallback if the live pointer is lost.
707 if( newParent )
708 new_symbol.SetParentName( newParent->GetName() );
709 }
710
711 newNames.push_back( newName );
712 m_libMgr.UpdateSymbol( &new_symbol, aNewLibName );
713 }
714
715 return true;
716 }
717
718private:
719 wxString resolveConflict( const wxString& proposed, const wxString& aNewLibName ) const
720 {
721 switch( m_strategy )
722 {
724 {
725 // In an overwrite strategy, we don't care about conflicts
726 return proposed;
727 }
729 {
730 // In a rename strategy, we need to find a name that doesn't conflict
731 int suffix = 1;
732
733 while( true )
734 {
735 wxString newName = wxString::Format( "%s_%d", proposed, suffix );
736
737 if( !m_libMgr.SymbolNameInUse( newName, aNewLibName ) )
738 return newName;
739
740 ++suffix;
741 }
742 break;
743 }
744 // No default
745 }
746
747 wxFAIL_MSG( "Invalid conflict strategy" );
748 return "";
749 }
750
754};
755
756
763
764
766{
767public:
768 using SymLibNameValidator = std::function<int( const wxString& libName, const wxString& symbolName )>;
769
777
779 PARAMS& aParams,
780 SymLibNameValidator aValidator,
781 const std::vector<wxString>& aParentSymbolNames ) :
782 EDA_LIST_DIALOG( aParent, _( "Save Symbol As" ), false ),
783 m_validator( std::move( aValidator ) ),
784 m_params( aParams )
785 {
786 wxArrayString headers;
787 std::vector<wxArrayString> itemsToDisplay;
788
789 if( aParentSymbolNames.size() )
790 {
791 // This is a little trick to word - when saving to another library, "copy parents" makes sense,
792 // but when in the same library, the parents will be untouched in any case.
793 const wxString aParentNames = AccumulateDescriptions( aParentSymbolNames );
794 AddExtraCheckbox(
795 wxString::Format( "Flatten/remove symbol inheritance (current parent symbols: %s)", aParentNames ),
796 &m_params.m_FlattenSymbol );
797 }
798
799 aParent->GetLibraryItemsForListDialog( headers, itemsToDisplay );
800 initDialog( headers, itemsToDisplay, m_params.m_LibraryName );
801
802 SetListLabel( _( "Save in library:" ) );
803 SetOKLabel( _( "Save" ) );
804
805 wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
806
807 wxStaticText* label = new wxStaticText( this, wxID_ANY, _( "Name:" ) );
808 bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
809
810 m_symbolNameCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString );
811 bNameSizer->Add( m_symbolNameCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
812
813 wxButton* newLibraryButton = new wxButton( this, ID_MAKE_NEW_LIBRARY, _( "New Library..." ) );
814 m_ButtonsSizer->Prepend( 80, 20 );
815 m_ButtonsSizer->Prepend( newLibraryButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 );
816
817 GetSizer()->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
818
819 Bind( wxEVT_BUTTON,
820 [this]( wxCommandEvent& )
821 {
822 EndModal( ID_MAKE_NEW_LIBRARY );
824
825 // Move nameTextCtrl to the head of the tab-order
826 if( GetChildren().DeleteObject( m_symbolNameCtrl ) )
827 GetChildren().Insert( m_symbolNameCtrl );
828
830
832
833 Layout();
834 GetSizer()->Fit( this );
835
836 Centre();
837 }
838
839protected:
840 wxString getSymbolName() const
841 {
842 wxString symbolName = m_symbolNameCtrl->GetValue();
843 symbolName.Trim( true );
844 symbolName.Trim( false );
845 symbolName.Replace( " ", "_" );
846 return EscapeString( symbolName, CTX_LIBID );
847 }
848
849 bool TransferDataToWindow() override
850 {
851 m_symbolNameCtrl->SetValue( UnescapeString( m_params.m_SymbolName ) );
852 return true;
853 }
854
856 {
857 // This updates m_params.m_FlattenSymbol
858 // Do this now, so the validator can use it
860
861 m_params.m_SymbolName = getSymbolName();
862 m_params.m_LibraryName = GetTextSelection();
863
864 int ret = m_validator( m_params.m_LibraryName, m_params.m_SymbolName );
865
866 if( ret == wxID_CANCEL )
867 return false;
868
869 if( ret == ID_OVERWRITE_CONFLICTS )
871 else if( ret == ID_RENAME_CONFLICTS )
873
874 return true;
875 }
876
877private:
878 wxTextCtrl* m_symbolNameCtrl;
881};
882
883
885{
886 LIB_SYMBOL* symbol = getTargetSymbol();
887
888 if( !symbol )
889 return;
890
891 const bool savingUnsavedTab = m_activeTab && m_activeTab->IsUnsaved() && symbol == m_symbol;
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
1005 if( symbol->IsDerived() )
1006 {
1007 // The parents are everything but the leaf symbol
1008 std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain = GetParentChain( *symbol, false );
1009
1010 for( const std::shared_ptr<LIB_SYMBOL>& parent : parentChain )
1011 parentSymbolNames.push_back( parent->GetName() );
1012 }
1013
1015 symbolName,
1016 libraryName,
1017 flattenSymbol,
1018 strategy,
1019 };
1020
1021 // Keep asking the user for a new name until they give a valid one or cancel the operation
1022 while( !done )
1023 {
1024 SAVE_SYMBOL_AS_DIALOG dlg( this, params, dialogValidatorFunc, parentSymbolNames );
1025
1026 int ret = dlg.ShowModal();
1027
1028 switch( ret )
1029 {
1030 case wxID_CANCEL:
1031 // A cancelled save leaves the unsaved tab dirty so the user is re-prompted later.
1032 return;
1033
1034 case wxID_OK: // No conflicts
1037 {
1038 done = true;
1039 break;
1040 }
1042 {
1043 wxFileName newLibrary( AddLibraryFile( true ) );
1044 params.m_LibraryName = newLibrary.GetName();
1045
1046 // Go round again to ask for the symbol name
1047 break;
1048 }
1049
1050 default:
1051 break;
1052 }
1053 }
1054
1055 SYMBOL_SAVE_AS_HANDLER saver( *m_libMgr, params.m_ConflictStrategy, valueFollowsName );
1056
1057 saver.DoSave( *symbol, params.m_SymbolName, params.m_LibraryName, params.m_FlattenSymbol );
1058
1059 SyncLibraries( false );
1060
1061 if( savingUnsavedTab )
1062 {
1063 symbol->SetLibId( LIB_ID( params.m_LibraryName, params.m_SymbolName ) );
1064
1065 RenameSymbolTab( LIB_ID( wxEmptyString, symbolName ), LIB_ID( params.m_LibraryName, params.m_SymbolName ) );
1066
1067 GetScreen()->SetContentModified( false );
1068
1069 if( int idx = m_tabsPanel->FindTab( m_activeTab->GetTabKey() ); idx >= 0 )
1070 m_tabsPanel->MarkModified( idx, false );
1071 }
1072 else
1073 {
1074 RenameSymbolTab( LIB_ID( libraryName, symbolName ), LIB_ID( params.m_LibraryName, params.m_SymbolName ) );
1075 }
1076
1077 if( aOpenCopy )
1078 LoadSymbol( params.m_SymbolName, params.m_LibraryName, 1 );
1079}
1080
1081
1083{
1084 wxString msg;
1085 LIB_SYMBOL* symbol = getTargetSymbol();
1086
1087 if( !symbol )
1088 {
1089 ShowInfoBarError( _( "There is no symbol selected to save." ) );
1090 return;
1091 }
1092
1093 wxFileName fn;
1094
1095 fn.SetName( symbol->GetName().Lower() );
1097
1098 wxFileDialog dlg( this, _( "Export Symbol" ), m_mruPath, fn.GetFullName(),
1100
1102
1103 if( dlg.ShowModal() == wxID_CANCEL )
1104 return;
1105
1107
1108 fn = dlg.GetPath();
1109 fn.MakeAbsolute();
1110
1111 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
1112
1113 wxString libraryName;
1114 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = symbol->Flatten();
1115
1116 for( const wxString& candidate : m_libMgr->GetLibraryNames() )
1117 {
1118 if( auto uri = manager.GetFullURI( LIBRARY_TABLE_TYPE::SYMBOL, candidate, true ); uri )
1119 {
1120 if( *uri == fn.GetFullPath() )
1121 libraryName = candidate;
1122 }
1123 }
1124
1125 if( !libraryName.IsEmpty() )
1126 {
1127 SYMBOL_SAVE_AS_HANDLER saver( *m_libMgr, strategy, false );
1128
1129 if( m_libMgr->IsLibraryReadOnly( libraryName ) )
1130 {
1131 msg = wxString::Format( _( "Library '%s' is read-only." ), libraryName );
1132 DisplayError( this, msg );
1133 return;
1134 }
1135
1136 if( m_libMgr->SymbolNameInUse( symbol->GetName(), libraryName ) )
1137 {
1138 msg = wxString::Format( _( "Symbol '%s' already exists in library '%s'." ),
1139 symbol->GetName(), libraryName );
1140
1141 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1142 errorDlg.SetOKLabel( _( "Overwrite" ) );
1143 errorDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1144
1145 if( errorDlg.ShowModal() == wxID_CANCEL )
1146 return;
1147 }
1148
1149 saver.DoSave( *flattenedSymbol, symbol->GetName(), libraryName, false );
1150
1151 SyncLibraries( false );
1152 return;
1153 }
1154
1155 LIB_SYMBOL* old_symbol = nullptr;
1156 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() );
1157
1158 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1159 pluginType = SCH_IO_MGR::SCH_KICAD;
1160
1161 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pluginType ) );
1162
1163 if( fn.FileExists() )
1164 {
1165 try
1166 {
1167 old_symbol = pi->LoadSymbol( fn.GetFullPath(), symbol->GetName() );
1168 }
1169 catch( const IO_ERROR& ioe )
1170 {
1171 msg.Printf( _( "Error occurred attempting to load symbol library file '%s'." ),
1172 fn.GetFullPath() );
1173 DisplayErrorMessage( this, msg, ioe.What() );
1174 return;
1175 }
1176
1177 if( old_symbol )
1178 {
1179 msg.Printf( _( "Symbol %s already exists in library '%s'." ),
1180 UnescapeString( symbol->GetName() ),
1181 fn.GetFullName() );
1182
1183 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1184 errorDlg.SetOKLabel( _( "Overwrite" ) );
1185 errorDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1186
1187 if( errorDlg.ShowModal() == wxID_CANCEL )
1188 return;
1189 }
1190 }
1191
1192 if( !fn.IsDirWritable() )
1193 {
1194 msg.Printf( _( "Insufficient permissions to save library '%s'." ), fn.GetFullPath() );
1195 DisplayError( this, msg );
1196 return;
1197 }
1198
1199 try
1200 {
1201 if( !fn.FileExists() )
1202 pi->CreateLibrary( fn.GetFullPath() );
1203
1204 // The flattened symbol is most likely what the user would want. As some point in
1205 // the future as more of the symbol library inheritance is implemented, this may have
1206 // to be changes to save symbols of inherited symbols.
1207 pi->SaveSymbol( fn.GetFullPath(), std::move( flattenedSymbol ) );
1208 }
1209 catch( const IO_ERROR& ioe )
1210 {
1211 msg.Printf( _( "Failed to create symbol library file '%s'." ), fn.GetFullPath() );
1212 DisplayErrorMessage( this, msg, ioe.What() );
1213 msg.Printf( _( "Error creating symbol library '%s'." ), fn.GetFullName() );
1214 SetStatusText( msg );
1215 return;
1216 }
1217
1218 m_mruPath = fn.GetPath();
1219
1220 msg.Printf( _( "Symbol %s saved to library '%s'." ),
1221 UnescapeString( symbol->GetName() ),
1222 fn.GetFullPath() );
1223 SetStatusText( msg );
1224}
1225
1226
1228{
1229 wxCHECK( m_symbol, /* void */ );
1230
1231 wxString lib;
1232
1233 if( !IsSymbolFromSchematic() )
1234 lib = m_symbol->GetLibNickname();
1235
1236 if( !lib.IsEmpty() && aOldName && *aOldName != m_symbol->GetName() )
1237 {
1238 // Test the current library for name conflicts
1239 if( m_libMgr->SymbolNameInUse( m_symbol->GetName(), lib ) )
1240 {
1241 wxString msg = wxString::Format( _( "Symbol name '%s' already in use." ),
1242 UnescapeString( m_symbol->GetName() ) );
1243
1244 DisplayErrorMessage( this, msg );
1245 m_symbol->SetName( *aOldName );
1246 }
1247 else
1248 {
1249 m_libMgr->UpdateSymbolAfterRename( m_symbol, *aOldName, lib );
1250 }
1251
1252 // Reselect the renamed symbol
1253 m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, m_symbol->GetName() ) );
1254 }
1255
1256 wxDataViewItem treeItem = m_libMgr->GetAdapter()->FindItem( LIB_ID( lib, m_symbol->GetName() ) );
1257
1258 if( treeItem.IsOk() )
1259 UpdateLibraryTree( treeItem, m_symbol );
1260
1262
1263 if( aOldName )
1264 RenameSymbolTab( LIB_ID( lib, *aOldName ), m_symbol->GetLibId() );
1265
1266 // N.B. The view needs to be rebuilt first as the Symbol Properties change may invalidate
1267 // the view pointers by rebuilting the field table
1268 RebuildView();
1270
1271 OnModify();
1272}
1273
1274
1276{
1277 std::vector<LIB_ID> toDelete = GetSelectedLibIds();
1278
1279 if( toDelete.empty() )
1280 toDelete.emplace_back( GetTargetLibId() );
1281
1282 // A derived symbol selected together with its base is already gone once the base is removed
1283 std::set<LIB_ID> removedWithBase;
1284
1285 for( LIB_ID& libId : toDelete )
1286 {
1287 if( removedWithBase.count( libId ) )
1288 continue;
1289
1290 if( m_libMgr->IsSymbolModified( libId.GetLibItemName(), libId.GetLibNickname() )
1291 && !IsOK( this, wxString::Format( _( "The symbol '%s' has been modified.\n"
1292 "Do you want to remove it from the library?" ),
1293 libId.GetUniStringLibItemName() ) ) )
1294 {
1295 continue;
1296 }
1297
1298 wxArrayString derived;
1299
1300 if( m_libMgr->GetDerivedSymbolNames( libId.GetLibItemName(), libId.GetLibNickname(), derived ) > 0 )
1301 {
1302 wxString msg = _( "Deleting a base symbol will delete all symbols derived from it.\n\n" );
1303
1304 msg += libId.GetLibItemName().wx_str() + _( " (base)\n" );
1305
1306 for( const wxString& name : derived )
1307 msg += name + wxT( "\n" );
1308
1309 KICAD_MESSAGE_DIALOG dlg( this, msg, _( "Warning" ), wxYES_NO | wxICON_WARNING | wxCENTER );
1310 dlg.SetExtendedMessage( wxT( " " ) );
1311 dlg.SetYesNoLabels( _( "Delete All Listed Symbols" ), _( "Cancel" ) );
1312
1313 if( dlg.ShowModal() == wxID_NO )
1314 continue;
1315 }
1316
1317 if( m_tabsPanel )
1318 {
1319 // Close only the tabs for the symbol being deleted and the symbols derived from it,
1320 // which are removed along with it. The other open tabs stay put.
1321 closeSymbolTab( libId );
1322
1323 for( const wxString& derivedName : derived )
1324 closeSymbolTab( LIB_ID( libId.GetLibNickname().wx_str(), derivedName ) );
1325 }
1326 else if( GetCurSymbol() )
1327 {
1328 for( const std::shared_ptr<LIB_SYMBOL>& symbol : GetParentChain( *GetCurSymbol() ) )
1329 {
1330 if( symbol->GetLibId() == libId )
1331 {
1332 emptyScreen();
1333 break;
1334 }
1335 }
1336 }
1337
1338 m_libMgr->RemoveSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1339
1340 for( const wxString& derivedName : derived )
1341 removedWithBase.emplace( libId.GetLibNickname().wx_str(), derivedName );
1342 }
1343
1344 m_treePane->GetLibTree()->RefreshLibTree();
1345}
1346
1347
1349{
1350 std::vector<LIB_ID> symbols;
1351
1352 if( GetTreeLIBIDs( symbols ) == 0 )
1353 return;
1354
1355 STRING_FORMATTER formatter;
1356
1357 for( LIB_ID& libId : symbols )
1358 {
1359 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(),
1360 libId.GetLibNickname() );
1361
1362 if( !symbol )
1363 continue;
1364
1365 std::unique_ptr<LIB_SYMBOL> tmp = symbol->Flatten();
1366 SCH_IO_KICAD_SEXPR::FormatLibSymbol( tmp.get(), formatter );
1367 }
1368
1369 std::string prettyData = formatter.GetString();
1370 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES );
1371
1372 wxLogNull doNotLog; // disable logging of failed clipboard actions
1373
1374 auto clipboard = wxTheClipboard;
1375 wxClipboardLocker clipboardLock( clipboard );
1376
1377 if( !clipboardLock || !clipboard->IsOpened() )
1378 return;
1379
1380 auto data = new wxTextDataObject( wxString( prettyData.c_str(), wxConvUTF8 ) );
1381 clipboard->SetData( data );
1382
1383 clipboard->Flush();
1384}
1385
1386
1387void SYMBOL_EDIT_FRAME::DuplicateSymbol( bool aFromClipboard )
1388{
1389 LIB_ID libId = GetTargetLibId();
1390 wxString lib = libId.GetLibNickname();
1391
1392 if( !m_libMgr->LibraryExists( lib ) )
1393 return;
1394
1395 std::vector<LIB_SYMBOL*> newSymbols;
1396
1397 if( aFromClipboard )
1398 {
1399 std::string clipboardData = GetClipboardUTF8();
1400
1401 try
1402 {
1403 newSymbols = SCH_IO_KICAD_SEXPR::ParseLibSymbols( clipboardData, "Clipboard" );
1404 }
1405 catch( IO_ERROR& e )
1406 {
1407 wxLogMessage( wxS( "Can not paste: %s" ), e.Problem() );
1408 }
1409 }
1410 else if( LIB_SYMBOL* srcSymbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(), lib ) )
1411 {
1412 newSymbols.emplace_back( new LIB_SYMBOL( *srcSymbol ) );
1413
1414 // Derive from same parent.
1415 if( srcSymbol->IsDerived() )
1416 {
1417 if( std::shared_ptr<LIB_SYMBOL> srcParent = srcSymbol->GetParent().lock() )
1418 newSymbols.back()->SetParent( srcParent.get() );
1419 }
1420 }
1421
1422 if( newSymbols.empty() )
1423 return;
1424
1425 for( LIB_SYMBOL* symbol : newSymbols )
1426 {
1427 ensureUniqueName( symbol, lib );
1428 m_libMgr->UpdateSymbol( symbol, lib );
1429
1430 LoadOneLibrarySymbol( symbol, lib, GetUnit(), GetBodyStyle() );
1431 }
1432
1433 SyncLibraries( false );
1434 m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newSymbols[0]->GetName() ) );
1435
1436 for( LIB_SYMBOL* symbol : newSymbols )
1437 delete symbol;
1438}
1439
1440
1441void SYMBOL_EDIT_FRAME::ensureUniqueName( LIB_SYMBOL* aSymbol, const wxString& aLibrary )
1442{
1443 if( aSymbol )
1444 {
1445 int i = 1;
1446 wxString newName = aSymbol->GetName();
1447
1448 // Append a number to the name until the name is unique in the library.
1449 while( m_libMgr->SymbolNameInUse( newName, aLibrary ) )
1450 newName.Printf( "%s_%d", aSymbol->GetName(), i++ );
1451
1452 aSymbol->SetName( newName );
1453 }
1454}
1455
1456
1457void SYMBOL_EDIT_FRAME::Revert( LIB_ID& aTarget, bool aConfirm )
1458{
1459 const wxString& libName = aTarget.GetLibNickname();
1460
1461 // Empty if this is the library itself that is selected.
1462 const wxString& symbolName = aTarget.GetLibItemName();
1463
1464 wxString msg = wxString::Format( _( "Revert '%s' to last version saved?" ),
1465 symbolName.IsEmpty() ? libName : symbolName );
1466
1467 if( aConfirm && !ConfirmRevertDialog( this, msg ) )
1468 return;
1469
1470 bool reload_currentSymbol = false;
1471 wxString curr_symbolName = symbolName;
1472
1473 if( GetCurSymbol() )
1474 {
1475 // the library itself is reverted: the current symbol will be reloaded only if it is
1476 // owned by this library
1477 if( symbolName.IsEmpty() )
1478 {
1479 LIB_ID curr_libId = GetCurSymbol()->GetLibId();
1480 reload_currentSymbol = libName == curr_libId.GetLibNickname().wx_str();
1481
1482 if( reload_currentSymbol )
1483 curr_symbolName = curr_libId.GetUniStringLibItemName();
1484 }
1485 else
1486 {
1487 reload_currentSymbol = IsCurrentSymbol( aTarget );
1488 }
1489 }
1490
1491 int unit = m_unit;
1492
1493 if( reload_currentSymbol )
1494 emptyScreen();
1495
1496 if( symbolName.IsEmpty() )
1497 {
1498 m_libMgr->RevertLibrary( libName );
1499 }
1500 else
1501 {
1502 aTarget = m_libMgr->RevertSymbol( aTarget );
1503
1504 m_treePane->GetLibTree()->SelectLibId( aTarget );
1505 m_libMgr->ClearSymbolModified( aTarget.GetLibItemName(), aTarget.GetLibNickname() );
1506 }
1507
1508 if( reload_currentSymbol && m_libMgr->SymbolExists( curr_symbolName, libName ) )
1509 LoadSymbol( curr_symbolName, libName, unit );
1510
1511 m_treePane->Refresh();
1512}
1513
1514
1516{
1517 wxCHECK_RET( m_libMgr, "Library manager object not created." );
1518
1519 LIB_ID target = GetTargetLibId();
1520 Revert( target, false );
1521 m_libMgr->RevertAll();
1522}
1523
1524
1525void SYMBOL_EDIT_FRAME::LoadSymbol( const wxString& aAlias, const wxString& aLibrary, int aUnit )
1526{
1528 {
1529 if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
1530 [&]() -> bool
1531 {
1532 return saveCurrentSymbol();
1533 } ) )
1534 {
1535 return;
1536 }
1537 }
1538
1539 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( aAlias, aLibrary );
1540
1541 if( !symbol )
1542 {
1543 DisplayError( this, wxString::Format( _( "Symbol %s not found in library '%s'." ),
1544 aAlias,
1545 aLibrary ) );
1546 m_treePane->GetLibTree()->RefreshLibTree();
1547 return;
1548 }
1549
1550 // Optimize default edit options for this symbol
1551 // Usually if units are locked, graphic items are specific to each unit
1552 // and if units are interchangeable, graphic items are common to units
1553 SetDrawSpecificUnit( symbol->UnitsLocked() );
1554
1555 LoadOneLibrarySymbol( symbol, aLibrary, aUnit, 0 );
1556}
1557
1558
1559bool SYMBOL_EDIT_FRAME::saveLibrary( const wxString& aLibrary, SAVE_LIBRARY_AS aSaveType )
1560{
1561 wxFileName fn;
1562 wxString msg;
1564 SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::SCH_FILE_T::SCH_KICAD;
1565 PROJECT& prj = Prj();
1566
1568
1570
1571 wxCHECK( adapter, false );
1572
1573 if( ( aSaveType == SAVE_LIBRARY_AS::ORIGINAL ) && ( aLibrary.empty() || !adapter->HasLibrary( aLibrary ) ) )
1574 {
1575 ShowInfoBarError( _( "No library specified." ) );
1576 return false;
1577 }
1578
1579 bool newPackedLibrary = ( ( aSaveType == SAVE_LIBRARY_AS::ORIGINAL ) && wxFileName::FileExists( aLibrary ) ) ||
1580 ( aSaveType == SAVE_LIBRARY_AS::PACKED );
1581
1582 bool newUnpackedLibrary = ( ( aSaveType == SAVE_LIBRARY_AS::ORIGINAL ) && wxFileName::DirExists( aLibrary ) ) ||
1583 ( aSaveType == SAVE_LIBRARY_AS::UNPACKED );
1584
1585 if( newPackedLibrary )
1586 {
1587 SEARCH_STACK* search = PROJECT_SCH::SchSearchS( &prj );
1588
1589 // Get a new name for the library
1590 wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
1591
1592 if( !default_path )
1593 default_path = search->LastVisitedPath();
1594
1595 fn.SetName( aLibrary );
1597
1598 wxString wildcards = FILEEXT::KiCadSymbolLibFileWildcard();
1599 wxString dlgPrompt;
1600
1601 if( aSaveType == SAVE_LIBRARY_AS::ORIGINAL )
1602 dlgPrompt.Printf( _( "Save Library '%s' As..." ), aLibrary );
1603 else
1604 dlgPrompt.Printf( _( "Save Library '%s' As Packed Library..." ), aLibrary );
1605
1606 wxFileDialog dlg( this, dlgPrompt, default_path, fn.GetFullName(), wildcards,
1607 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1608
1609 SYMBOL_LIBRARY_SAVE_AS_FILEDLG_HOOK saveAsHook( type );
1610 dlg.SetCustomizeHook( saveAsHook );
1611
1613
1614 if( dlg.ShowModal() == wxID_CANCEL )
1615 return false;
1616
1617 fn = dlg.GetPath();
1618
1619 prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() );
1620
1621 if( fn.GetExt().IsEmpty() )
1623
1624 type = saveAsHook.GetOption();
1625 }
1626 else if( newUnpackedLibrary )
1627 {
1628 SEARCH_STACK* search = PROJECT_SCH::SchSearchS( &prj );
1629
1630 // Get a new name for the library
1631 wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
1632
1633 if( !default_path )
1634 default_path = search->LastVisitedPath();
1635
1636 wxString dlgPrompt;
1637
1638 if( aSaveType == SAVE_LIBRARY_AS::ORIGINAL )
1639 dlgPrompt.Printf( _( "Save Library '%s' As..." ), aLibrary );
1640 else
1641 dlgPrompt.Printf( _( "Save Library '%s' As Unpacked Library..." ), aLibrary );
1642
1643 wxDirDialog dlg( this, dlgPrompt, default_path );
1644
1646
1647 if( dlg.ShowModal() == wxID_CANCEL )
1648 return false;
1649
1650 fn.SetPath( dlg.GetPath() );
1651 }
1652 else
1653 {
1654 std::optional<LIBRARY_TABLE_ROW*> optRow = adapter->GetRow( aLibrary );
1655 wxCHECK( optRow, false );
1656
1657 wxString libFileName = LIBRARY_MANAGER::GetFullURI( *optRow, true );
1658
1659 // wxFileName will parse any string with a dot(.) followed by any characters as a file extension.
1660 // By default KiCad uses paths suffixed with .kicad_symdir which is interpreted as a file rather
1661 // than a path. Checking if the library is a file (packed) or a folder (unpacked) is required to
1662 // ensure the correct save type is used.
1663 if( wxFileName::DirExists( libFileName ) )
1664 fn.SetPath( libFileName );
1665 else
1666 fn = libFileName;
1667
1669
1670 if( fileType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1671 fileType = SCH_IO_MGR::SCH_KICAD;
1672 }
1673
1674 // Verify the user has write privileges before attempting to save the library file.
1675 if( ( aSaveType == SAVE_LIBRARY_AS::ORIGINAL ) && m_libMgr->IsLibraryReadOnly( aLibrary ) )
1676 return false;
1677
1678 ClearMsgPanel();
1679
1680 // Only make a backup when saving to the original library.
1681 if( aSaveType == SAVE_LIBRARY_AS::ORIGINAL )
1682 {
1683 wxString errMsg;
1684
1685 // Copy .kicad_symb file to .bak.
1686 if( !backupLibrary( fn, errMsg ) )
1687 {
1688 return false;
1689 }
1690 }
1691
1692 if( !m_libMgr->SaveLibrary( aLibrary, fn.GetFullPath(), fileType ) )
1693 {
1694 msg.Printf( _( "Failed to save changes to symbol library file '%s'." ),
1695 fn.GetFullPath() );
1696 DisplayErrorMessage( this, _( "Error Saving Library" ), msg );
1697 return false;
1698 }
1699
1700 if( aSaveType == SAVE_LIBRARY_AS::ORIGINAL )
1701 {
1702 m_libMgr->ClearLibraryModified( aLibrary );
1703
1705
1706 // Update the library modification time so that we don't reload based on the watcher
1707 if( aLibrary == getTargetLib() )
1708 {
1709 if( fn.DirExists() )
1710 {
1712 fn.GetFullPath(),
1713 wxS( "*." ) + wxString( FILEEXT::KiCadSymbolLibFileExtension ) ) );
1714 }
1715 else if( fn.FileExists() )
1716 {
1717 wxLogNull silence;
1718 SetSymModificationTime( fn.GetModificationTime().GetValue().GetValue() );
1719 }
1720 }
1721 }
1722 else
1723 {
1724 bool resyncLibTree = false;
1725 wxString originalLibNickname = getTargetLib();
1726 wxString forceRefresh;
1727
1728 switch( type )
1729 {
1731 resyncLibTree = replaceLibTableEntry( originalLibNickname, fn.GetFullPath() );
1732 forceRefresh = originalLibNickname;
1733 break;
1734
1736 resyncLibTree = addLibTableEntry( fn.GetFullPath() );
1737 break;
1738
1740 resyncLibTree = addLibTableEntry( fn.GetFullPath(), LIBRARY_TABLE_SCOPE::PROJECT );
1741 break;
1742
1743 default:
1744 break;
1745 }
1746
1747 if( resyncLibTree )
1748 {
1750 SyncLibraries( true, false, forceRefresh );
1752 }
1753 }
1754
1755 ClearMsgPanel();
1756 msg.Printf( _( "Symbol library file '%s' saved." ), fn.GetFullPath() );
1758
1759 return true;
1760}
1761
1762
1763bool SYMBOL_EDIT_FRAME::SaveLibraryHeadless( const wxString& aLibrary )
1764{
1765 return saveLibrary( aLibrary, SAVE_LIBRARY_AS::ORIGINAL );
1766}
1767
1768
1769bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
1770{
1771 wxString msg, msg2;
1772 bool doSave = true;
1773 int dirtyCount = 0;
1774 bool applyToAll = false;
1775 bool retv = true;
1776
1777 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1778 {
1779 if( m_libMgr->IsLibraryModified( libNickname ) )
1780 dirtyCount++;
1781 }
1782
1783 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1784 {
1785 if( m_libMgr->IsLibraryModified( libNickname ) )
1786 {
1787 if( aRequireConfirmation && !applyToAll )
1788 {
1789 msg.Printf( _( "Save changes to '%s' before closing?" ), libNickname );
1790
1791 switch( UnsavedChangesDialog( this, msg, dirtyCount > 1 ? &applyToAll : nullptr ) )
1792 {
1793 case wxID_YES: doSave = true; break;
1794 case wxID_NO: doSave = false; break;
1795 default:
1796 case wxID_CANCEL: return false;
1797 }
1798 }
1799
1800 if( doSave )
1801 {
1802 // If saving under existing name fails then do a Save As..., and if that
1803 // fails then cancel close action.
1804 if( m_libMgr->IsLibraryReadOnly( libNickname ) )
1805 {
1806 msg.Printf( _( "Symbol library '%s' is not writable." ), libNickname );
1807 msg2 = _( "You must save to a different location." );
1808
1809 if( dirtyCount == 1 )
1810 {
1811 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) != wxID_OK )
1812 {
1813 retv = false;
1814 continue;
1815 }
1816 }
1817 else
1818 {
1819 m_infoBar->Dismiss();
1820 m_infoBar->ShowMessageFor( msg + wxS( " " ) + msg2, 5000, wxICON_EXCLAMATION );
1821
1822 while( m_infoBar->IsShownOnScreen() )
1823 wxSafeYield();
1824
1825 retv = false;
1826 continue;
1827 }
1828 }
1829 else if( saveLibrary( libNickname, SAVE_LIBRARY_AS::ORIGINAL ) )
1830 {
1831 continue;
1832 }
1833
1834 if( !saveLibrary( libNickname, SAVE_LIBRARY_AS::NEW ) )
1835 retv = false;
1836 }
1837 }
1838 }
1839
1840 return retv;
1841}
1842
1843
1845{
1847
1848 if( !m_symbol )
1849 return;
1850
1851 wxString msg = m_symbol->GetName();
1852
1853 AppendMsgPanel( _( "Name" ), UnescapeString( msg ), 8 );
1854
1855 if( m_symbol->IsDerived() )
1856 {
1857 std::shared_ptr<LIB_SYMBOL> parent = m_symbol->GetParent().lock();
1858
1859 msg = parent ? parent->GetName() : _( "Undefined!" );
1860 AppendMsgPanel( _( "Parent" ), UnescapeString( msg ), 8 );
1861 }
1862
1863 if( m_symbol->IsGlobalPower() )
1864 msg = _( "Power Symbol" );
1865 else if( m_symbol->IsLocalPower() )
1866 msg = _( "Power Symbol (Local)" );
1867 else
1868 msg = _( "Symbol" );
1869
1870 AppendMsgPanel( _( "Type" ), msg, 8 );
1871 AppendMsgPanel( _( "Description" ), m_symbol->GetDescription(), 8 );
1872 AppendMsgPanel( _( "Keywords" ), m_symbol->GetKeyWords() );
1873 AppendMsgPanel( _( "Datasheet" ), m_symbol->GetDatasheetField().GetText() );
1874}
const char * name
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION zoomFitScreen
Definition actions.h:138
bool IsContentModified() const
Definition base_screen.h:56
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:1743
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.
static std::unique_ptr< LIB_SYMBOL > CreateSymbol(const NEW_SYMBOL_PROPERTIES &aProps, LIB_SYMBOL *aParent)
Define a library symbol object.
Definition lib_symbol.h:114
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:190
bool UnitsLocked() const
Check whether symbol units are interchangeable.
bool IsDerived() const
Definition lib_symbol.h:241
LIB_ID GetSourceLibId() const
Definition lib_symbol.h:193
void SetParent(LIB_SYMBOL *aParent=nullptr)
wxString GetName() const override
Definition lib_symbol.h:183
SCH_FIELD & GetValueField()
Definition lib_symbol.h:447
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:125
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
void SetParentName(const wxString &aParentName)
Definition lib_symbol.h:994
void SetLibId(const LIB_ID &aLibId)
virtual void SetName(const wxString &aName)
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:125
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)
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 KIGFX::VIEW instance used in the panel.
Schematic editor (Eeschema) main window.
bool 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:139
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 file type from the corresponding plugin type name: "kicad", "legacy", etc.
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:430
const std::string & GetString()
Definition richio.h:453
One open symbol tab owning a working LIB_SYMBOL and screen lent to the frame while active.
The symbol library editor main window.
bool SaveLibraryHeadless(const wxString &aLibrary)
Save the given library (including buffered changes) without user interaction.
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
Return either the library selected in the symbol tree, if context menu is active or the library that ...
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
Return true if aLibId is an alias for the editor screen symbol.
bool backupLibrary(const wxFileName &aOriginalFile, wxString &aErrorMsg)
Create a backup copy of a symbol library.
EDITOR_TABS_PANEL * m_tabsPanel
bool saveLibrary(const wxString &aLibrary, SAVE_LIBRARY_AS aSaveType=SAVE_LIBRARY_AS::ORIGINAL)
Save the changes to the current library.
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 SaveLibraryAs(SAVE_LIBRARY_AS aSaveType=SAVE_LIBRARY_AS::NEW)
Save the currently selected library to a new file.
void Save()
Save the selected symbol or library.
void LoadSymbol(const wxString &aLibrary, const wxString &aSymbol, int Unit)
bool addLibTableEntry(const wxString &aLibFile, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::GLOBAL)
Add aLibFile to the symbol library table defined by aScope.
int m_unit
The unit number to edit and show.
bool LoadOneLibrarySymbol(LIB_SYMBOL *aLibEntry, const wxString &aLibrary, int aUnit, int aBodyStyle)
Create a copy of aLibEntry into memory.
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 emptyScreen()
Restore the empty editor screen, without any symbol or library selected.
SYMBOL_EDITOR_TAB_CONTEXT * m_activeTab
void DuplicateSymbol(bool aFromClipboard)
Insert a duplicate symbol.
void saveSymbolCopyAs(bool aOpenCopy)
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...
int m_bodyStyle
Show the normal shape (m_bodyStyle <= 1) or the DeMorgan converted shape (m_bodyStyle > 1)
bool saveAllLibraries(bool aRequireConfirmation)
Return true when the operation has succeeded (all requested libraries have been saved or none was sel...
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_EDITOR_TAB_CONTEXT * CreateUnsavedSymbolTab(LIB_SYMBOL *aSymbol, SCH_SCREEN *aScreen)
Open a new tab over a transient working symbol and screen and make it active.
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()
Save the current symbol.
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 Revert(LIB_ID &aTarget, bool aConfirm=true)
Revert unsaved changes in a symbol, restoring to the last saved state.
void ensureUniqueName(LIB_SYMBOL *aSymbol, const wxString &aLibrary)
Rename LIB_SYMBOL aliases to avoid conflicts before adding a symbol to a library.
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.
bool IsContentModified() const override
Get if any symbols or libraries have been modified but not saved.
LIB_SYMBOL * getTargetSymbol() const
Return currently edited symbol.
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)
@ ITALIC
Definition font.h:44
@ 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:733
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:533
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_LIBRARY_AS
Types of KiCad symbol library save actions.
@ NEW
Save to a new library in the original symbol library format.
@ UNPACKED
Save a packed symbol library to the unpacked format.
@ PACKED
Save an unpacked symbol library to the packed format.
@ ORIGINAL
Save to the original symbol library format.
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
JSON_SCHEMA_VALIDATOR validator(schema)
const SHAPE_LINE_CHAIN chain
Definition of file extensions used in Kicad.