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