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 // Close only the tabs for the symbol being deleted and the symbols derived from it,
1318 // which are removed along with it. The other open tabs stay put.
1319 closeSymbolTab( libId );
1320
1321 for( const wxString& derivedName : derived )
1322 closeSymbolTab( LIB_ID( libId.GetLibNickname().wx_str(), derivedName ) );
1323
1324 m_libMgr->RemoveSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1325
1326 for( const wxString& derivedName : derived )
1327 removedWithBase.emplace( libId.GetLibNickname().wx_str(), derivedName );
1328 }
1329
1330 m_treePane->GetLibTree()->RefreshLibTree();
1331}
1332
1333
1335{
1336 std::vector<LIB_ID> symbols;
1337
1338 if( GetTreeLIBIDs( symbols ) == 0 )
1339 return;
1340
1341 STRING_FORMATTER formatter;
1342
1343 for( LIB_ID& libId : symbols )
1344 {
1345 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(),
1346 libId.GetLibNickname() );
1347
1348 if( !symbol )
1349 continue;
1350
1351 std::unique_ptr<LIB_SYMBOL> tmp = symbol->Flatten();
1352 SCH_IO_KICAD_SEXPR::FormatLibSymbol( tmp.get(), formatter );
1353 }
1354
1355 std::string prettyData = formatter.GetString();
1356 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES );
1357
1358 wxLogNull doNotLog; // disable logging of failed clipboard actions
1359
1360 auto clipboard = wxTheClipboard;
1361 wxClipboardLocker clipboardLock( clipboard );
1362
1363 if( !clipboardLock || !clipboard->IsOpened() )
1364 return;
1365
1366 auto data = new wxTextDataObject( wxString( prettyData.c_str(), wxConvUTF8 ) );
1367 clipboard->SetData( data );
1368
1369 clipboard->Flush();
1370}
1371
1372
1373void SYMBOL_EDIT_FRAME::DuplicateSymbol( bool aFromClipboard )
1374{
1375 LIB_ID libId = GetTargetLibId();
1376 wxString lib = libId.GetLibNickname();
1377
1378 if( !m_libMgr->LibraryExists( lib ) )
1379 return;
1380
1381 std::vector<LIB_SYMBOL*> newSymbols;
1382
1383 if( aFromClipboard )
1384 {
1385 std::string clipboardData = GetClipboardUTF8();
1386
1387 try
1388 {
1389 newSymbols = SCH_IO_KICAD_SEXPR::ParseLibSymbols( clipboardData, "Clipboard" );
1390 }
1391 catch( IO_ERROR& e )
1392 {
1393 wxLogMessage( wxS( "Can not paste: %s" ), e.Problem() );
1394 }
1395 }
1396 else if( LIB_SYMBOL* srcSymbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(), lib ) )
1397 {
1398 newSymbols.emplace_back( new LIB_SYMBOL( *srcSymbol ) );
1399
1400 // Derive from same parent.
1401 if( srcSymbol->IsDerived() )
1402 {
1403 if( std::shared_ptr<LIB_SYMBOL> srcParent = srcSymbol->GetParent().lock() )
1404 newSymbols.back()->SetParent( srcParent.get() );
1405 }
1406 }
1407
1408 if( newSymbols.empty() )
1409 return;
1410
1411 for( LIB_SYMBOL* symbol : newSymbols )
1412 {
1413 ensureUniqueName( symbol, lib );
1414 m_libMgr->UpdateSymbol( symbol, lib );
1415
1416 LoadOneLibrarySymbol( symbol, lib, GetUnit(), GetBodyStyle() );
1417 }
1418
1419 SyncLibraries( false );
1420 m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newSymbols[0]->GetName() ) );
1421
1422 for( LIB_SYMBOL* symbol : newSymbols )
1423 delete symbol;
1424}
1425
1426
1427void SYMBOL_EDIT_FRAME::ensureUniqueName( LIB_SYMBOL* aSymbol, const wxString& aLibrary )
1428{
1429 if( aSymbol )
1430 {
1431 int i = 1;
1432 wxString newName = aSymbol->GetName();
1433
1434 // Append a number to the name until the name is unique in the library.
1435 while( m_libMgr->SymbolNameInUse( newName, aLibrary ) )
1436 newName.Printf( "%s_%d", aSymbol->GetName(), i++ );
1437
1438 aSymbol->SetName( newName );
1439 }
1440}
1441
1442
1443void SYMBOL_EDIT_FRAME::Revert( LIB_ID& aTarget, bool aConfirm )
1444{
1445 const wxString& libName = aTarget.GetLibNickname();
1446
1447 // Empty if this is the library itself that is selected.
1448 const wxString& symbolName = aTarget.GetLibItemName();
1449
1450 wxString msg = wxString::Format( _( "Revert '%s' to last version saved?" ),
1451 symbolName.IsEmpty() ? libName : symbolName );
1452
1453 if( aConfirm && !ConfirmRevertDialog( this, msg ) )
1454 return;
1455
1456 bool reload_currentSymbol = false;
1457 wxString curr_symbolName = symbolName;
1458
1459 if( GetCurSymbol() )
1460 {
1461 // the library itself is reverted: the current symbol will be reloaded only if it is
1462 // owned by this library
1463 if( symbolName.IsEmpty() )
1464 {
1465 LIB_ID curr_libId = GetCurSymbol()->GetLibId();
1466 reload_currentSymbol = libName == curr_libId.GetLibNickname().wx_str();
1467
1468 if( reload_currentSymbol )
1469 curr_symbolName = curr_libId.GetUniStringLibItemName();
1470 }
1471 else
1472 {
1473 reload_currentSymbol = IsCurrentSymbol( aTarget );
1474 }
1475 }
1476
1477 int unit = m_unit;
1478
1479 if( reload_currentSymbol )
1480 emptyScreen();
1481
1482 if( symbolName.IsEmpty() )
1483 {
1484 m_libMgr->RevertLibrary( libName );
1485 }
1486 else
1487 {
1488 aTarget = m_libMgr->RevertSymbol( aTarget );
1489
1490 m_treePane->GetLibTree()->SelectLibId( aTarget );
1491 m_libMgr->ClearSymbolModified( aTarget.GetLibItemName(), aTarget.GetLibNickname() );
1492 }
1493
1494 if( reload_currentSymbol && m_libMgr->SymbolExists( curr_symbolName, libName ) )
1495 LoadSymbol( curr_symbolName, libName, unit );
1496
1497 m_treePane->Refresh();
1498}
1499
1500
1502{
1503 wxCHECK_RET( m_libMgr, "Library manager object not created." );
1504
1505 LIB_ID target = GetTargetLibId();
1506 Revert( target, false );
1507 m_libMgr->RevertAll();
1508}
1509
1510
1511void SYMBOL_EDIT_FRAME::LoadSymbol( const wxString& aAlias, const wxString& aLibrary, int aUnit )
1512{
1514 {
1515 if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
1516 [&]() -> bool
1517 {
1518 return saveCurrentSymbol();
1519 } ) )
1520 {
1521 return;
1522 }
1523 }
1524
1525 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( aAlias, aLibrary );
1526
1527 if( !symbol )
1528 {
1529 DisplayError( this, wxString::Format( _( "Symbol %s not found in library '%s'." ),
1530 aAlias,
1531 aLibrary ) );
1532 m_treePane->GetLibTree()->RefreshLibTree();
1533 return;
1534 }
1535
1536 // Optimize default edit options for this symbol
1537 // Usually if units are locked, graphic items are specific to each unit
1538 // and if units are interchangeable, graphic items are common to units
1539 SetDrawSpecificUnit( symbol->UnitsLocked() );
1540
1541 LoadOneLibrarySymbol( symbol, aLibrary, aUnit, 0 );
1542}
1543
1544
1545bool SYMBOL_EDIT_FRAME::saveLibrary( const wxString& aLibrary, SAVE_LIBRARY_AS aSaveType )
1546{
1547 wxFileName fn;
1548 wxString msg;
1550 SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::SCH_FILE_T::SCH_KICAD;
1551 PROJECT& prj = Prj();
1552
1554
1556
1557 wxCHECK( adapter, false );
1558
1559 if( ( aSaveType == SAVE_LIBRARY_AS::ORIGINAL ) && ( aLibrary.empty() || !adapter->HasLibrary( aLibrary ) ) )
1560 {
1561 ShowInfoBarError( _( "No library specified." ) );
1562 return false;
1563 }
1564
1565 bool newPackedLibrary = ( ( aSaveType == SAVE_LIBRARY_AS::ORIGINAL ) && wxFileName::FileExists( aLibrary ) ) ||
1566 ( aSaveType == SAVE_LIBRARY_AS::PACKED );
1567
1568 bool newUnpackedLibrary = ( ( aSaveType == SAVE_LIBRARY_AS::ORIGINAL ) && wxFileName::DirExists( aLibrary ) ) ||
1569 ( aSaveType == SAVE_LIBRARY_AS::UNPACKED );
1570
1571 if( newPackedLibrary )
1572 {
1573 SEARCH_STACK* search = PROJECT_SCH::SchSearchS( &prj );
1574
1575 // Get a new name for the library
1576 wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
1577
1578 if( !default_path )
1579 default_path = search->LastVisitedPath();
1580
1581 fn.SetName( aLibrary );
1583
1584 wxString wildcards = FILEEXT::KiCadSymbolLibFileWildcard();
1585 wxString dlgPrompt;
1586
1587 if( aSaveType == SAVE_LIBRARY_AS::ORIGINAL )
1588 dlgPrompt.Printf( _( "Save Library '%s' As..." ), aLibrary );
1589 else
1590 dlgPrompt.Printf( _( "Save Library '%s' As Packed Library..." ), aLibrary );
1591
1592 wxFileDialog dlg( this, dlgPrompt, default_path, fn.GetFullName(), wildcards,
1593 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1594
1595 SYMBOL_LIBRARY_SAVE_AS_FILEDLG_HOOK saveAsHook( type );
1596 dlg.SetCustomizeHook( saveAsHook );
1597
1599
1600 if( dlg.ShowModal() == wxID_CANCEL )
1601 return false;
1602
1603 fn = dlg.GetPath();
1604
1605 prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() );
1606
1607 if( fn.GetExt().IsEmpty() )
1609
1610 type = saveAsHook.GetOption();
1611 }
1612 else if( newUnpackedLibrary )
1613 {
1614 SEARCH_STACK* search = PROJECT_SCH::SchSearchS( &prj );
1615
1616 // Get a new name for the library
1617 wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
1618
1619 if( !default_path )
1620 default_path = search->LastVisitedPath();
1621
1622 wxString dlgPrompt;
1623
1624 if( aSaveType == SAVE_LIBRARY_AS::ORIGINAL )
1625 dlgPrompt.Printf( _( "Save Library '%s' As..." ), aLibrary );
1626 else
1627 dlgPrompt.Printf( _( "Save Library '%s' As Unpacked Library..." ), aLibrary );
1628
1629 wxDirDialog dlg( this, dlgPrompt, default_path );
1630
1632
1633 if( dlg.ShowModal() == wxID_CANCEL )
1634 return false;
1635
1636 fn.SetPath( dlg.GetPath() );
1637 }
1638 else
1639 {
1640 std::optional<LIBRARY_TABLE_ROW*> optRow = adapter->GetRow( aLibrary );
1641 wxCHECK( optRow, false );
1642
1643 wxString libFileName = LIBRARY_MANAGER::GetFullURI( *optRow, true );
1644
1645 // wxFileName will parse any string with a dot(.) followed by any characters as a file extension.
1646 // By default KiCad uses paths suffixed with .kicad_symdir which is interpreted as a file rather
1647 // than a path. Checking if the library is a file (packed) or a folder (unpacked) is required to
1648 // ensure the correct save type is used.
1649 if( wxFileName::DirExists( libFileName ) )
1650 fn.SetPath( libFileName );
1651 else
1652 fn = libFileName;
1653
1655
1656 if( fileType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1657 fileType = SCH_IO_MGR::SCH_KICAD;
1658 }
1659
1660 // Verify the user has write privileges before attempting to save the library file.
1661 if( ( aSaveType == SAVE_LIBRARY_AS::ORIGINAL ) && m_libMgr->IsLibraryReadOnly( aLibrary ) )
1662 return false;
1663
1664 ClearMsgPanel();
1665
1666 // Only make a backup when saving to the original library.
1667 if( aSaveType == SAVE_LIBRARY_AS::ORIGINAL )
1668 {
1669 wxString errMsg;
1670
1671 // Copy .kicad_symb file to .bak.
1672 if( !backupLibrary( fn, errMsg ) )
1673 {
1674 return false;
1675 }
1676 }
1677
1678 if( !m_libMgr->SaveLibrary( aLibrary, fn.GetFullPath(), fileType ) )
1679 {
1680 msg.Printf( _( "Failed to save changes to symbol library file '%s'." ),
1681 fn.GetFullPath() );
1682 DisplayErrorMessage( this, _( "Error Saving Library" ), msg );
1683 return false;
1684 }
1685
1686 if( aSaveType == SAVE_LIBRARY_AS::ORIGINAL )
1687 {
1688 m_libMgr->ClearLibraryModified( aLibrary );
1689
1691
1692 // Update the library modification time so that we don't reload based on the watcher
1693 if( aLibrary == getTargetLib() )
1694 {
1695 if( fn.DirExists() )
1696 {
1698 fn.GetFullPath(),
1699 wxS( "*." ) + wxString( FILEEXT::KiCadSymbolLibFileExtension ) ) );
1700 }
1701 else if( fn.FileExists() )
1702 {
1703 wxLogNull silence;
1704 SetSymModificationTime( fn.GetModificationTime().GetValue().GetValue() );
1705 }
1706 }
1707 }
1708 else
1709 {
1710 bool resyncLibTree = false;
1711 wxString originalLibNickname = getTargetLib();
1712 wxString forceRefresh;
1713
1714 switch( type )
1715 {
1717 resyncLibTree = replaceLibTableEntry( originalLibNickname, fn.GetFullPath() );
1718 forceRefresh = originalLibNickname;
1719 break;
1720
1722 resyncLibTree = addLibTableEntry( fn.GetFullPath() );
1723 break;
1724
1726 resyncLibTree = addLibTableEntry( fn.GetFullPath(), LIBRARY_TABLE_SCOPE::PROJECT );
1727 break;
1728
1729 default:
1730 break;
1731 }
1732
1733 if( resyncLibTree )
1734 {
1736 SyncLibraries( true, false, forceRefresh );
1738 }
1739 }
1740
1741 ClearMsgPanel();
1742 msg.Printf( _( "Symbol library file '%s' saved." ), fn.GetFullPath() );
1744
1745 return true;
1746}
1747
1748
1749bool SYMBOL_EDIT_FRAME::SaveLibraryHeadless( const wxString& aLibrary )
1750{
1751 return saveLibrary( aLibrary, SAVE_LIBRARY_AS::ORIGINAL );
1752}
1753
1754
1755bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
1756{
1757 wxString msg, msg2;
1758 bool doSave = true;
1759 int dirtyCount = 0;
1760 bool applyToAll = false;
1761 bool retv = true;
1762
1763 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1764 {
1765 if( m_libMgr->IsLibraryModified( libNickname ) )
1766 dirtyCount++;
1767 }
1768
1769 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1770 {
1771 if( m_libMgr->IsLibraryModified( libNickname ) )
1772 {
1773 if( aRequireConfirmation && !applyToAll )
1774 {
1775 msg.Printf( _( "Save changes to '%s' before closing?" ), libNickname );
1776
1777 switch( UnsavedChangesDialog( this, msg, dirtyCount > 1 ? &applyToAll : nullptr ) )
1778 {
1779 case wxID_YES: doSave = true; break;
1780 case wxID_NO: doSave = false; break;
1781 default:
1782 case wxID_CANCEL: return false;
1783 }
1784 }
1785
1786 if( doSave )
1787 {
1788 // If saving under existing name fails then do a Save As..., and if that
1789 // fails then cancel close action.
1790 if( m_libMgr->IsLibraryReadOnly( libNickname ) )
1791 {
1792 msg.Printf( _( "Symbol library '%s' is not writable." ), libNickname );
1793 msg2 = _( "You must save to a different location." );
1794
1795 if( dirtyCount == 1 )
1796 {
1797 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) != wxID_OK )
1798 {
1799 retv = false;
1800 continue;
1801 }
1802 }
1803 else
1804 {
1805 m_infoBar->Dismiss();
1806 m_infoBar->ShowMessageFor( msg + wxS( " " ) + msg2, 5000, wxICON_EXCLAMATION );
1807
1808 while( m_infoBar->IsShownOnScreen() )
1809 wxSafeYield();
1810
1811 retv = false;
1812 continue;
1813 }
1814 }
1815 else if( saveLibrary( libNickname, SAVE_LIBRARY_AS::ORIGINAL ) )
1816 {
1817 continue;
1818 }
1819
1820 if( !saveLibrary( libNickname, SAVE_LIBRARY_AS::NEW ) )
1821 retv = false;
1822 }
1823 }
1824 }
1825
1826 return retv;
1827}
1828
1829
1831{
1833
1834 if( !m_symbol )
1835 return;
1836
1837 wxString msg = m_symbol->GetName();
1838
1839 AppendMsgPanel( _( "Name" ), UnescapeString( msg ), 8 );
1840
1841 if( m_symbol->IsDerived() )
1842 {
1843 std::shared_ptr<LIB_SYMBOL> parent = m_symbol->GetParent().lock();
1844
1845 msg = parent ? parent->GetName() : _( "Undefined!" );
1846 AppendMsgPanel( _( "Parent" ), UnescapeString( msg ), 8 );
1847 }
1848
1849 if( m_symbol->IsGlobalPower() )
1850 msg = _( "Power Symbol" );
1851 else if( m_symbol->IsLocalPower() )
1852 msg = _( "Power Symbol (Local)" );
1853 else
1854 msg = _( "Symbol" );
1855
1856 AppendMsgPanel( _( "Type" ), msg, 8 );
1857 AppendMsgPanel( _( "Description" ), m_symbol->GetDescription(), 8 );
1858 AppendMsgPanel( _( "Keywords" ), m_symbol->GetKeyWords() );
1859 AppendMsgPanel( _( "Datasheet" ), m_symbol->GetDatasheetField().GetText() );
1860}
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:2475
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:401
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:235
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:448
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:459
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:737
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:640
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.