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 <widgets/wx_infobar.h>
29#include <symbol_edit_frame.h>
30#include <template_fieldnames.h>
33#include <symbol_tree_pane.h>
35#include <richio.h>
36#include <widgets/lib_tree.h>
40#include <eda_list_dialog.h>
41#include <wx/clipbrd.h>
42#include <wx/filedlg.h>
43#include <wx/log.h>
44#include <project_sch.h>
45#include <kiplatform/io.h>
46#include <kiplatform/ui.h>
47#include <string_utils.h>
48#include "symbol_saveas_type.h"
52
53
55{
56 wxString title;
57
59 {
61 title = wxT( "*" );
62
63 title += m_reference;
64 title += wxS( " " ) + _( "[from schematic]" );
65 }
66 else if( GetCurSymbol() )
67 {
69 title = wxT( "*" );
70
71 title += UnescapeString( GetCurSymbol()->GetLibId().Format() );
72
73 if( m_libMgr && m_libMgr->LibraryExists( GetCurLib() ) && m_libMgr->IsLibraryReadOnly( GetCurLib() ) )
74 title += wxS( " " ) + _( "[Read Only Library]" );
75 }
76 else
77 {
78 title = _( "[no symbol loaded]" );
79 }
80
81 title += wxT( " \u2014 " ) + _( "Symbol Editor" );
82 SetTitle( title );
83}
84
85
86void SYMBOL_EDIT_FRAME::SelectActiveLibrary( const wxString& aLibrary )
87{
88 wxString selectedLib = aLibrary;
89
90 if( selectedLib.empty() )
91 selectedLib = SelectLibrary( _( "Select Symbol Library" ), _( "Library:" ) );
92
93 if( !selectedLib.empty() )
94 SetCurLib( selectedLib );
95
97}
98
99
101{
102 if( GetCurSymbol() )
103 {
105 {
106 SCH_EDIT_FRAME* schframe = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
107
108 if( !schframe ) // happens when the schematic editor has been closed
109 {
110 DisplayErrorMessage( this, _( "No schematic currently open." ) );
111 return false;
112 }
113 else
114 {
116 GetScreen()->SetContentModified( false );
117 return true;
118 }
119 }
120 else
121 {
122 const wxString& libName = GetCurSymbol()->GetLibId().GetLibNickname();
123
124 if( m_libMgr->IsLibraryReadOnly( libName ) )
125 {
126 wxString msg = wxString::Format( _( "Symbol library '%s' is not writable." ),
127 libName );
128 wxString msg2 = _( "You must save to a different location." );
129
130 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) == wxID_OK )
131 return saveLibrary( libName, true );
132 }
133 else
134 {
135 return saveLibrary( libName, false );
136 }
137 }
138 }
139
140 return false;
141}
142
143
144bool SYMBOL_EDIT_FRAME::LoadSymbol( const LIB_ID& aLibId, int aUnit, int aBodyStyle )
145{
146 LIB_ID libId = aLibId;
149
150 // Some libraries can't be edited, so load the underlying chosen symbol
151 if( auto optRow = manager.GetRow( LIBRARY_TABLE_TYPE::SYMBOL, aLibId.GetLibNickname() );
152 optRow.has_value() )
153 {
154 const LIBRARY_TABLE_ROW* row = *optRow;
155 SCH_IO_MGR::SCH_FILE_T type = SCH_IO_MGR::EnumFromStr( row->Type() );
156
157 if( type == SCH_IO_MGR::SCH_DATABASE
158 || type == SCH_IO_MGR::SCH_CADSTAR_ARCHIVE
159 || type == SCH_IO_MGR::SCH_HTTP )
160 {
161 try
162 {
163 LIB_SYMBOL* readOnlySym = adapter->LoadSymbol( aLibId );
164
165 if( readOnlySym && readOnlySym->GetSourceLibId().IsValid() )
166 libId = readOnlySym->GetSourceLibId();
167 }
168 catch( const IO_ERROR& ioe )
169 {
170 wxString msg;
171
172 msg.Printf( _( "Error loading symbol %s from library '%s'." ),
173 aLibId.GetUniStringLibId(), aLibId.GetUniStringLibItemName() );
174 DisplayErrorMessage( this, msg, ioe.What() );
175 return false;
176 }
177 }
178 }
179
181 && GetCurSymbol()->GetLibId() == libId
182 && GetUnit() == aUnit
183 && GetBodyStyle() == aBodyStyle )
184 {
185 return true;
186 }
187
189 {
190 if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
191 [&]() -> bool
192 {
193 return saveCurrentSymbol();
194 } ) )
195 {
196 return false;
197 }
198 }
199
201
202 if( LoadSymbolFromCurrentLib( libId.GetLibItemName(), aUnit, aBodyStyle ) )
203 {
204 m_treePane->GetLibTree()->SelectLibId( libId );
205 m_treePane->GetLibTree()->ExpandLibId( libId );
206
207 m_centerItemOnIdle = libId;
208 Bind( wxEVT_IDLE, &SYMBOL_EDIT_FRAME::centerItemIdleHandler, this );
209 setSymWatcher( &libId );
210
211 return true;
212 }
213
214 return false;
215}
216
217
219{
220 m_treePane->GetLibTree()->CenterLibId( m_centerItemOnIdle );
221 Unbind( wxEVT_IDLE, &SYMBOL_EDIT_FRAME::centerItemIdleHandler, this );
222}
223
224
225bool SYMBOL_EDIT_FRAME::LoadSymbolFromCurrentLib( const wxString& aSymbolName, int aUnit, int aBodyStyle )
226{
227 LIB_SYMBOL* symbol = nullptr;
228
229 try
230 {
231 symbol = PROJECT_SCH::SymbolLibAdapter( &Prj() )->LoadSymbol( GetCurLib(), aSymbolName );
232 }
233 catch( const IO_ERROR& ioe )
234 {
235 wxString msg;
236
237 msg.Printf( _( "Error loading symbol %s from library '%s'." ),
238 aSymbolName,
239 GetCurLib() );
240 DisplayErrorMessage( this, msg, ioe.What() );
241 return false;
242 }
243
244 if( !symbol || !LoadOneLibrarySymbolAux( symbol, GetCurLib(), aUnit, aBodyStyle ) )
245 return false;
246
247 // Enable synchronized pin edit mode for symbols with interchangeable units
249
251
253
254 return true;
255}
256
257
258bool SYMBOL_EDIT_FRAME::LoadOneLibrarySymbolAux( LIB_SYMBOL* aEntry, const wxString& aLibrary,
259 int aUnit, int aBodyStyle )
260{
261 bool rebuildMenuAndToolbar = false;
262
263 if( !aEntry || aLibrary.empty() )
264 return false;
265
266 if( aEntry->GetName().IsEmpty() )
267 {
268 wxLogWarning( "Symbol in library '%s' has empty name field.", aLibrary );
269 return false;
270 }
271
273
274 // Switching away from a schematic-instance tab changes the available menu/toolbar actions. The
275 // instance tab keeps owning its working objects, so nothing is deleted here.
277 rebuildMenuAndToolbar = true;
278
279 LIB_SYMBOL* lib_symbol = m_libMgr->GetBufferedSymbol( aEntry->GetName(), aLibrary );
280 wxCHECK( lib_symbol, false );
281
282 m_unit = aUnit > 0 ? aUnit : 1;
283 m_bodyStyle = aBodyStyle > 0 ? aBodyStyle : 1;
284
285 // Open as a preview tab that the next library-open reuses until the symbol is edited.
286 bool wasCreated = false;
287 SYMBOL_EDITOR_TAB_CONTEXT* ctx = findOrCreateSymbolTab( aLibrary, lib_symbol->GetName(),
288 m_unit, m_bodyStyle, true,
289 &wasCreated );
290 wxCHECK( ctx, false );
291
292 if( rebuildMenuAndToolbar )
293 {
296 GetInfoBar()->Dismiss();
297 }
298
299 UpdateTitle();
301
302 // Only a freshly-created tab gets a clean undo history; re-focusing preserves the live stack.
303 if( wasCreated )
305
306 if( !IsSymbolFromSchematic() )
307 {
308 LIB_ID libId = GetCurSymbol()->GetLibId();
309 setSymWatcher( &libId );
310 }
311
314
315 // Display the document information based on the entry selected just in
316 // case the entry is an alias.
318 Refresh();
319
320 return true;
321}
322
323
325{
326 saveAllLibraries( false );
327 m_treePane->GetLibTree()->RefreshLibTree();
328}
329
330
331void SYMBOL_EDIT_FRAME::CreateNewSymbol( const wxString& aInheritFrom )
332{
334
335 wxString lib = getTargetLib();
336
337 if( !m_libMgr->LibraryExists( lib ) )
338 {
339 lib = SelectLibrary( _( "New Symbol" ), _( "Create symbol in library:" ) );
340
341 if( !m_libMgr->LibraryExists( lib ) )
342 return;
343 }
344
345 const auto validator =
346 [&]( wxString newName ) -> bool
347 {
348 if( newName.IsEmpty() )
349 {
350 wxMessageBox( _( "Symbol must have a name." ) );
351 return false;
352 }
353
354 if( !lib.empty() && m_libMgr->SymbolNameInUse( newName, lib ) )
355 {
356 wxString msg;
357
358 msg.Printf( _( "Symbol '%s' already exists in library '%s'." ),
359 UnescapeString( newName ),
360 lib );
361
362 KIDIALOG errorDlg( this, msg, _( "Confirmation" ),
363 wxOK | wxCANCEL | wxICON_WARNING );
364
365 errorDlg.SetOKLabel( _( "Overwrite" ) );
366
367 return errorDlg.ShowModal() == wxID_OK;
368 }
369
370 return true;
371 };
372
373 wxArrayString symbolNamesInLib;
374 m_libMgr->GetSymbolNames( lib, symbolNamesInLib );
375
376 DIALOG_LIB_NEW_SYMBOL dlg( this, symbolNamesInLib, aInheritFrom, validator );
377
378 dlg.SetMinSize( dlg.GetSize() );
379
380 if( dlg.ShowModal() == wxID_CANCEL )
381 return;
382
384
385 props.name = dlg.GetName();
387 props.reference = dlg.GetReference();
388 props.unitCount = dlg.GetUnitCount();
389 props.pinNameInside = dlg.GetPinNameInside();
391 props.powerSymbol = dlg.GetPowerSymbol();
392 props.showPinNumber = dlg.GetShowPinNumber();
393 props.showPinName = dlg.GetShowPinName();
395 props.includeInBom = dlg.GetIncludeInBom();
396 props.includeOnBoard = dlg.GetIncludeOnBoard();
398 props.keepFootprint = dlg.GetKeepFootprint();
399 props.keepDatasheet = dlg.GetKeepDatasheet();
402
403 m_libMgr->CreateNewSymbol( lib, props );
404 SyncLibraries( false );
405 LoadSymbol( props.name, lib, 1 );
406}
407
408
410{
411 wxString libName;
412
413 if( IsLibraryTreeShown() )
415
416 if( libName.empty() )
417 {
419 }
420 else if( m_libMgr->IsLibraryReadOnly( libName ) )
421 {
422 wxString msg = wxString::Format( _( "Symbol library '%s' is not writable." ),
423 libName );
424 wxString msg2 = _( "You must save to a different location." );
425
426 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) == wxID_OK )
427 saveLibrary( libName, true );
428 }
429 else
430 {
431 saveLibrary( libName, false );
432 }
433
434 if( IsLibraryTreeShown() )
435 m_treePane->GetLibTree()->RefreshLibTree();
436
437 UpdateTitle();
438}
439
440
442{
443 const wxString& libName = GetTargetLibId().GetLibNickname();
444
445 if( !libName.IsEmpty() )
446 {
447 saveLibrary( libName, true );
448 m_treePane->GetLibTree()->RefreshLibTree();
449 }
450}
451
452
454{
455 saveSymbolCopyAs( aOpenCopy );
456
457 m_treePane->GetLibTree()->RefreshLibTree();
458}
459
460
470static std::vector<std::shared_ptr<LIB_SYMBOL>> GetParentChain( const LIB_SYMBOL& aSymbol, bool aIncludeLeaf = true )
471{
472 std::vector<std::shared_ptr<LIB_SYMBOL>> chain;
473 std::shared_ptr<LIB_SYMBOL> sym = aSymbol.SharedPtr();
474
475 if( aIncludeLeaf )
476 chain.push_back( sym );
477
478 while( sym->IsDerived() )
479 {
480 std::shared_ptr<LIB_SYMBOL> parent = sym->GetParent().lock();
481
482 // A symbol can report itself as derived while its parent pointer has already expired.
483 // Stop walking rather than push a null entry and dereference it on the next iteration.
484 if( !parent )
485 break;
486
487 chain.push_back( parent );
488 sym = parent;
489 }
490
491 return chain;
492}
493
494
504static std::pair<bool, bool> CheckSavingIntoOwnInheritance( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr,
505 LIB_SYMBOL& aSymbol,
506 const wxString& aNewSymbolName,
507 const wxString& aNewLibraryName )
508{
509 const wxString& oldLibraryName = aSymbol.GetLibId().GetLibNickname();
510
511 // Cannot be intersecting if in different libs
512 if( aNewLibraryName != oldLibraryName )
513 return { false, false };
514
515 // Or if the target symbol doesn't exist
516 if( !aLibMgr.SymbolNameInUse( aNewSymbolName, aNewLibraryName ) )
517 return { false, false };
518
519 bool inAncestry = false;
520 bool inDescendents = false;
521
522 {
523 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChainFromUs = GetParentChain( aSymbol, true );
524
525 // Ignore the leaf symbol (0) - that must match
526 for( size_t i = 1; i < parentChainFromUs.size(); ++i )
527 {
528 // Attempting to overwrite a symbol in the parental chain
529 if( parentChainFromUs[i]->GetName() == aNewSymbolName )
530 {
531 inAncestry = true;
532 break;
533 }
534 }
535 }
536
537 {
538 LIB_SYMBOL* targetSymbol = aLibMgr.GetSymbol( aNewSymbolName, aNewLibraryName );
539 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChainFromTarget = GetParentChain( *targetSymbol, true );
540 const wxString oldSymbolName = aSymbol.GetName();
541
542 // Ignore the leaf symbol - it'll match if we're saving the symbol
543 // to the same name, and that would be OK
544 for( size_t i = 1; i < parentChainFromTarget.size(); ++i )
545 {
546 if( parentChainFromTarget[i]->GetName() == oldSymbolName )
547 {
548 inDescendents = true;
549 break;
550 }
551 }
552 }
553
554 return { inAncestry, inDescendents };
555}
556
557
565static std::vector<wxString> CheckForParentalChainConflicts( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr,
566 LIB_SYMBOL& aSymbol,
567 bool aFlattenSymbol,
568 const wxString& newSymbolName,
569 const wxString& newLibraryName )
570{
571 std::vector<wxString> conflicts;
572 const wxString& oldLibraryName = aSymbol.GetLibId().GetLibNickname();
573
574 if( newLibraryName == oldLibraryName || aFlattenSymbol )
575 {
576 // Saving into the same library - the only conflict could be the symbol itself
577 // Different library and flattening - ditto
578 if( aLibMgr.SymbolNameInUse( newSymbolName, newLibraryName ) )
579 conflicts.push_back( newSymbolName );
580 }
581 else
582 {
583 // In a different library with parents - check the whole chain
584 const std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain = GetParentChain( aSymbol, true );
585
586 for( size_t i = 0; i < parentChain.size(); ++i )
587 {
588 if( i == 0 )
589 {
590 // This is the leaf symbol which the user actually named
591 if( aLibMgr.SymbolNameInUse( newSymbolName, newLibraryName ) )
592 conflicts.push_back( newSymbolName );
593 }
594 else
595 {
596 std::shared_ptr<LIB_SYMBOL> chainSymbol = parentChain[i];
597
598 if( aLibMgr.SymbolNameInUse( chainSymbol->GetName(), newLibraryName ) )
599 conflicts.push_back( chainSymbol->GetName() );
600 }
601 }
602 }
603
604 return conflicts;
605}
606
607
615{
616public:
618 {
619 // Just overwrite any existing symbols in the target library
621 // Add a suffix until we find a name that doesn't conflict
623 // Could have a mode that asks for every one, be then we'll need a fancier
624 // SAVE_SYMBOL_AS_DIALOG subdialog with Overwrite/Rename/Prompt/Cancel
625 // PROMPT
626 };
627
628 SYMBOL_SAVE_AS_HANDLER( LIB_SYMBOL_LIBRARY_MANAGER& aLibMgr, CONFLICT_STRATEGY aStrategy, bool aValueFollowsName ) :
629 m_libMgr( aLibMgr ),
630 m_strategy( aStrategy ),
631 m_valueFollowsName( aValueFollowsName )
632 {
633 }
634
635 bool DoSave( LIB_SYMBOL& symbol, const wxString& aNewSymName, const wxString& aNewLibName, bool aFlattenSymbol )
636 {
637 std::unique_ptr<LIB_SYMBOL> flattenedSymbol; // for ownership
638 std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain;
639
640 const bool sameLib = aNewLibName == symbol.GetLibId().GetLibNickname().wx_str();
641
642 if( aFlattenSymbol )
643 {
644 // If we're not copying parent symbols, we need to flatten the symbol
645 // and only save that.
646 flattenedSymbol = symbol.Flatten();
647 wxCHECK( flattenedSymbol, false );
648
649 parentChain.push_back( flattenedSymbol->SharedPtr() );
650 }
651 else if( sameLib )
652 {
653 // If we're saving into the same library, we don't need to check the parental chain
654 // because we can just keep the same parent symbol
655 parentChain.push_back( symbol.SharedPtr() );
656 }
657 else
658 {
659 // Need to copy all parent symbols
660 parentChain = GetParentChain( symbol, true );
661 }
662
663 std::vector<wxString> newNames;
664
665 // Iterate backwards (i.e. from the root down)
666 for( int i = (int) parentChain.size() - 1; i >= 0; --i )
667 {
668 std::shared_ptr<LIB_SYMBOL>& oldSymbol = parentChain[i];
669 LIB_SYMBOL new_symbol( *oldSymbol );
670
671 wxString newName;
672 if( i == 0 )
673 {
674 // This is the leaf symbol which the user actually named
675 newName = aNewSymName;
676 }
677 else
678 {
679 // Somewhere in the inheritance chain, use the conflict resolution strategy
680 newName = oldSymbol->GetName();
681 }
682
683 newName = resolveConflict( newName, aNewLibName );
684 new_symbol.SetName( newName );
685
687 new_symbol.GetValueField().SetText( newName );
688
689 if( i == (int) parentChain.size() - 1 )
690 {
691 // This is the root symbol
692 // Nothing extra to do, it's just a simple symbol with no parents
693 }
694 else
695 {
696 // Get the buffered new copy in the new library (with the name we gave it)
697 LIB_SYMBOL* newParent = m_libMgr.GetSymbol( newNames.back(), aNewLibName );
698
699 // We should have stored this already, why didn't we get it back?
700 wxASSERT( newParent );
701 new_symbol.SetParent( newParent );
702
703 // Keep the recorded parent name in sync with the (possibly renamed) buffered
704 // parent so serialization has a valid fallback if the live pointer is lost.
705 if( newParent )
706 new_symbol.SetParentName( newParent->GetName() );
707 }
708
709 newNames.push_back( newName );
710 m_libMgr.UpdateSymbol( &new_symbol, aNewLibName );
711 }
712
713 return true;
714 }
715
716private:
717 wxString resolveConflict( const wxString& proposed, const wxString& aNewLibName ) const
718 {
719 switch( m_strategy )
720 {
722 {
723 // In an overwrite strategy, we don't care about conflicts
724 return proposed;
725 }
727 {
728 // In a rename strategy, we need to find a name that doesn't conflict
729 int suffix = 1;
730
731 while( true )
732 {
733 wxString newName = wxString::Format( "%s_%d", proposed, suffix );
734
735 if( !m_libMgr.SymbolNameInUse( newName, aNewLibName ) )
736 return newName;
737
738 ++suffix;
739 }
740 break;
741 }
742 // No default
743 }
744
745 wxFAIL_MSG( "Invalid conflict strategy" );
746 return "";
747 }
748
752};
753
754
761
762
764{
765public:
766 using SymLibNameValidator = std::function<int( const wxString& libName, const wxString& symbolName )>;
767
775
777 PARAMS& aParams,
778 SymLibNameValidator aValidator,
779 const std::vector<wxString>& aParentSymbolNames ) :
780 EDA_LIST_DIALOG( aParent, _( "Save Symbol As" ), false ),
781 m_validator( std::move( aValidator ) ),
782 m_params( aParams )
783 {
784 wxArrayString headers;
785 std::vector<wxArrayString> itemsToDisplay;
786
787 if( aParentSymbolNames.size() )
788 {
789 // This is a little trick to word - when saving to another library, "copy parents" makes sense,
790 // but when in the same library, the parents will be untouched in any case.
791 const wxString aParentNames = AccumulateDescriptions( aParentSymbolNames );
792 AddExtraCheckbox(
793 wxString::Format( "Flatten/remove symbol inheritance (current parent symbols: %s)", aParentNames ),
794 &m_params.m_FlattenSymbol );
795 }
796
797 aParent->GetLibraryItemsForListDialog( headers, itemsToDisplay );
798 initDialog( headers, itemsToDisplay, m_params.m_LibraryName );
799
800 SetListLabel( _( "Save in library:" ) );
801 SetOKLabel( _( "Save" ) );
802
803 wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
804
805 wxStaticText* label = new wxStaticText( this, wxID_ANY, _( "Name:" ) );
806 bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
807
808 m_symbolNameCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString );
809 bNameSizer->Add( m_symbolNameCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
810
811 wxButton* newLibraryButton = new wxButton( this, ID_MAKE_NEW_LIBRARY, _( "New Library..." ) );
812 m_ButtonsSizer->Prepend( 80, 20 );
813 m_ButtonsSizer->Prepend( newLibraryButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 );
814
815 GetSizer()->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
816
817 Bind( wxEVT_BUTTON,
818 [this]( wxCommandEvent& )
819 {
820 EndModal( ID_MAKE_NEW_LIBRARY );
822
823 // Move nameTextCtrl to the head of the tab-order
824 if( GetChildren().DeleteObject( m_symbolNameCtrl ) )
825 GetChildren().Insert( m_symbolNameCtrl );
826
828
830
831 Layout();
832 GetSizer()->Fit( this );
833
834 Centre();
835 }
836
837protected:
838 wxString getSymbolName() const
839 {
840 wxString symbolName = m_symbolNameCtrl->GetValue();
841 symbolName.Trim( true );
842 symbolName.Trim( false );
843 symbolName.Replace( " ", "_" );
844 return EscapeString( symbolName, CTX_LIBID );
845 }
846
847 bool TransferDataToWindow() override
848 {
849 m_symbolNameCtrl->SetValue( UnescapeString( m_params.m_SymbolName ) );
850 return true;
851 }
852
854 {
855 // This updates m_params.m_FlattenSymbol
856 // Do this now, so the validator can use it
858
859 m_params.m_SymbolName = getSymbolName();
860 m_params.m_LibraryName = GetTextSelection();
861
862 int ret = m_validator( m_params.m_LibraryName, m_params.m_SymbolName );
863
864 if( ret == wxID_CANCEL )
865 return false;
866
867 if( ret == ID_OVERWRITE_CONFLICTS )
869 else if( ret == ID_RENAME_CONFLICTS )
871
872 return true;
873 }
874
875private:
876 wxTextCtrl* m_symbolNameCtrl;
879};
880
881
883{
884 LIB_SYMBOL* symbol = getTargetSymbol();
885
886 if( !symbol )
887 return;
888
889 LIB_ID old_lib_id = symbol->GetLibId();
890 wxString symbolName = old_lib_id.GetLibItemName();
891 wxString libraryName = old_lib_id.GetLibNickname();
892 bool valueFollowsName = symbol->GetValueField().GetText() == symbolName;
893 wxString msg;
894 bool done = false;
895 bool flattenSymbol = false;
896
897 // This is the function that will be called when the user clicks OK in the dialog and checks
898 // if the proposed name has problems, and asks for clarification.
899 const auto dialogValidatorFunc =
900 [&]( const wxString& newLib, const wxString& newName ) -> int
901 {
902 if( newLib.IsEmpty() )
903 {
904 wxMessageBox( _( "A library must be specified." ) );
905 return wxID_CANCEL;
906 }
907
908 if( newName.IsEmpty() )
909 {
910 wxMessageBox( _( "Symbol must have a name." ) );
911 return wxID_CANCEL;
912 }
913
914 if( m_libMgr->IsLibraryReadOnly( newLib ) )
915 {
916 msg = wxString::Format( _( "Library '%s' is read-only. Choose a "
917 "different library to save the symbol '%s' to." ),
918 newLib,
919 UnescapeString( newName ) );
920 wxMessageBox( msg );
921 return wxID_CANCEL;
922 }
923
928 const auto& [inAncestry, inDescendents] = CheckSavingIntoOwnInheritance( *m_libMgr, *symbol,
929 newName, newLib );
930
931 if( inAncestry )
932 {
933 msg = wxString::Format( _( "Symbol '%s' cannot replace another symbol '%s' "
934 "that it descends from" ),
935 symbolName,
936 UnescapeString( newName ) );
937 wxMessageBox( msg );
938 return wxID_CANCEL;
939 }
940
941 if( inDescendents )
942 {
943 msg = wxString::Format( _( "Symbol '%s' cannot replace another symbol '%s' "
944 "that is a descendent of it." ),
945 symbolName,
946 UnescapeString( newName ) );
947 wxMessageBox( msg );
948 return wxID_CANCEL;
949 }
950
951 const std::vector<wxString> conflicts =
952 CheckForParentalChainConflicts( *m_libMgr, *symbol, flattenSymbol, newName, newLib );
953
954 if( conflicts.size() == 1 && conflicts.front() == newName )
955 {
956 // The simplest case is when the symbol itself has a conflict
957 msg = wxString::Format( _( "Symbol '%s' already exists in library '%s'. "
958 "Do you want to overwrite it?" ),
959 UnescapeString( newName ),
960 newLib );
961
962 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
963 errorDlg.SetOKLabel( _( "Overwrite" ) );
964
965 return errorDlg.ShowModal() == wxID_OK ? ID_OVERWRITE_CONFLICTS : (int) wxID_CANCEL;
966 }
967 else if( !conflicts.empty() )
968 {
969 // If there are conflicts in the parental chain, we need to ask the user
970 // if they want to overwrite all of them.
971 // A more complex UI might allow the user to re-parent the symbol to an
972 // existing symbol in the target lib, or rename all the parents somehow.
973 msg = wxString::Format( _( "The following symbols in the inheritance chain of "
974 "'%s' already exist in library '%s':\n" ),
975 UnescapeString( symbolName ),
976 newLib );
977
978 for( const wxString& conflict : conflicts )
979 msg += wxString::Format( " %s\n", conflict );
980
981 msg += _( "\nDo you want to overwrite all of them, or rename the new symbols?" );
982
983 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
984 errorDlg.SetYesNoCancelLabels( _( "Overwrite All" ), _( "Rename All" ), _( "Cancel" ) );
985
986 switch( errorDlg.ShowModal() )
987 {
988 case wxID_YES: return ID_OVERWRITE_CONFLICTS;
989 case wxID_NO: return ID_RENAME_CONFLICTS;
990 default: return wxID_CANCEL;
991 }
992 }
993
994 return wxID_OK;
995 };
996
998
999 std::vector<wxString> parentSymbolNames;
1000 if( symbol->IsDerived() )
1001 {
1002 // The parents are everything but the leaf symbol
1003 std::vector<std::shared_ptr<LIB_SYMBOL>> parentChain = GetParentChain( *symbol, false );
1004
1005 for( const auto& parent : parentChain )
1006 parentSymbolNames.push_back( parent->GetName() );
1007 }
1008
1010 symbolName,
1011 libraryName,
1012 flattenSymbol,
1013 strategy,
1014 };
1015
1016 // Keep asking the user for a new name until they give a valid one or cancel the operation
1017 while( !done )
1018 {
1019 SAVE_SYMBOL_AS_DIALOG dlg( this, params, dialogValidatorFunc, parentSymbolNames );
1020
1021 int ret = dlg.ShowModal();
1022
1023 switch( ret )
1024 {
1025 case wxID_CANCEL:
1026 return;
1027
1028 case wxID_OK: // No conflicts
1031 {
1032 done = true;
1033 break;
1034 }
1036 {
1037 wxFileName newLibrary( AddLibraryFile( true ) );
1038 params.m_LibraryName = newLibrary.GetName();
1039
1040 // Go round again to ask for the symbol name
1041 break;
1042 }
1043
1044 default:
1045 break;
1046 }
1047 }
1048
1049 SYMBOL_SAVE_AS_HANDLER saver( *m_libMgr, params.m_ConflictStrategy, valueFollowsName );
1050
1051 saver.DoSave( *symbol, params.m_SymbolName, params.m_LibraryName, params.m_FlattenSymbol );
1052
1053 SyncLibraries( false );
1054
1055 if( aOpenCopy )
1056 LoadSymbol( params.m_SymbolName, params.m_LibraryName, 1 );
1057}
1058
1059
1061{
1062 wxString msg;
1063 LIB_SYMBOL* symbol = getTargetSymbol();
1064
1065 if( !symbol )
1066 {
1067 ShowInfoBarError( _( "There is no symbol selected to save." ) );
1068 return;
1069 }
1070
1071 wxFileName fn;
1072
1073 fn.SetName( symbol->GetName().Lower() );
1075
1076 wxFileDialog dlg( this, _( "Export Symbol" ), m_mruPath, fn.GetFullName(),
1078
1080
1081 if( dlg.ShowModal() == wxID_CANCEL )
1082 return;
1083
1085
1086 fn = dlg.GetPath();
1087 fn.MakeAbsolute();
1088
1089 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
1090
1091 wxString libraryName;
1092 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = symbol->Flatten();
1093
1094 for( const wxString& candidate : m_libMgr->GetLibraryNames() )
1095 {
1096 if( auto uri = manager.GetFullURI( LIBRARY_TABLE_TYPE::SYMBOL, candidate, true ); uri )
1097 {
1098 if( *uri == fn.GetFullPath() )
1099 libraryName = candidate;
1100 }
1101 }
1102
1103 if( !libraryName.IsEmpty() )
1104 {
1105 SYMBOL_SAVE_AS_HANDLER saver( *m_libMgr, strategy, false );
1106
1107 if( m_libMgr->IsLibraryReadOnly( libraryName ) )
1108 {
1109 msg = wxString::Format( _( "Library '%s' is read-only." ), libraryName );
1110 DisplayError( this, msg );
1111 return;
1112 }
1113
1114 if( m_libMgr->SymbolNameInUse( symbol->GetName(), libraryName ) )
1115 {
1116 msg = wxString::Format( _( "Symbol '%s' already exists in library '%s'." ),
1117 symbol->GetName(), libraryName );
1118
1119 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1120 errorDlg.SetOKLabel( _( "Overwrite" ) );
1121 errorDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1122
1123 if( errorDlg.ShowModal() == wxID_CANCEL )
1124 return;
1125 }
1126
1127 saver.DoSave( *flattenedSymbol, symbol->GetName(), libraryName, false );
1128
1129 SyncLibraries( false );
1130 return;
1131 }
1132
1133 LIB_SYMBOL* old_symbol = nullptr;
1134 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() );
1135
1136 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1137 pluginType = SCH_IO_MGR::SCH_KICAD;
1138
1139 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pluginType ) );
1140
1141 if( fn.FileExists() )
1142 {
1143 try
1144 {
1145 old_symbol = pi->LoadSymbol( fn.GetFullPath(), symbol->GetName() );
1146 }
1147 catch( const IO_ERROR& ioe )
1148 {
1149 msg.Printf( _( "Error occurred attempting to load symbol library file '%s'." ),
1150 fn.GetFullPath() );
1151 DisplayErrorMessage( this, msg, ioe.What() );
1152 return;
1153 }
1154
1155 if( old_symbol )
1156 {
1157 msg.Printf( _( "Symbol %s already exists in library '%s'." ),
1158 UnescapeString( symbol->GetName() ),
1159 fn.GetFullName() );
1160
1161 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1162 errorDlg.SetOKLabel( _( "Overwrite" ) );
1163 errorDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1164
1165 if( errorDlg.ShowModal() == wxID_CANCEL )
1166 return;
1167 }
1168 }
1169
1170 if( !fn.IsDirWritable() )
1171 {
1172 msg.Printf( _( "Insufficient permissions to save library '%s'." ), fn.GetFullPath() );
1173 DisplayError( this, msg );
1174 return;
1175 }
1176
1177 try
1178 {
1179 if( !fn.FileExists() )
1180 pi->CreateLibrary( fn.GetFullPath() );
1181
1182 // The flattened symbol is most likely what the user would want. As some point in
1183 // the future as more of the symbol library inheritance is implemented, this may have
1184 // to be changes to save symbols of inherited symbols.
1185 pi->SaveSymbol( fn.GetFullPath(), flattenedSymbol.release() );
1186 }
1187 catch( const IO_ERROR& ioe )
1188 {
1189 msg.Printf( _( "Failed to create symbol library file '%s'." ), fn.GetFullPath() );
1190 DisplayErrorMessage( this, msg, ioe.What() );
1191 msg.Printf( _( "Error creating symbol library '%s'." ), fn.GetFullName() );
1192 SetStatusText( msg );
1193 return;
1194 }
1195
1196 m_mruPath = fn.GetPath();
1197
1198 msg.Printf( _( "Symbol %s saved to library '%s'." ),
1199 UnescapeString( symbol->GetName() ),
1200 fn.GetFullPath() );
1201 SetStatusText( msg );
1202}
1203
1204
1206{
1207 wxCHECK( m_symbol, /* void */ );
1208
1209 wxString lib = m_symbol->GetLibNickname();
1210
1211 if( !lib.IsEmpty() && aOldName && *aOldName != m_symbol->GetName() )
1212 {
1213 // Test the current library for name conflicts
1214 if( m_libMgr->SymbolNameInUse( m_symbol->GetName(), lib ) )
1215 {
1216 wxString msg = wxString::Format( _( "Symbol name '%s' already in use." ),
1217 UnescapeString( m_symbol->GetName() ) );
1218
1219 DisplayErrorMessage( this, msg );
1220 m_symbol->SetName( *aOldName );
1221 }
1222 else
1223 {
1224 m_libMgr->UpdateSymbolAfterRename( m_symbol, *aOldName, lib );
1225 }
1226
1227 // Reselect the renamed symbol
1228 m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, m_symbol->GetName() ) );
1229 }
1230
1231 wxDataViewItem treeItem = m_libMgr->GetAdapter()->FindItem( LIB_ID( lib, m_symbol->GetName() ) );
1232
1233 if( treeItem.IsOk() )
1234 UpdateLibraryTree( treeItem, m_symbol );
1235
1237 UpdateTitle();
1238
1239 // N.B. The view needs to be rebuilt first as the Symbol Properties change may invalidate
1240 // the view pointers by rebuilting the field table
1241 RebuildView();
1243
1244 OnModify();
1245}
1246
1247
1249{
1250 std::vector<LIB_ID> toDelete = GetSelectedLibIds();
1251
1252 if( toDelete.empty() )
1253 toDelete.emplace_back( GetTargetLibId() );
1254
1255 for( LIB_ID& libId : toDelete )
1256 {
1257 if( m_libMgr->IsSymbolModified( libId.GetLibItemName(), libId.GetLibNickname() )
1258 && !IsOK( this, wxString::Format( _( "The symbol '%s' has been modified.\n"
1259 "Do you want to remove it from the library?" ),
1260 libId.GetUniStringLibItemName() ) ) )
1261 {
1262 continue;
1263 }
1264
1265 wxArrayString derived;
1266
1267 if( m_libMgr->GetDerivedSymbolNames( libId.GetLibItemName(), libId.GetLibNickname(), derived ) > 0 )
1268 {
1269 wxString msg = _( "Deleting a base symbol will delete all symbols derived from it.\n\n" );
1270
1271 msg += libId.GetLibItemName().wx_str() + _( " (base)\n" );
1272
1273 for( const wxString& name : derived )
1274 msg += name + wxT( "\n" );
1275
1276 KICAD_MESSAGE_DIALOG dlg( this, msg, _( "Warning" ), wxYES_NO | wxICON_WARNING | wxCENTER );
1277 dlg.SetExtendedMessage( wxT( " " ) );
1278 dlg.SetYesNoLabels( _( "Delete All Listed Symbols" ), _( "Cancel" ) );
1279
1280 if( dlg.ShowModal() == wxID_NO )
1281 continue;
1282 }
1283
1284 if( m_tabsPanel )
1285 {
1286 // Close only the tabs for the symbol being deleted and the symbols derived from it,
1287 // which are removed along with it. The other open tabs stay put.
1288 closeSymbolTab( libId );
1289
1290 for( const wxString& derivedName : derived )
1291 closeSymbolTab( LIB_ID( libId.GetLibNickname().wx_str(), derivedName ) );
1292 }
1293 else if( GetCurSymbol() )
1294 {
1295 for( const std::shared_ptr<LIB_SYMBOL>& symbol : GetParentChain( *GetCurSymbol() ) )
1296 {
1297 if( symbol->GetLibId() == libId )
1298 {
1299 emptyScreen();
1300 break;
1301 }
1302 }
1303 }
1304
1305 m_libMgr->RemoveSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1306 }
1307
1308 m_treePane->GetLibTree()->RefreshLibTree();
1309}
1310
1311
1313{
1314 std::vector<LIB_ID> symbols;
1315
1316 if( GetTreeLIBIDs( symbols ) == 0 )
1317 return;
1318
1319 STRING_FORMATTER formatter;
1320
1321 for( LIB_ID& libId : symbols )
1322 {
1323 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(),
1324 libId.GetLibNickname() );
1325
1326 if( !symbol )
1327 continue;
1328
1329 std::unique_ptr<LIB_SYMBOL> tmp = symbol->Flatten();
1330 SCH_IO_KICAD_SEXPR::FormatLibSymbol( tmp.get(), formatter );
1331 }
1332
1333 std::string prettyData = formatter.GetString();
1334 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES );
1335
1336 wxLogNull doNotLog; // disable logging of failed clipboard actions
1337
1338 auto clipboard = wxTheClipboard;
1339 wxClipboardLocker clipboardLock( clipboard );
1340
1341 if( !clipboardLock || !clipboard->IsOpened() )
1342 return;
1343
1344 auto data = new wxTextDataObject( wxString( prettyData.c_str(), wxConvUTF8 ) );
1345 clipboard->SetData( data );
1346
1347 clipboard->Flush();
1348}
1349
1350
1351void SYMBOL_EDIT_FRAME::DuplicateSymbol( bool aFromClipboard )
1352{
1353 LIB_ID libId = GetTargetLibId();
1354 wxString lib = libId.GetLibNickname();
1355
1356 if( !m_libMgr->LibraryExists( lib ) )
1357 return;
1358
1359 std::vector<LIB_SYMBOL*> newSymbols;
1360
1361 if( aFromClipboard )
1362 {
1363 std::string clipboardData = GetClipboardUTF8();
1364
1365 try
1366 {
1367 newSymbols = SCH_IO_KICAD_SEXPR::ParseLibSymbols( clipboardData, "Clipboard" );
1368 }
1369 catch( IO_ERROR& e )
1370 {
1371 wxLogMessage( wxS( "Can not paste: %s" ), e.Problem() );
1372 }
1373 }
1374 else if( LIB_SYMBOL* srcSymbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(), lib ) )
1375 {
1376 newSymbols.emplace_back( new LIB_SYMBOL( *srcSymbol ) );
1377
1378 // Derive from same parent.
1379 if( srcSymbol->IsDerived() )
1380 {
1381 if( std::shared_ptr<LIB_SYMBOL> srcParent = srcSymbol->GetParent().lock() )
1382 newSymbols.back()->SetParent( srcParent.get() );
1383 }
1384 }
1385
1386 if( newSymbols.empty() )
1387 return;
1388
1389 for( LIB_SYMBOL* symbol : newSymbols )
1390 {
1391 ensureUniqueName( symbol, lib );
1392 m_libMgr->UpdateSymbol( symbol, lib );
1393
1394 LoadOneLibrarySymbolAux( symbol, lib, GetUnit(), GetBodyStyle() );
1395 }
1396
1397 SyncLibraries( false );
1398 m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newSymbols[0]->GetName() ) );
1399
1400 for( LIB_SYMBOL* symbol : newSymbols )
1401 delete symbol;
1402}
1403
1404
1405void SYMBOL_EDIT_FRAME::ensureUniqueName( LIB_SYMBOL* aSymbol, const wxString& aLibrary )
1406{
1407 if( aSymbol )
1408 {
1409 int i = 1;
1410 wxString newName = aSymbol->GetName();
1411
1412 // Append a number to the name until the name is unique in the library.
1413 while( m_libMgr->SymbolNameInUse( newName, aLibrary ) )
1414 newName.Printf( "%s_%d", aSymbol->GetName(), i++ );
1415
1416 aSymbol->SetName( newName );
1417 }
1418}
1419
1420
1421void SYMBOL_EDIT_FRAME::Revert( bool aConfirm )
1422{
1423 LIB_ID libId = GetTargetLibId();
1424 const wxString& libName = libId.GetLibNickname();
1425
1426 // Empty if this is the library itself that is selected.
1427 const wxString& symbolName = libId.GetLibItemName();
1428
1429 wxString msg = wxString::Format( _( "Revert '%s' to last version saved?" ),
1430 symbolName.IsEmpty() ? libName : symbolName );
1431
1432 if( aConfirm && !ConfirmRevertDialog( this, msg ) )
1433 return;
1434
1435 bool reload_currentSymbol = false;
1436 wxString curr_symbolName = symbolName;
1437
1438 if( GetCurSymbol() )
1439 {
1440 // the library itself is reverted: the current symbol will be reloaded only if it is
1441 // owned by this library
1442 if( symbolName.IsEmpty() )
1443 {
1444 LIB_ID curr_libId = GetCurSymbol()->GetLibId();
1445 reload_currentSymbol = libName == curr_libId.GetLibNickname().wx_str();
1446
1447 if( reload_currentSymbol )
1448 curr_symbolName = curr_libId.GetUniStringLibItemName();
1449 }
1450 else
1451 {
1452 reload_currentSymbol = IsCurrentSymbol( libId );
1453 }
1454 }
1455
1456 int unit = m_unit;
1457
1458 if( reload_currentSymbol )
1459 emptyScreen();
1460
1461 if( symbolName.IsEmpty() )
1462 {
1463 m_libMgr->RevertLibrary( libName );
1464 }
1465 else
1466 {
1467 libId = m_libMgr->RevertSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1468
1469 m_treePane->GetLibTree()->SelectLibId( libId );
1470 m_libMgr->ClearSymbolModified( libId.GetLibItemName(), libId.GetLibNickname() );
1471 }
1472
1473 if( reload_currentSymbol && m_libMgr->SymbolExists( curr_symbolName, libName ) )
1474 LoadSymbol( curr_symbolName, libName, unit );
1475
1476 m_treePane->Refresh();
1477}
1478
1479
1481{
1482 wxCHECK_RET( m_libMgr, "Library manager object not created." );
1483
1484 Revert( false );
1485 m_libMgr->RevertAll();
1486}
1487
1488
1489void SYMBOL_EDIT_FRAME::LoadSymbol( const wxString& aAlias, const wxString& aLibrary, int aUnit )
1490{
1492 {
1493 if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
1494 [&]() -> bool
1495 {
1496 return saveCurrentSymbol();
1497 } ) )
1498 {
1499 return;
1500 }
1501 }
1502
1503 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( aAlias, aLibrary );
1504
1505 if( !symbol )
1506 {
1507 DisplayError( this, wxString::Format( _( "Symbol %s not found in library '%s'." ),
1508 aAlias,
1509 aLibrary ) );
1510 m_treePane->GetLibTree()->RefreshLibTree();
1511 return;
1512 }
1513
1514 // Optimize default edit options for this symbol
1515 // Usually if units are locked, graphic items are specific to each unit
1516 // and if units are interchangeable, graphic items are common to units
1518 tools->SetDrawSpecificUnit( symbol->UnitsLocked() );
1519
1520 LoadOneLibrarySymbolAux( symbol, aLibrary, aUnit, 0 );
1521}
1522
1523
1524bool SYMBOL_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile )
1525{
1526 wxFileName fn;
1527 wxString msg;
1529 SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::SCH_FILE_T::SCH_KICAD;
1530 PROJECT& prj = Prj();
1531
1533
1535
1536 if( !aNewFile && ( aLibrary.empty() || !adapter->HasLibrary( aLibrary ) ) )
1537 {
1538 ShowInfoBarError( _( "No library specified." ) );
1539 return false;
1540 }
1541
1542 if( aNewFile )
1543 {
1544 SEARCH_STACK* search = PROJECT_SCH::SchSearchS( &prj );
1545
1546 // Get a new name for the library
1547 wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
1548
1549 if( !default_path )
1550 default_path = search->LastVisitedPath();
1551
1552 fn.SetName( aLibrary );
1554
1555 wxString wildcards = FILEEXT::KiCadSymbolLibFileWildcard();
1556
1557 wxFileDialog dlg( this, wxString::Format( _( "Save Library '%s' As..." ), aLibrary ), default_path,
1558 fn.GetFullName(), wildcards, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1559
1560 SYMBOL_LIBRARY_SAVE_AS_FILEDLG_HOOK saveAsHook( type );
1561 dlg.SetCustomizeHook( saveAsHook );
1562
1564
1565 if( dlg.ShowModal() == wxID_CANCEL )
1566 return false;
1567
1568 fn = dlg.GetPath();
1569
1570 prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() );
1571
1572 if( fn.GetExt().IsEmpty() )
1574
1575 type = saveAsHook.GetOption();
1576 }
1577 else
1578 {
1579 std::optional<LIBRARY_TABLE_ROW*> optRow = adapter->GetRow( aLibrary );
1580 wxCHECK( optRow, false );
1581
1582 fn = LIBRARY_MANAGER::GetFullURI( *optRow, true );
1584
1585 if( fileType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1586 fileType = SCH_IO_MGR::SCH_KICAD;
1587 }
1588
1589 // Verify the user has write privileges before attempting to save the library file.
1590 if( !aNewFile && m_libMgr->IsLibraryReadOnly( aLibrary ) )
1591 return false;
1592
1593 ClearMsgPanel();
1594
1595 // Copy .kicad_symb file to .bak.
1596 if( !backupFile( fn, "bak" ) )
1597 return false;
1598
1599 if( !m_libMgr->SaveLibrary( aLibrary, fn.GetFullPath(), fileType ) )
1600 {
1601 msg.Printf( _( "Failed to save changes to symbol library file '%s'." ),
1602 fn.GetFullPath() );
1603 DisplayErrorMessage( this, _( "Error Saving Library" ), msg );
1604 return false;
1605 }
1606
1607 if( !aNewFile )
1608 {
1609 m_libMgr->ClearLibraryModified( aLibrary );
1610
1612
1613 // Update the library modification time so that we don't reload based on the watcher
1614 if( aLibrary == getTargetLib() )
1615 {
1616 if( fn.DirExists() )
1617 {
1619 fn.GetFullPath(),
1620 wxS( "*." ) + wxString( FILEEXT::KiCadSymbolLibFileExtension ) ) );
1621 }
1622 else if( fn.FileExists() )
1623 {
1624 wxLogNull silence;
1625 SetSymModificationTime( fn.GetModificationTime().GetValue().GetValue() );
1626 }
1627 }
1628 }
1629 else
1630 {
1631 bool resyncLibTree = false;
1632 wxString originalLibNickname = getTargetLib();
1633 wxString forceRefresh;
1634
1635 switch( type )
1636 {
1638 resyncLibTree = replaceLibTableEntry( originalLibNickname, fn.GetFullPath() );
1639 forceRefresh = originalLibNickname;
1640 break;
1641
1643 resyncLibTree = addLibTableEntry( fn.GetFullPath() );
1644 break;
1645
1647 resyncLibTree = addLibTableEntry( fn.GetFullPath(), LIBRARY_TABLE_SCOPE::PROJECT );
1648 break;
1649
1650 default:
1651 break;
1652 }
1653
1654 if( resyncLibTree )
1655 {
1657 SyncLibraries( true, false, forceRefresh );
1659 }
1660 }
1661
1662 ClearMsgPanel();
1663 msg.Printf( _( "Symbol library file '%s' saved." ), fn.GetFullPath() );
1665
1666 return true;
1667}
1668
1669
1670bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
1671{
1672 wxString msg, msg2;
1673 bool doSave = true;
1674 int dirtyCount = 0;
1675 bool applyToAll = false;
1676 bool retv = true;
1677
1678 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1679 {
1680 if( m_libMgr->IsLibraryModified( libNickname ) )
1681 dirtyCount++;
1682 }
1683
1684 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1685 {
1686 if( m_libMgr->IsLibraryModified( libNickname ) )
1687 {
1688 if( aRequireConfirmation && !applyToAll )
1689 {
1690 msg.Printf( _( "Save changes to '%s' before closing?" ), libNickname );
1691
1692 switch( UnsavedChangesDialog( this, msg, dirtyCount > 1 ? &applyToAll : nullptr ) )
1693 {
1694 case wxID_YES: doSave = true; break;
1695 case wxID_NO: doSave = false; break;
1696 default:
1697 case wxID_CANCEL: return false;
1698 }
1699 }
1700
1701 if( doSave )
1702 {
1703 // If saving under existing name fails then do a Save As..., and if that
1704 // fails then cancel close action.
1705 if( m_libMgr->IsLibraryReadOnly( libNickname ) )
1706 {
1707 msg.Printf( _( "Symbol library '%s' is not writable." ), libNickname );
1708 msg2 = _( "You must save to a different location." );
1709
1710 if( dirtyCount == 1 )
1711 {
1712 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) != wxID_OK )
1713 {
1714 retv = false;
1715 continue;
1716 }
1717 }
1718 else
1719 {
1720 m_infoBar->Dismiss();
1721 m_infoBar->ShowMessageFor( msg + wxS( " " ) + msg2,
1722 2000, wxICON_EXCLAMATION );
1723
1724 while( m_infoBar->IsShownOnScreen() )
1725 wxSafeYield();
1726
1727 retv = false;
1728 continue;
1729 }
1730 }
1731 else if( saveLibrary( libNickname, false ) )
1732 {
1733 continue;
1734 }
1735
1736 if( !saveLibrary( libNickname, true ) )
1737 retv = false;
1738 }
1739 }
1740 }
1741
1742 UpdateTitle();
1743 return retv;
1744}
1745
1746
1748{
1750
1751 if( !m_symbol )
1752 return;
1753
1754 wxString msg = m_symbol->GetName();
1755
1756 AppendMsgPanel( _( "Name" ), UnescapeString( msg ), 8 );
1757
1758 if( m_symbol->IsDerived() )
1759 {
1760 std::shared_ptr<LIB_SYMBOL> parent = m_symbol->GetParent().lock();
1761
1762 msg = parent ? parent->GetName() : _( "Undefined!" );
1763 AppendMsgPanel( _( "Parent" ), UnescapeString( msg ), 8 );
1764 }
1765
1766 if( m_symbol->IsGlobalPower() )
1767 msg = _( "Power Symbol" );
1768 else if( m_symbol->IsLocalPower() )
1769 msg = _( "Power Symbol (Local)" );
1770 else
1771 msg = _( "Symbol" );
1772
1773 AppendMsgPanel( _( "Type" ), msg, 8 );
1774 AppendMsgPanel( _( "Description" ), m_symbol->GetDescription(), 8 );
1775 AppendMsgPanel( _( "Keywords" ), m_symbol->GetKeyWords() );
1776 AppendMsgPanel( _( "Datasheet" ), m_symbol->GetDatasheetField().GetText() );
1777}
const char * name
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION zoomFitScreen
Definition actions.h:138
void SetContentModified(bool aModified=true)
Definition base_screen.h:55
wxString GetParentSymbolName() const
wxString GetName() const override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:79
void SetupStandardButtons(std::map< int, wxString > aLabels={})
int ShowModal() override
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
WX_INFOBAR * m_infoBar
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, INFOBAR_MESSAGE_TYPE aType=INFOBAR_MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
virtual void RecreateToolbars()
void ReCreateMenuBar()
Recreate the menu bar.
WX_INFOBAR * GetInfoBar()
virtual void ClearMsgPanel()
Clear all messages from the message panel.
void AppendMsgPanel(const wxString &aTextUpper, const wxString &aTextLower, int aPadding=6)
Append a message to the message panel.
void SetOKLabel(const wxString &aLabel)
void initDialog(const wxArrayString &aItemHeaders, const std::vector< wxArrayString > &aItemList, const wxString &aPreselectText)
wxString GetTextSelection(int aColumn=0)
Return the selected text from aColumn in the wxListCtrl in the dialog.
void SetListLabel(const wxString &aLabel)
void GetExtraCheckboxValues()
Fills in the value pointers from the checkboxes after the dialog has run.
EDA_LIST_DIALOG(wxWindow *aParent, const wxString &aTitle, const wxArrayString &aItemHeaders, const std::vector< wxArrayString > &aItemList, const wxString &aPreselectText=wxEmptyString, bool aSortList=true)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
virtual const wxString Problem() const
what was the problem?
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:51
int ShowModal() override
Definition kidialog.cpp:89
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition view.cpp:1686
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:398
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
std::optional< LIBRARY_TABLE_ROW * > GetRow(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
const wxString & Type() const
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
wxString GetUniStringLibId() const
Definition lib_id.h:144
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:108
const wxString GetUniStringLibNickname() const
Definition lib_id.h:84
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
Symbol library management helper that is specific to the symbol library editor frame.
Define a library symbol object.
Definition lib_symbol.h:79
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:148
bool UnitsLocked() const
Check whether symbol units are interchangeable.
Definition lib_symbol.h:283
bool IsDerived() const
Definition lib_symbol.h:196
LIB_ID GetSourceLibId() const
Definition lib_symbol.h:151
void SetParent(LIB_SYMBOL *aParent=nullptr)
wxString GetName() const override
Definition lib_symbol.h:141
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:329
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:88
bool IsMultiUnit() const override
Definition lib_symbol.h:767
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
void SetParentName(const wxString &aParentName)
Definition lib_symbol.h:852
virtual void SetName(const wxString &aName)
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:126
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
static SEARCH_STACK * SchSearchS(PROJECT *aProject)
Accessor for Eeschema search stack.
Container for project specific data.
Definition project.h:62
@ SCH_LIB_PATH
Definition project.h:216
virtual void SetRString(RSTRING_T aStringId, const wxString &aString)
Store a "retained string", which is any session and project specific string identified in enum RSTRIN...
Definition project.cpp:355
virtual const wxString & GetRString(RSTRING_T aStringId)
Return a "retained string", which is any session and project specific string identified in enum RSTRI...
Definition project.cpp:366
bool TransferDataFromWindow() override
std::function< int(const wxString &libName, const wxString &symbolName)> SymLibNameValidator
bool TransferDataToWindow() override
SymLibNameValidator m_validator
SAVE_SYMBOL_AS_DIALOG(SYMBOL_EDIT_FRAME *aParent, PARAMS &aParams, SymLibNameValidator aValidator, const std::vector< wxString > &aParentSymbolNames)
wxString getSymbolName() const
wxTextCtrl * m_symbolNameCtrl
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void GetLibraryItemsForListDialog(wxArrayString &aHeaders, std::vector< wxArrayString > &aItemsToDisplay)
wxString SelectLibrary(const wxString &aDialogTitle, const wxString &aListLabel, const std::vector< std::pair< wxString, bool * > > &aExtraCheckboxes={})
Display a list of loaded libraries and allows the user to select a library.
void setSymWatcher(const LIB_ID *aSymbol)
Creates (or removes) a watcher on the specified symbol library.
void SetSymModificationTime(long long aTimestamp)
Set the modification timestamp of the watched symbol library.
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
Schematic editor (Eeschema) main window.
void SaveSymbolToSchematic(const LIB_SYMBOL &aSymbol, const KIID &aSchematicSymbolUUID)
Update a schematic symbol from a LIB_SYMBOL.
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:128
void SetText(const wxString &aText) override
static void FormatLibSymbol(LIB_SYMBOL *aPart, OUTPUTFORMATTER &aFormatter)
static std::vector< LIB_SYMBOL * > ParseLibSymbols(std::string &aSymbolText, std::string aSource, int aFileVersion=SEXPR_SCHEMATIC_FILE_VERSION)
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the #SCH_FILE_T from the corresponding plugin type name: "kicad", "legacy",...
static SCH_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
Return a plugin type given a symbol library using the file extension of aLibPath.
Look for files in a number of paths.
const wxString LastVisitedPath(const wxString &aSubPathToSearch=wxEmptyString)
A quirky function inherited from old code that seems to serve particular needs in the UI.
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:418
const std::string & GetString()
Definition richio.h:441
One open symbol tab owning a working LIB_SYMBOL and screen lent to the frame while active.
The symbol library editor main window.
void ClearMsgPanel() override
Clear all messages from the message panel.
void UpdateAfterSymbolProperties(wxString *aOldName=nullptr)
void SaveAll()
Save all modified symbols and libraries.
bool IsLibraryTreeShown() const override
wxString getTargetLib() const
bool IsCurrentSymbol(const LIB_ID &aLibId) const
Restore the empty editor screen, without any symbol or library selected.
bool backupFile(const wxFileName &aOriginalFile, const wxString &aBackupExt)
Return currently edited symbol.
EDITOR_TABS_PANEL * m_tabsPanel
void RebuildSymbolUnitAndBodyStyleLists()
int GetTreeLIBIDs(std::vector< LIB_ID > &aSelection) const
LIB_ID GetTreeLIBID(int *aUnit=nullptr) const
Return the LIB_ID of the library or symbol selected in the symbol tree.
LIB_SYMBOL_LIBRARY_MANAGER * m_libMgr
wxString GetCurLib() const
The nickname of the current library being edited and empty string if none.
void Save()
Save the selected symbol or library.
void LoadSymbol(const wxString &aLibrary, const wxString &aSymbol, int Unit)
bool m_SyncPinEdit
Set to true to synchronize pins at the same position when editing symbols with multiple units or mult...
bool addLibTableEntry(const wxString &aLibFile, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::GLOBAL)
Add aLibFile to the symbol library table defined by aScope.
void Revert(bool aConfirm=true)
Revert unsaved changes in a symbol, restoring to the last saved state.
void centerItemIdleHandler(wxIdleEvent &aEvent)
bool replaceLibTableEntry(const wxString &aLibNickname, const wxString &aLibFile)
Replace the file path of the symbol library table entry aLibNickname with aLibFile.
bool IsSymbolFromSchematic() const
void DuplicateSymbol(bool aFromClipboard)
Insert a duplicate symbol.
void saveSymbolCopyAs(bool aOpenCopy)
KIID m_schematicSymbolUUID
RefDes of the symbol (only valid if symbol was loaded from schematic)
std::vector< LIB_ID > GetSelectedLibIds() const
void SyncLibraries(bool aShowProgress, bool aPreloadCancelled=false, const wxString &aForceRefresh=wxEmptyString)
Synchronize the library manager to the symbol library table, and then the symbol tree to the library ...
SYMBOL_EDITOR_TAB_CONTEXT * findOrCreateSymbolTab(const wxString &aLib, const wxString &aName, int aUnit, int aBodyStyle, bool aAsPreview, bool *aWasCreated=nullptr)
Open aName from aLib in a tab, creating it when absent, and return the activated context.
LIB_SYMBOL * GetCurSymbol() const
Return the current symbol being edited or NULL if none selected.
void UpdateSymbolMsgPanelInfo()
Display the documentation of the selected symbol.
LIB_ID GetTargetLibId() const override
Return either the symbol selected in the symbol tree (if context menu is active) or the symbol on the...
bool saveLibrary(const wxString &aLibrary, bool aNewFile)
Save the changes to the current library.
void SelectActiveLibrary(const wxString &aLibrary=wxEmptyString)
Set the current active library to aLibrary.
int m_bodyStyle
Flag if the symbol being edited was loaded directly from a schematic.
bool saveAllLibraries(bool aRequireConfirmation)
Save the current symbol.
void UpdateMsgPanel() override
Redraw the message panel.
void CreateNewSymbol(const wxString &newName=wxEmptyString)
Create a new symbol in the selected library.
wxString SetCurLib(const wxString &aLibNickname)
Set the current library nickname and returns the old library nickname.
void UpdateTitle()
Update the main window title bar with the current library name and read only status of the library.
bool LoadSymbolFromCurrentLib(const wxString &aSymbolName, int aUnit=0, int aBodyStyle=0)
Load a symbol from the current active library, optionally setting the selected unit and convert.
SYMBOL_TREE_PANE * m_treePane
bool LoadOneLibrarySymbolAux(LIB_SYMBOL *aLibEntry, const wxString &aLibrary, int aUnit, int aBodyStyle)
Create a copy of aLibEntry into memory.
void closeSymbolTab(const LIB_ID &aLibId)
Close the open tab for aLibId, if any, without prompting and leaving the other tabs open.
bool saveCurrentSymbol()
Store the currently modified symbol in the library manager buffer.
void SaveSymbolCopyAs(bool aOpenCopy)
Save the currently selected symbol to a new name and/or location.
void clearSymbolTabsModifiedForLibrary(const wxString &aLibrary)
Clear the unsaved-edits flag on every tab in a saved library so its dirty indicator clears.
wxString AddLibraryFile(bool aCreateNew)
Create or add an existing library to the symbol library table.
void ensureUniqueName(LIB_SYMBOL *aSymbol, const wxString &aLibrary)
void UpdateLibraryTree(const wxDataViewItem &aTreeItem, LIB_SYMBOL *aSymbol)
Update a symbol node in the library tree.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current symbol.
void SaveLibraryAs()
Save the currently selected library to a new file.
bool IsContentModified() const override
Get if any symbols or libraries have been modified but not saved.
LIB_SYMBOL * getTargetSymbol() const
Return either the library selected in the symbol tree, if context menu is active or the library that ...
An interface to the global shared library manager that is schematic-specific and linked to one projec...
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
bool SymbolNameInUse(const wxString &aName, const wxString &aLibrary)
Return true if the symbol name is already in use in the specified library.
LIB_SYMBOL * GetSymbol(const wxString &aSymbolName, const wxString &aLibrary) const
Return either an alias of a working LIB_SYMBOL copy, or alias of the original symbol if there is no w...
This is a class that handles state involved in saving a symbol copy as a new symbol.
CONFLICT_STRATEGY m_strategy
wxString resolveConflict(const wxString &proposed, const wxString &aNewLibName) const
SYMBOL_SAVE_AS_HANDLER(LIB_SYMBOL_LIBRARY_MANAGER &aLibMgr, CONFLICT_STRATEGY aStrategy, bool aValueFollowsName)
LIB_SYMBOL_LIBRARY_MANAGER & m_libMgr
bool DoSave(LIB_SYMBOL &symbol, const wxString &aNewSymName, const wxString &aNewLibName, bool aFlattenSymbol)
TOOL_MANAGER * m_toolManager
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
wxString wx_str() const
Definition utf8.cpp:41
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
std::string GetClipboardUTF8()
Return the information currently stored in the system clipboard.
int OKOrCancelDialog(wxWindow *aParent, const wxString &aWarning, const wxString &aMessage, const wxString &aDetailedMessage, const wxString &aOKLabel, const wxString &aCancelLabel, bool *aApplyToAll)
Display a warning dialog with aMessage and returns the user response.
Definition confirm.cpp:165
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition confirm.cpp:146
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
int UnsavedChangesDialog(wxWindow *parent, const wxString &aMessage, bool *aApplyToAll)
A specialized version of HandleUnsavedChanges which handles an apply-to-all checkbox.
Definition confirm.cpp:60
bool ConfirmRevertDialog(wxWindow *parent, const wxString &aMessage)
Display a confirmation dialog for a revert action.
Definition confirm.cpp:133
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
Definition confirm.h:48
#define _(s)
@ FRAME_SCH
Definition frame_type.h:30
static const std::string KiCadSymbolLibFileExtension
static wxString KiCadSymbolLibFileWildcard()
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
PROJECT & Prj()
Definition kicad.cpp:730
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:448
STL namespace.
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition ptree.cpp:194
KIWAY Kiway(KFCTL_STANDALONE)
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
SYMBOL_SAVE_AS_HANDLER::CONFLICT_STRATEGY m_ConflictStrategy
SAVE_AS_IDS
@ ID_OVERWRITE_CONFLICTS
@ ID_RENAME_CONFLICTS
@ ID_MAKE_NEW_LIBRARY
static std::vector< wxString > CheckForParentalChainConflicts(LIB_SYMBOL_LIBRARY_MANAGER &aLibMgr, LIB_SYMBOL &aSymbol, bool aFlattenSymbol, const wxString &newSymbolName, const wxString &newLibraryName)
Get a list of all the symbols in the parental chain of a symbol that have conflicts when transposed t...
static std::vector< std::shared_ptr< LIB_SYMBOL > > GetParentChain(const LIB_SYMBOL &aSymbol, bool aIncludeLeaf=true)
Get a list of all the symbols in the parental chain of a symbol, with the "leaf" symbol at the start ...
static std::pair< bool, bool > CheckSavingIntoOwnInheritance(LIB_SYMBOL_LIBRARY_MANAGER &aLibMgr, LIB_SYMBOL &aSymbol, const wxString &aNewSymbolName, const wxString &aNewLibraryName)
Check if a planned overwrite would put a symbol into it's own inheritance chain.
SYMBOL_SAVEAS_TYPE
const SHAPE_LINE_CHAIN chain
Definition of file extensions used in Kicad.