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( GetCurSymbol() )
1285 {
1286 for( const std::shared_ptr<LIB_SYMBOL>& symbol : GetParentChain( *GetCurSymbol() ) )
1287 {
1288 if( symbol->GetLibId() == libId )
1289 {
1290 emptyScreen();
1291 break;
1292 }
1293 }
1294 }
1295
1296 m_libMgr->RemoveSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1297 }
1298
1299 m_treePane->GetLibTree()->RefreshLibTree();
1300}
1301
1302
1304{
1305 std::vector<LIB_ID> symbols;
1306
1307 if( GetTreeLIBIDs( symbols ) == 0 )
1308 return;
1309
1310 STRING_FORMATTER formatter;
1311
1312 for( LIB_ID& libId : symbols )
1313 {
1314 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(),
1315 libId.GetLibNickname() );
1316
1317 if( !symbol )
1318 continue;
1319
1320 std::unique_ptr<LIB_SYMBOL> tmp = symbol->Flatten();
1321 SCH_IO_KICAD_SEXPR::FormatLibSymbol( tmp.get(), formatter );
1322 }
1323
1324 std::string prettyData = formatter.GetString();
1325 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES );
1326
1327 wxLogNull doNotLog; // disable logging of failed clipboard actions
1328
1329 auto clipboard = wxTheClipboard;
1330 wxClipboardLocker clipboardLock( clipboard );
1331
1332 if( !clipboardLock || !clipboard->IsOpened() )
1333 return;
1334
1335 auto data = new wxTextDataObject( wxString( prettyData.c_str(), wxConvUTF8 ) );
1336 clipboard->SetData( data );
1337
1338 clipboard->Flush();
1339}
1340
1341
1342void SYMBOL_EDIT_FRAME::DuplicateSymbol( bool aFromClipboard )
1343{
1344 LIB_ID libId = GetTargetLibId();
1345 wxString lib = libId.GetLibNickname();
1346
1347 if( !m_libMgr->LibraryExists( lib ) )
1348 return;
1349
1350 std::vector<LIB_SYMBOL*> newSymbols;
1351
1352 if( aFromClipboard )
1353 {
1354 std::string clipboardData = GetClipboardUTF8();
1355
1356 try
1357 {
1358 newSymbols = SCH_IO_KICAD_SEXPR::ParseLibSymbols( clipboardData, "Clipboard" );
1359 }
1360 catch( IO_ERROR& e )
1361 {
1362 wxLogMessage( wxS( "Can not paste: %s" ), e.Problem() );
1363 }
1364 }
1365 else if( LIB_SYMBOL* srcSymbol = m_libMgr->GetBufferedSymbol( libId.GetLibItemName(), lib ) )
1366 {
1367 newSymbols.emplace_back( new LIB_SYMBOL( *srcSymbol ) );
1368
1369 // Derive from same parent.
1370 if( srcSymbol->IsDerived() )
1371 {
1372 if( std::shared_ptr<LIB_SYMBOL> srcParent = srcSymbol->GetParent().lock() )
1373 newSymbols.back()->SetParent( srcParent.get() );
1374 }
1375 }
1376
1377 if( newSymbols.empty() )
1378 return;
1379
1380 for( LIB_SYMBOL* symbol : newSymbols )
1381 {
1382 ensureUniqueName( symbol, lib );
1383 m_libMgr->UpdateSymbol( symbol, lib );
1384
1385 LoadOneLibrarySymbolAux( symbol, lib, GetUnit(), GetBodyStyle() );
1386 }
1387
1388 SyncLibraries( false );
1389 m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newSymbols[0]->GetName() ) );
1390
1391 for( LIB_SYMBOL* symbol : newSymbols )
1392 delete symbol;
1393}
1394
1395
1396void SYMBOL_EDIT_FRAME::ensureUniqueName( LIB_SYMBOL* aSymbol, const wxString& aLibrary )
1397{
1398 if( aSymbol )
1399 {
1400 int i = 1;
1401 wxString newName = aSymbol->GetName();
1402
1403 // Append a number to the name until the name is unique in the library.
1404 while( m_libMgr->SymbolNameInUse( newName, aLibrary ) )
1405 newName.Printf( "%s_%d", aSymbol->GetName(), i++ );
1406
1407 aSymbol->SetName( newName );
1408 }
1409}
1410
1411
1412void SYMBOL_EDIT_FRAME::Revert( bool aConfirm )
1413{
1414 LIB_ID libId = GetTargetLibId();
1415 const wxString& libName = libId.GetLibNickname();
1416
1417 // Empty if this is the library itself that is selected.
1418 const wxString& symbolName = libId.GetLibItemName();
1419
1420 wxString msg = wxString::Format( _( "Revert '%s' to last version saved?" ),
1421 symbolName.IsEmpty() ? libName : symbolName );
1422
1423 if( aConfirm && !ConfirmRevertDialog( this, msg ) )
1424 return;
1425
1426 bool reload_currentSymbol = false;
1427 wxString curr_symbolName = symbolName;
1428
1429 if( GetCurSymbol() )
1430 {
1431 // the library itself is reverted: the current symbol will be reloaded only if it is
1432 // owned by this library
1433 if( symbolName.IsEmpty() )
1434 {
1435 LIB_ID curr_libId = GetCurSymbol()->GetLibId();
1436 reload_currentSymbol = libName == curr_libId.GetLibNickname().wx_str();
1437
1438 if( reload_currentSymbol )
1439 curr_symbolName = curr_libId.GetUniStringLibItemName();
1440 }
1441 else
1442 {
1443 reload_currentSymbol = IsCurrentSymbol( libId );
1444 }
1445 }
1446
1447 int unit = m_unit;
1448
1449 if( reload_currentSymbol )
1450 emptyScreen();
1451
1452 if( symbolName.IsEmpty() )
1453 {
1454 m_libMgr->RevertLibrary( libName );
1455 }
1456 else
1457 {
1458 libId = m_libMgr->RevertSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1459
1460 m_treePane->GetLibTree()->SelectLibId( libId );
1461 m_libMgr->ClearSymbolModified( libId.GetLibItemName(), libId.GetLibNickname() );
1462 }
1463
1464 if( reload_currentSymbol && m_libMgr->SymbolExists( curr_symbolName, libName ) )
1465 LoadSymbol( curr_symbolName, libName, unit );
1466
1467 m_treePane->Refresh();
1468}
1469
1470
1472{
1473 wxCHECK_RET( m_libMgr, "Library manager object not created." );
1474
1475 Revert( false );
1476 m_libMgr->RevertAll();
1477}
1478
1479
1480void SYMBOL_EDIT_FRAME::LoadSymbol( const wxString& aAlias, const wxString& aLibrary, int aUnit )
1481{
1483 {
1484 if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
1485 [&]() -> bool
1486 {
1487 return saveCurrentSymbol();
1488 } ) )
1489 {
1490 return;
1491 }
1492 }
1493
1494 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( aAlias, aLibrary );
1495
1496 if( !symbol )
1497 {
1498 DisplayError( this, wxString::Format( _( "Symbol %s not found in library '%s'." ),
1499 aAlias,
1500 aLibrary ) );
1501 m_treePane->GetLibTree()->RefreshLibTree();
1502 return;
1503 }
1504
1505 // Optimize default edit options for this symbol
1506 // Usually if units are locked, graphic items are specific to each unit
1507 // and if units are interchangeable, graphic items are common to units
1509 tools->SetDrawSpecificUnit( symbol->UnitsLocked() );
1510
1511 LoadOneLibrarySymbolAux( symbol, aLibrary, aUnit, 0 );
1512}
1513
1514
1515bool SYMBOL_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile )
1516{
1517 wxFileName fn;
1518 wxString msg;
1520 SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::SCH_FILE_T::SCH_KICAD;
1521 PROJECT& prj = Prj();
1522
1524
1526
1527 if( !aNewFile && ( aLibrary.empty() || !adapter->HasLibrary( aLibrary ) ) )
1528 {
1529 ShowInfoBarError( _( "No library specified." ) );
1530 return false;
1531 }
1532
1533 if( aNewFile )
1534 {
1535 SEARCH_STACK* search = PROJECT_SCH::SchSearchS( &prj );
1536
1537 // Get a new name for the library
1538 wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
1539
1540 if( !default_path )
1541 default_path = search->LastVisitedPath();
1542
1543 fn.SetName( aLibrary );
1545
1546 wxString wildcards = FILEEXT::KiCadSymbolLibFileWildcard();
1547
1548 wxFileDialog dlg( this, wxString::Format( _( "Save Library '%s' As..." ), aLibrary ), default_path,
1549 fn.GetFullName(), wildcards, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1550
1551 SYMBOL_LIBRARY_SAVE_AS_FILEDLG_HOOK saveAsHook( type );
1552 dlg.SetCustomizeHook( saveAsHook );
1553
1555
1556 if( dlg.ShowModal() == wxID_CANCEL )
1557 return false;
1558
1559 fn = dlg.GetPath();
1560
1561 prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() );
1562
1563 if( fn.GetExt().IsEmpty() )
1565
1566 type = saveAsHook.GetOption();
1567 }
1568 else
1569 {
1570 std::optional<LIBRARY_TABLE_ROW*> optRow = adapter->GetRow( aLibrary );
1571 wxCHECK( optRow, false );
1572
1573 fn = LIBRARY_MANAGER::GetFullURI( *optRow, true );
1575
1576 if( fileType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1577 fileType = SCH_IO_MGR::SCH_KICAD;
1578 }
1579
1580 // Verify the user has write privileges before attempting to save the library file.
1581 if( !aNewFile && m_libMgr->IsLibraryReadOnly( aLibrary ) )
1582 return false;
1583
1584 ClearMsgPanel();
1585
1586 // Copy .kicad_symb file to .bak.
1587 if( !backupFile( fn, "bak" ) )
1588 return false;
1589
1590 if( !m_libMgr->SaveLibrary( aLibrary, fn.GetFullPath(), fileType ) )
1591 {
1592 msg.Printf( _( "Failed to save changes to symbol library file '%s'." ),
1593 fn.GetFullPath() );
1594 DisplayErrorMessage( this, _( "Error Saving Library" ), msg );
1595 return false;
1596 }
1597
1598 if( !aNewFile )
1599 {
1600 m_libMgr->ClearLibraryModified( aLibrary );
1601
1603
1604 // Update the library modification time so that we don't reload based on the watcher
1605 if( aLibrary == getTargetLib() )
1606 {
1607 if( fn.DirExists() )
1608 {
1610 fn.GetFullPath(),
1611 wxS( "*." ) + wxString( FILEEXT::KiCadSymbolLibFileExtension ) ) );
1612 }
1613 else if( fn.FileExists() )
1614 {
1615 wxLogNull silence;
1616 SetSymModificationTime( fn.GetModificationTime().GetValue().GetValue() );
1617 }
1618 }
1619 }
1620 else
1621 {
1622 bool resyncLibTree = false;
1623 wxString originalLibNickname = getTargetLib();
1624 wxString forceRefresh;
1625
1626 switch( type )
1627 {
1629 resyncLibTree = replaceLibTableEntry( originalLibNickname, fn.GetFullPath() );
1630 forceRefresh = originalLibNickname;
1631 break;
1632
1634 resyncLibTree = addLibTableEntry( fn.GetFullPath() );
1635 break;
1636
1638 resyncLibTree = addLibTableEntry( fn.GetFullPath(), LIBRARY_TABLE_SCOPE::PROJECT );
1639 break;
1640
1641 default:
1642 break;
1643 }
1644
1645 if( resyncLibTree )
1646 {
1648 SyncLibraries( true, false, forceRefresh );
1650 }
1651 }
1652
1653 ClearMsgPanel();
1654 msg.Printf( _( "Symbol library file '%s' saved." ), fn.GetFullPath() );
1656
1657 return true;
1658}
1659
1660
1661bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
1662{
1663 wxString msg, msg2;
1664 bool doSave = true;
1665 int dirtyCount = 0;
1666 bool applyToAll = false;
1667 bool retv = true;
1668
1669 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1670 {
1671 if( m_libMgr->IsLibraryModified( libNickname ) )
1672 dirtyCount++;
1673 }
1674
1675 for( const wxString& libNickname : m_libMgr->GetLibraryNames() )
1676 {
1677 if( m_libMgr->IsLibraryModified( libNickname ) )
1678 {
1679 if( aRequireConfirmation && !applyToAll )
1680 {
1681 msg.Printf( _( "Save changes to '%s' before closing?" ), libNickname );
1682
1683 switch( UnsavedChangesDialog( this, msg, dirtyCount > 1 ? &applyToAll : nullptr ) )
1684 {
1685 case wxID_YES: doSave = true; break;
1686 case wxID_NO: doSave = false; break;
1687 default:
1688 case wxID_CANCEL: return false;
1689 }
1690 }
1691
1692 if( doSave )
1693 {
1694 // If saving under existing name fails then do a Save As..., and if that
1695 // fails then cancel close action.
1696 if( m_libMgr->IsLibraryReadOnly( libNickname ) )
1697 {
1698 msg.Printf( _( "Symbol library '%s' is not writable." ), libNickname );
1699 msg2 = _( "You must save to a different location." );
1700
1701 if( dirtyCount == 1 )
1702 {
1703 if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) != wxID_OK )
1704 {
1705 retv = false;
1706 continue;
1707 }
1708 }
1709 else
1710 {
1711 m_infoBar->Dismiss();
1712 m_infoBar->ShowMessageFor( msg + wxS( " " ) + msg2,
1713 2000, wxICON_EXCLAMATION );
1714
1715 while( m_infoBar->IsShownOnScreen() )
1716 wxSafeYield();
1717
1718 retv = false;
1719 continue;
1720 }
1721 }
1722 else if( saveLibrary( libNickname, false ) )
1723 {
1724 continue;
1725 }
1726
1727 if( !saveLibrary( libNickname, true ) )
1728 retv = false;
1729 }
1730 }
1731 }
1732
1733 UpdateTitle();
1734 return retv;
1735}
1736
1737
1739{
1741
1742 if( !m_symbol )
1743 return;
1744
1745 wxString msg = m_symbol->GetName();
1746
1747 AppendMsgPanel( _( "Name" ), UnescapeString( msg ), 8 );
1748
1749 if( m_symbol->IsDerived() )
1750 {
1751 std::shared_ptr<LIB_SYMBOL> parent = m_symbol->GetParent().lock();
1752
1753 msg = parent ? parent->GetName() : _( "Undefined!" );
1754 AppendMsgPanel( _( "Parent" ), UnescapeString( msg ), 8 );
1755 }
1756
1757 if( m_symbol->IsGlobalPower() )
1758 msg = _( "Power Symbol" );
1759 else if( m_symbol->IsLocalPower() )
1760 msg = _( "Power Symbol (Local)" );
1761 else
1762 msg = _( "Symbol" );
1763
1764 AppendMsgPanel( _( "Type" ), msg, 8 );
1765 AppendMsgPanel( _( "Description" ), m_symbol->GetDescription(), 8 );
1766 AppendMsgPanel( _( "Keywords" ), m_symbol->GetKeyWords() );
1767 AppendMsgPanel( _( "Datasheet" ), m_symbol->GetDatasheetField().GetText() );
1768}
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:1681
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:128
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.
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.
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:739
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.