KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_sym_lib_table.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) 2017 Wayne Stambaugh <[email protected]>
5 * Copyright (C) 2021 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * 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 <set>
23#include <wx/regex.h>
24
25#include <build_version.h>
26#include <common.h> // For ExpandEnvVarSubstitutions
28#include <project.h>
29#include <panel_sym_lib_table.h>
30#include <lib_id.h>
34#include <widgets/wx_grid.h>
38#include <confirm.h>
39#include <bitmaps.h>
42#include <env_paths.h>
43#include <functional>
44#include <eeschema_id.h>
45#include <env_vars.h>
46#include <sch_io/sch_io.h>
47#include <symbol_edit_frame.h>
48#include <sch_edit_frame.h>
49#include <kiway.h>
50#include <paths.h>
51#include <kiplatform/ui.h>
52#include <pgm_base.h>
54#include <wx/dir.h>
55#include <wx/dirdlg.h>
56#include <wx/filedlg.h>
57#include <wx/msgdlg.h>
58#include <project_sch.h>
63
68{
69 wxString m_Description;
70 wxString m_FileFilter;
71
74 bool m_IsFile;
75 SCH_IO_MGR::SCH_FILE_T m_Plugin;
76};
77
78
83static constexpr int FIRST_MENU_ID = 1000;
84// This must not collide with any SCH_FILE_T enum values so we offset it below.
87
88
90{
91public:
92 SYMBOL_LIB_TABLE_GRID_DATA_MODEL( DIALOG_SHIM* aParent, WX_GRID* aGrid, const LIBRARY_TABLE& aTableToEdit,
93 SYMBOL_LIBRARY_ADAPTER* aAdapter, const wxArrayString& aPluginChoices,
94 wxString* aMRUDirectory, const wxString& aProjectPath ) :
95 LIB_TABLE_GRID_DATA_MODEL( aParent, aGrid, aTableToEdit, aAdapter, aPluginChoices, aMRUDirectory,
96 aProjectPath )
97 {
98 }
99
100 void SetValue( int aRow, int aCol, const wxString &aValue ) override
101 {
102 wxCHECK( aRow < (int) size(), /* void */ );
103
104 LIB_TABLE_GRID_DATA_MODEL::SetValue( aRow, aCol, aValue );
105
106 // If setting a filepath, attempt to auto-detect the format
107 if( aCol == COL_URI )
108 {
109 LIBRARY_TABLE_ROW& row = at( static_cast<size_t>( aRow ) );
110 wxString uri = LIBRARY_MANAGER::ExpandURI( row.URI(), Pgm().GetSettingsManager().Prj() );
111 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( uri );
112
113 if( pluginType != SCH_IO_MGR::SCH_FILE_UNKNOWN )
114 SetValue( aRow, COL_TYPE, SCH_IO_MGR::ShowType( pluginType ) );
115 }
116 }
117
118protected:
119 wxString getFileTypes( WX_GRID* aGrid, int aRow ) override
120 {
121 LIB_TABLE_GRID_DATA_MODEL* table = static_cast<LIB_TABLE_GRID_DATA_MODEL*>( aGrid->GetTable() );
122 LIBRARY_TABLE_ROW& tableRow = table->At( aRow );
123
124 if( tableRow.Type() == LIBRARY_TABLE_ROW::TABLE_TYPE_NAME )
125 {
126 wxString filter = _( "Symbol Library Tables" );
127#ifndef __WXOSX__
128 filter << wxString::Format( _( " (%s)|%s" ), FILEEXT::SymbolLibraryTableFileName,
130#else
131 filter << wxString::Format( _( " (%s)|%s" ), wxFileSelectorDefaultWildcardStr,
132 wxFileSelectorDefaultWildcardStr );
133#endif
134 return filter;
135 }
136
137 SCH_IO_MGR::SCH_FILE_T pi_type = SCH_IO_MGR::EnumFromStr( tableRow.Type() );
138 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pi_type ) );
139
140 if( pi )
141 {
142 const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc();
143
144 if( desc.m_IsFile )
145 return desc.FileFilter();
146 }
147
148 return wxEmptyString;
149 }
150};
151
152
154{
155public:
157 std::function<void( wxCommandEvent& )> aAddHandler ) :
158 LIB_TABLE_GRID_TRICKS( aGrid, aAddHandler ),
159 m_panel( aPanel )
160 {
162 }
163
165 {
166 return true;
167 }
168
169protected:
170 void optionsEditor( int aRow ) override
171 {
172 LIB_TABLE_GRID_DATA_MODEL* tbl = static_cast<LIB_TABLE_GRID_DATA_MODEL*>( m_grid->GetTable() );
173
174 if( aRow < tbl->GetNumberRows() )
175 {
176 LIBRARY_TABLE_ROW& row = tbl->At( static_cast<size_t>( aRow ) );
177 const wxString& options = row.Options();
178 wxString result = options;
179 std::map<std::string, UTF8> choices;
180
181 SCH_IO_MGR::SCH_FILE_T pi_type = SCH_IO_MGR::EnumFromStr( row.Type() );
182 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pi_type ) );
183
184 if( pi )
185 pi->GetLibraryOptions( &choices );
186
187 DIALOG_PLUGIN_OPTIONS dlg( wxGetTopLevelParent( m_grid ), row.Nickname(), choices, options, &result );
188 dlg.ShowModal();
189
190 if( options != result )
191 {
192 tbl->OnModify();
193 row.SetOptions( result );
194 m_grid->Refresh();
195 }
196 }
197 }
198
199 void openTable( const LIBRARY_TABLE_ROW& aRow ) override
200 {
201 wxFileName fn( LIBRARY_MANAGER::ExpandURI( aRow.URI(), Pgm().GetSettingsManager().Prj() ) );
202 std::shared_ptr<LIBRARY_TABLE> child = std::make_shared<LIBRARY_TABLE>( fn, LIBRARY_TABLE_SCOPE::GLOBAL,
204
205 if( !child->IsOk() )
206 {
207 wxMessageBox( _( "Unable to load library table." ) );
208 }
209 else
210 {
212
213 m_panel->OpenTable( child, aRow.Nickname() );
214 }
215 }
216
217 wxString getTablePreamble() override
218 {
219 return wxT( "(sym_lib_table" );
220 }
221
226
227protected:
229};
230
231
232void PANEL_SYM_LIB_TABLE::OpenTable( const std::shared_ptr<LIBRARY_TABLE>& aTable, const wxString& aTitle )
233{
234 wxString tabTitle = aTitle;
235
236 if( aTable->IsReadOnly() )
237 tabTitle += wxS( " " ) + _( "(read-only)" );
238
239 for( int ii = 2; ii < (int) m_notebook->GetPageCount(); ++ii )
240 {
241 wxString candidate = m_notebook->GetPageText( ii );
242
243 if( candidate.EndsWith( " *" ) )
244 candidate = candidate.Left( candidate.Length() - 2 );
245
246 if( candidate == tabTitle )
247 {
248 // Something is pretty fishy with wxAuiNotebook::ChangeSelection(); on Mac at least it
249 // results in a re-entrant call where the second call is one page behind.
250 for( int attempts = 0; attempts < 3; ++attempts )
251 m_notebook->ChangeSelection( ii );
252
253 return;
254 }
255 }
256
257 m_nestedTables.push_back( aTable );
258 AddTable( aTable.get(), tabTitle, true );
259
260 // Something is pretty fishy with wxAuiNotebook::ChangeSelection(); on Mac at least it
261 // results in a re-entrant call where the second call is one page behind.
262 for( int attempts = 0; attempts < 3; ++attempts )
263 m_notebook->ChangeSelection( m_notebook->GetPageCount() - 1 );
264}
265
266
267void PANEL_SYM_LIB_TABLE::AddTable( LIBRARY_TABLE* table, const wxString& aTitle, bool aClosable )
268{
270 wxString projectPath = m_project->GetProjectPath();
271
273
274 WX_GRID* grid = get_grid( (int) m_notebook->GetPageCount() - 1 );
275
276 if( table->Path().StartsWith( projectPath ) )
277 {
279 &m_lastProjectLibDir, projectPath ),
280 true /* take ownership */ );
281 }
282 else
283 {
284 wxString* lastGlobalLibDir = nullptr;
285
287 {
288 if( cfg->m_lastSymbolLibDir.IsEmpty() )
289 cfg->m_lastSymbolLibDir = PATHS::GetDefaultUserSymbolsPath();
290
291 lastGlobalLibDir = &cfg->m_lastSymbolLibDir;
292 }
293
295 lastGlobalLibDir, wxEmptyString ),
296 true /* take ownership */ );
297 }
298
299 static_cast<LIB_TABLE_GRID_DATA_MODEL*>( grid->GetTable() )->RecheckRows();
300
301 LIB_TABLE_NOTEBOOK_PANEL* notebookPanel =
302 static_cast<LIB_TABLE_NOTEBOOK_PANEL*>( m_notebook->GetPage( m_notebook->GetPageCount() - 1 ) );
303
304 static_cast<LIB_TABLE_GRID_DATA_MODEL*>( grid->GetTable() )
306 [notebookPanel]()
307 {
308 notebookPanel->MarkDirty();
309 } );
310
311 // add Cut, Copy, and Paste to wxGrids
312 grid->PushEventHandler( new SYMBOL_GRID_TRICKS( this, grid,
313 [this]( wxCommandEvent& event )
314 {
315 appendRowHandler( event );
316 } ) );
317
318 auto autoSizeCol =
319 [&]( int aCol )
320 {
321 int prevWidth = grid->GetColSize( aCol );
322
323 grid->AutoSizeColumn( aCol, false );
324 grid->SetColSize( aCol, std::max( prevWidth, grid->GetColSize( aCol ) ) );
325 };
326
327 // all but COL_OPTIONS, which is edited with Option Editor anyways.
328 autoSizeCol( COL_NICKNAME );
329 autoSizeCol( COL_TYPE );
330 autoSizeCol( COL_URI );
331 autoSizeCol( COL_DESCR );
332
333 if( grid->GetNumberRows() > 0 )
334 {
335 grid->SetGridCursor( 0, COL_NICKNAME );
336 grid->SelectRow( 0 );
337 }
338}
339
340
342 PANEL_SYM_LIB_TABLE_BASE( aParent ),
343 m_project( aProject ),
344 m_parent( aParent ),
346{
347 m_notebook->SetArtProvider( new WX_AUI_TAB_ART() );
348
349 m_lastProjectLibDir = m_project->GetProjectPath();
350
352
353 for( const SCH_IO_MGR::SCH_FILE_T& type : SCH_IO_MGR::SCH_FILE_T_vector )
354 {
355 if( type == SCH_IO_MGR::SCH_NESTED_TABLE )
356 {
358 continue;
359 }
360
361 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( type ) );
362
363 if( pi )
365 }
366
367 std::optional<LIBRARY_TABLE*> table = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
369 wxASSERT( table.has_value() );
370
371 AddTable( table.value(), _( "Global Libraries" ), false /* closable */ );
372
373 std::optional<LIBRARY_TABLE*> projectTable = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
375
376 if( projectTable.has_value() )
377 AddTable( projectTable.value(), _( "Project Specific Libraries" ), false /* closable */ );
378
379 // add Cut, Copy, and Paste to wxGrids
380 m_path_subs_grid->PushEventHandler( new GRID_TRICKS( m_path_subs_grid ) );
381
383
384 m_path_subs_grid->SetColLabelValue( 0, _( "Name" ) );
385 m_path_subs_grid->SetColLabelValue( 1, _( "Value" ) );
386
387 // Configure button logos
393
394 // For aesthetic reasons, we must set the size of m_browseButton to match the other bitmaps
395 Layout();
396 wxSize buttonSize = m_append_button->GetSize();
397
398 m_browseButton->SetWidthPadding( 4 );
399 m_browseButton->SetMinSize( buttonSize );
400
401 // Populate the browse library options
402 wxMenu* browseMenu = m_browseButton->GetSplitButtonMenu();
403
404 auto joinExtensions =
405 []( const std::vector<std::string>& aExts ) -> wxString
406 {
407 wxString result;
408
409 for( const std::string& ext : aExts )
410 {
411 if( !result.IsEmpty() )
412 result << wxT( ", " );
413
414 result << wxT( "." ) << ext;
415 }
416
417 return result;
418 };
419
420 for( auto& [type, desc] : m_supportedSymFiles )
421 {
422 wxString entryStr = SCH_IO_MGR::ShowType( type );
423
424 if( !desc.m_FileExtensions.empty() )
425 entryStr << wxString::Format( wxS( " (%s)" ), joinExtensions( desc.m_FileExtensions ) );
426
427 browseMenu->Append( type + FIRST_MENU_ID, entryStr );
428 browseMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_SYM_LIB_TABLE::browseLibrariesHandler, this,
429 type + FIRST_MENU_ID );
430
431 // Add folder-based entry right after KiCad file-based entry
432 if( type == SCH_IO_MGR::SCH_KICAD )
433 {
434 wxString folderEntry = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_KICAD );
435 folderEntry << wxString::Format( wxS( " (%s)" ), _( "folder with .kicad_sym files" ) );
436 browseMenu->Append( ID_PANEL_SYM_LIB_KICAD_FOLDER, folderEntry );
437 browseMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_SYM_LIB_TABLE::browseLibrariesHandler, this,
439 }
440
441 // Creating a database library belongs next to adding an existing one
442 if( type == SCH_IO_MGR::SCH_DATABASE )
443 {
444 browseMenu->Append( ID_PANEL_SYM_LIB_NEW_DATABASE, _( "New Database Library..." ) );
445 browseMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_SYM_LIB_TABLE::newDatabaseLibraryHandler, this,
447 }
448 }
449
450 Layout();
451
452 m_notebook->Bind( wxEVT_AUINOTEBOOK_PAGE_CLOSE, &PANEL_SYM_LIB_TABLE::onNotebookPageCloseRequest, this );
453 m_notebook->Bind( wxEVT_AUINOTEBOOK_PAGE_CHANGING, &PANEL_SYM_LIB_TABLE::onNotebookPageChangeRequest, this );
455}
456
457
459{
460 wxMenu* browseMenu = m_browseButton->GetSplitButtonMenu();
461
462 for( auto& [type, desc] : m_supportedSymFiles )
463 browseMenu->Unbind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_SYM_LIB_TABLE::browseLibrariesHandler, this,
464 type + FIRST_MENU_ID );
465
466 browseMenu->Unbind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_SYM_LIB_TABLE::browseLibrariesHandler,
468 browseMenu->Unbind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_SYM_LIB_TABLE::newDatabaseLibraryHandler,
470 m_browseButton->Unbind( wxEVT_BUTTON, &PANEL_SYM_LIB_TABLE::browseLibrariesHandler, this );
471
472 // Delete the GRID_TRICKS.
473 // (Notebook page GRID_TRICKS are deleted by LIB_TABLE_NOTEBOOK_PANEL.)
474 m_path_subs_grid->PopEventHandler( true );
475}
476
477
479{
480 for( const SCH_IO_MGR::SCH_FILE_T& type : SCH_IO_MGR::SCH_FILE_T_vector )
481 {
482 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( type ) );
483
484 if( !pi )
485 continue;
486
487 if( const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc() )
488 {
489 if( !desc.m_FileExtensions.empty() )
490 m_supportedSymFiles.emplace( type, desc );
491 }
492 }
493
494 m_supportedSymFiles.emplace( SCH_IO_MGR::SCH_NESTED_TABLE,
495 IO_BASE::IO_FILE_DESC( _( "Table (nested library table)" ), {} ) );
496}
497
498
500{
501 return static_cast<SYMBOL_LIB_TABLE_GRID_DATA_MODEL*>( get_grid( aPage )->GetTable() );
502}
503
504
506{
507 return static_cast<LIB_TABLE_NOTEBOOK_PANEL*>( m_notebook->GetPage( aPage ) )->GetGrid();
508}
509
510
512{
513 // for ALT+A handling, we want the initial focus to be on the first selected grid.
514 m_parent->SetInitialFocus( cur_grid() );
515
516 return true;
517}
518
519
521{
522 for( int page = 0 ; page < (int) m_notebook->GetPageCount(); ++page )
523 {
524 WX_GRID* grid = get_grid( page );
525
527 [&]( int aRow, int aCol )
528 {
529 // show the tabbed panel holding the grid we have flunked:
530 if( m_notebook->GetSelection() != page )
531 m_notebook->SetSelection( page );
532
533 grid->MakeCellVisible( aRow, 0 );
534 grid->SetGridCursor( aRow, aCol );
535 } ) )
536 {
537 return false;
538 }
539 }
540
541 return true;
542}
543
544
546{
547 if( !cur_grid()->CommitPendingChanges() )
548 return;
549
550 SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::SCH_FILE_UNKNOWN;
551 bool selectingFolder = false;
552
553 // We are bound both to the menu and button with this one handler
554 if( event.GetEventType() == wxEVT_BUTTON )
555 {
556 // Default to KiCad file format when clicking the button directly
557 fileType = SCH_IO_MGR::SCH_KICAD;
558 }
559 else if( event.GetId() == ID_PANEL_SYM_LIB_KICAD_FOLDER )
560 {
561 // Special case for folder-based KiCad library
562 fileType = SCH_IO_MGR::SCH_KICAD;
563 selectingFolder = true;
564 }
565 else
566 {
567 fileType = static_cast<SCH_IO_MGR::SCH_FILE_T>( event.GetId() - FIRST_MENU_ID );
568 }
569
570 if( fileType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
571 return;
572
574 wxString dummy;
575 wxString* lastDir;
576
577 if( m_notebook->GetSelection() == 0 )
578 lastDir = cfg ? &cfg->m_lastSymbolLibDir : &dummy;
579 else
580 lastDir = &m_lastProjectLibDir;
581
582 wxString title = wxString::Format( _( "Select %s Library" ), SCH_IO_MGR::ShowType( fileType ) );
583 wxWindow* topLevelParent = wxGetTopLevelParent( this );
584 wxArrayString files;
585
586 if( selectingFolder )
587 {
588 wxDirDialog dlg( topLevelParent, title, *lastDir, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST | wxDD_MULTIPLE );
589
590 if( dlg.ShowModal() == wxID_CANCEL )
591 return;
592
593 dlg.GetPaths( files );
594
595 if( !files.IsEmpty() )
596 {
597 wxFileName first( files.front() );
598 *lastDir = first.GetPath();
599 }
600 }
601 else
602 {
603 auto it = m_supportedSymFiles.find( fileType );
604
605 if( it == m_supportedSymFiles.end() )
606 return;
607
608 const IO_BASE::IO_FILE_DESC& fileDesc = it->second;
609
610 wxFileDialog dlg( topLevelParent, title, *lastDir, wxEmptyString, fileDesc.FileFilter(),
611 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE );
612
614
615 if( dlg.ShowModal() == wxID_CANCEL )
616 return;
617
618 dlg.GetPaths( files );
619 *lastDir = dlg.GetDirectory();
620 }
621
622 bool addDuplicates = false;
623 bool applyToAll = false;
624 wxString warning = _( "Warning: Duplicate Nicknames" );
625 wxString msg = _( "An item nicknamed '%s' already exists." );
626 wxString detailedMsg = _( "One of the nicknames will need to be changed." );
627
628 for( const wxString& filePath : files )
629 {
630 wxFileName fn( filePath );
631 wxString nickname = LIB_ID::FixIllegalChars( fn.GetName(), true );
632 bool doAdd = true;
633
634 if( cur_model()->ContainsNickname( nickname ) )
635 {
636 if( !applyToAll )
637 {
638 addDuplicates = OKOrCancelDialog( topLevelParent, warning,
639 wxString::Format( msg, nickname ), detailedMsg,
640 _( "Skip" ), _( "Add Anyway" ),
641 &applyToAll ) == wxID_CANCEL;
642 }
643
644 doAdd = addDuplicates;
645 }
646
647 if( doAdd )
648 appendLibraryRow( nickname, fileType, filePath );
649 }
650
651 if( !files.IsEmpty() )
652 {
653 cur_grid()->MakeCellVisible( cur_grid()->GetNumberRows() - 1, COL_ENABLED );
654 cur_grid()->SetGridCursor( cur_grid()->GetNumberRows() - 1, COL_NICKNAME );
655 }
656}
657
658
659void PANEL_SYM_LIB_TABLE::appendLibraryRow( const wxString& aNickname, SCH_IO_MGR::SCH_FILE_T aType,
660 const wxString& aFilePath )
661{
662 if( !cur_grid()->AppendRows( 1 ) )
663 return;
664
665 int last_row = cur_grid()->GetNumberRows() - 1;
666
667 cur_grid()->SetCellValue( last_row, COL_NICKNAME, aNickname );
668 cur_grid()->SetCellValue( last_row, COL_TYPE, SCH_IO_MGR::ShowType( aType ) );
669
670 // try to use path normalized to an environmental variable or project path
671 wxString path = NormalizePath( aFilePath, &Pgm().GetLocalEnvVariables(), m_project->GetProjectPath() );
672
673 // Do not use the project path in the global library table. This will almost
674 // assuredly be wrong for a different project.
675 if( m_notebook->GetSelection() == 0 && path.Contains( wxT( "${KIPRJMOD}" ) ) )
676 path = wxFileName( aFilePath ).GetFullPath();
677
678 cur_grid()->SetCellValue( last_row, COL_URI, path );
679}
680
681
683{
684 if( !cur_grid()->CommitPendingChanges() )
685 return;
686
687 wxWindow* topLevelParent = wxGetTopLevelParent( this );
689 wxString* lastDir = m_notebook->GetSelection() == 0 && cfg ? &cfg->m_lastSymbolLibDir
691
692 wxString defaultDir = m_project->IsNullProject() ? *lastDir : m_project->GetProjectPath();
693
694 // The file is chosen when the user accepts the dialog
695 DIALOG_DATABASE_LIB_SETTINGS settingsDlg( topLevelParent, wxEmptyString,
697
698 if( settingsDlg.ShowModal() != wxID_OK )
699 return;
700
701 wxFileName fn( settingsDlg.GetSettingsPath() );
702 *lastDir = fn.GetPath();
703
704 wxString nickname = LIB_ID::FixIllegalChars( fn.GetName(), true );
705
706 if( cur_model()->ContainsNickname( nickname ) )
707 {
708 DisplayError( topLevelParent, wxString::Format( _( "An item nicknamed '%s' already exists; the new "
709 "library was added with a blank nickname." ),
710 nickname ) );
711 nickname.clear();
712 }
713
714 appendLibraryRow( nickname, SCH_IO_MGR::SCH_DATABASE, fn.GetFullPath() );
715
716 cur_grid()->MakeCellVisible( cur_grid()->GetNumberRows() - 1, COL_ENABLED );
717 cur_grid()->SetGridCursor( cur_grid()->GetNumberRows() - 1, COL_NICKNAME );
718}
719
720
721void PANEL_SYM_LIB_TABLE::appendRowHandler( wxCommandEvent& event )
722{
724}
725
726
731
732
737
738
743
744
745void PANEL_SYM_LIB_TABLE::onReset( wxCommandEvent& event )
746{
747 if( !cur_grid()->CommitPendingChanges() )
748 return;
749
750 WX_GRID* grid = get_grid( 0 );
751
752 // No need to prompt to preserve an empty table
753 if( grid->GetNumberRows() > 0 && !IsOK( this, wxString::Format( _( "This action will reset your global library "
754 "table on disk and cannot be undone." ) ) ) )
755 {
756 return;
757 }
758
759 wxString* lastGlobalLibDir = nullptr;
760
762 {
763 if( cfg->m_lastSymbolLibDir.IsEmpty() )
764 cfg->m_lastSymbolLibDir = PATHS::GetDefaultUserSymbolsPath();
765
766 lastGlobalLibDir = &cfg->m_lastSymbolLibDir;
767 }
768
770
771 // Go ahead and reload here because this action takes place even if the dialog is canceled
773
774 if( KIFACE *schface = m_parent->Kiway().KiFACE( KIWAY::FACE_SCH ) )
775 schface->PreloadLibraries( &m_parent->Kiway() );
776
777 grid->Freeze();
778
779 wxGridTableBase* table = grid->GetTable();
780 grid->DestroyTable( table );
781
782 std::optional<LIBRARY_TABLE*> newTable = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
784 wxASSERT( newTable );
785
787
788 grid->SetTable( new SYMBOL_LIB_TABLE_GRID_DATA_MODEL( m_parent, grid, *newTable.value(), adapter, m_pluginChoices,
789 lastGlobalLibDir, wxEmptyString ),
790 true /* take ownership */ );
791
792 LIB_TABLE_NOTEBOOK_PANEL* panel0 = static_cast<LIB_TABLE_NOTEBOOK_PANEL*>( m_notebook->GetPage( 0 ) );
793 panel0->ClearDirty();
794
795 static_cast<LIB_TABLE_GRID_DATA_MODEL*>( grid->GetTable() )->SetChangeCallback(
796 [panel0]()
797 {
798 panel0->MarkDirty();
799 } );
800
801 m_parent->m_GlobalTableChanged = true;
802
803 grid->Thaw();
804
805 if( grid->GetNumberRows() > 0 )
806 {
807 grid->SetGridCursor( 0, COL_NICKNAME );
808 grid->SelectRow( 0 );
809 }
810}
811
812
813void PANEL_SYM_LIB_TABLE::onNotebookPageChangeRequest( wxAuiNotebookEvent& aEvent )
814{
816 aEvent.Veto();
817 else
818 aEvent.Skip();
819}
820
821
822void PANEL_SYM_LIB_TABLE::onPageChange( wxAuiNotebookEvent& event )
823{
824 m_resetGlobal->Enable( m_notebook->GetSelection() == 0 );
825}
826
827
828void PANEL_SYM_LIB_TABLE::onNotebookPageCloseRequest( wxAuiNotebookEvent& aEvent )
829{
830 wxAuiNotebook* notebook = (wxAuiNotebook*) aEvent.GetEventObject();
831 wxWindow* page = notebook->GetPage( aEvent.GetSelection() );
832
833 if( LIB_TABLE_NOTEBOOK_PANEL* panel = dynamic_cast<LIB_TABLE_NOTEBOOK_PANEL*>( page ) )
834 {
835 if( panel->GetClosable() && panel->GetCanClose() )
836 {
837 m_parent->m_ProjectTableChanged = true;
838 m_parent->m_GlobalTableChanged = true;
839 }
840 else
841 {
842 aEvent.Veto();
843 }
844 }
845}
846
847
849{
850 if( !cur_grid()->CommitPendingChanges() )
851 return;
852
853 wxArrayInt selectedRows = cur_grid()->GetSelectedRows();
854
855 if( selectedRows.empty() && cur_grid()->GetGridCursorRow() >= 0 )
856 selectedRows.push_back( cur_grid()->GetGridCursorRow() );
857
858 wxArrayInt legacyRows;
859 wxString databaseType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_DATABASE );
860 wxString httpType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_HTTP );
861 wxString kicadType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_KICAD );
862 wxString nestedTableType = LIBRARY_TABLE_ROW::TABLE_TYPE_NAME;
863 wxString msg;
864
865 // HTTP and Database libraries are live, dynamic backends that are not file-based.
866 // Migrating them to a static .kicad_sym snapshot is not meaningful and would silently
867 // produce an empty library, destroying the original table entry. Nested library tables
868 // are not symbol libraries at all and likewise cannot be migrated.
869 for( int row : selectedRows )
870 {
871 const wxString& type = cur_grid()->GetCellValue( row, COL_TYPE );
872
873 if( type != databaseType && type != httpType && type != kicadType && type != nestedTableType )
874 legacyRows.push_back( row );
875 }
876
877 if( legacyRows.size() <= 0 )
878 {
879 wxMessageBox( _( "Select one or more rows containing libraries to save as current KiCad format." ) );
880 return;
881 }
882 else
883 {
884 if( legacyRows.size() == 1 )
885 {
886 msg.Printf( _( "Save '%s' as current KiCad format (*.kicad_sym) and replace legacy entry in table?" ),
887 cur_grid()->GetCellValue( legacyRows[0], COL_NICKNAME ) );
888 }
889 else
890 {
891 msg.Printf( _( "Save %d libraries as current KiCad format (*.kicad_sym) and replace legacy entries "
892 "in table?" ),
893 (int) legacyRows.size() );
894 }
895
896 if( !IsOK( m_parent, msg ) )
897 return;
898 }
899
900 for( int row : legacyRows )
901 {
902 wxString relPath = cur_grid()->GetCellValue( row, COL_URI );
903 wxString resolvedPath = ExpandEnvVarSubstitutions( relPath, m_project );
904 wxFileName legacyLib( resolvedPath );
905
906 if( !legacyLib.Exists() )
907 {
908 DisplayErrorMessage( m_parent, wxString::Format( _( "Library '%s' not found." ), relPath ) );
909 continue;
910 }
911
912 wxFileName newLib( resolvedPath );
913 newLib.SetExt( "kicad_sym" );
914
915 if( newLib.Exists() )
916 {
917 msg.Printf( _( "File '%s' already exists. Do you want overwrite this file?" ), newLib.GetFullPath() );
918
919 switch( wxMessageBox( msg, _( "Migrate Library" ), wxYES_NO | wxCANCEL | wxICON_QUESTION, m_parent ) )
920 {
921 case wxYES: break;
922 case wxNO: continue;
923 case wxCANCEL: return;
924 }
925 }
926
927 wxString options = cur_grid()->GetCellValue( row, COL_OPTIONS );
928 std::map<std::string, UTF8> props( LIBRARY_TABLE::ParseOptions( options.ToStdString() ) );
929
930 if( SCH_IO_MGR::ConvertLibrary( &props, legacyLib.GetFullPath(), newLib.GetFullPath() ) )
931 {
932 relPath = NormalizePath( newLib.GetFullPath(), &Pgm().GetLocalEnvVariables(), m_project );
933
934 cur_grid()->SetCellValue( row, COL_URI, relPath );
935 cur_grid()->SetCellValue( row, COL_TYPE, kicadType );
936 cur_grid()->SetCellValue( row, COL_OPTIONS, wxEmptyString );
937 }
938 else
939 {
940 DisplayErrorMessage( m_parent, wxString::Format( _( "Failed to save symbol library file '%s'." ),
941 newLib.GetFullPath() ) );
942 }
943 }
944}
945
946
948{
949 if( !cur_grid()->CommitPendingChanges() )
950 return false;
951
952 if( !verifyTables() )
953 return false;
954
955 bool success = true;
957 int firstNestedTable = 1;
958 std::optional<LIBRARY_TABLE*> globalTable = manager.Table( LIBRARY_TABLE_TYPE::SYMBOL,
960
961 if( globalTable.has_value() && get_model( 0 )->Table() != *globalTable.value() )
962 {
963 m_parent->m_GlobalTableChanged = true;
964 *globalTable.value() = get_model( 0 )->Table();
965
966 globalTable.value()->Save().map_error(
967 [&success]( const LIBRARY_ERROR& aError )
968 {
969 wxMessageBox( _( "Error saving global library table:\n\n" ) + aError.message,
970 _( "File Save Error" ), wxOK | wxICON_ERROR );
971 success = false;
972 } );
973 }
974
975 std::optional<LIBRARY_TABLE*> projectTable = manager.Table( LIBRARY_TABLE_TYPE::SYMBOL,
977
978 if( projectTable.has_value() && get_model( 1 )->Table().Path() == projectTable.value()->Path() )
979 {
980 firstNestedTable = 2;
981
982 if( get_model( 1 )->Table() != *projectTable.value() )
983 {
984 m_parent->m_ProjectTableChanged = true;
985 *projectTable.value() = get_model( 1 )->Table();
986
987 projectTable.value()->Save().map_error(
988 [&success]( const LIBRARY_ERROR& aError )
989 {
990 wxMessageBox( _( "Error saving project library table:\n\n" ) + aError.message,
991 _( "File Save Error" ), wxOK | wxICON_ERROR );
992 success = false;
993 } );
994 }
995 }
996
997 for( int ii = firstNestedTable; ii < (int) m_notebook->GetPageCount(); ++ii )
998 {
999 LIB_TABLE_NOTEBOOK_PANEL* panel = static_cast<LIB_TABLE_NOTEBOOK_PANEL*>( m_notebook->GetPage( ii ) );
1000
1001 if( panel->TableModified() )
1002 {
1003 success &= panel->SaveTable();
1004
1005 m_parent->m_ProjectTableChanged = true;
1006 m_parent->m_GlobalTableChanged = true;
1007 }
1008 }
1009
1011 return success;
1012}
1013
1014
1016{
1017 wxRegEx re( ".*?(\\$\\{(.+?)\\})|(\\$\\((.+?)\\)).*?", wxRE_ADVANCED );
1018 wxASSERT( re.IsValid() ); // wxRE_ADVANCED is required.
1019
1020 std::set< wxString > unique;
1021
1022 // clear the table
1023 m_path_subs_grid->ClearRows();
1024
1025 for( int page = 0 ; page < (int) m_notebook->GetPageCount(); ++page )
1026 {
1028
1029 for( int row = 0; row < model->GetNumberRows(); ++row )
1030 {
1031 wxString uri = model->GetValue( row, COL_URI );
1032
1033 while( re.Matches( uri ) )
1034 {
1035 wxString envvar = re.GetMatch( uri, 2 );
1036
1037 // if not ${...} form then must be $(...)
1038 if( envvar.IsEmpty() )
1039 envvar = re.GetMatch( uri, 4 );
1040
1041 // ignore duplicates
1042 unique.insert( envvar );
1043
1044 // delete the last match and search again
1045 uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString );
1046 }
1047 }
1048 }
1049
1050 // Make sure this special environment variable shows up even if it was
1051 // not used yet. It is automatically set by KiCad to the directory holding
1052 // the current project.
1053 unique.insert( PROJECT_VAR_NAME );
1054 unique.insert( ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) ) );
1055
1056 for( const wxString& evName : unique )
1057 {
1058 int row = m_path_subs_grid->GetNumberRows();
1059 m_path_subs_grid->AppendRows( 1 );
1060
1061 m_path_subs_grid->SetCellValue( row, 0, wxT( "${" ) + evName + wxT( "}" ) );
1062 m_path_subs_grid->SetCellEditor( row, 0, new GRID_CELL_READONLY_TEXT_EDITOR() );
1063
1064 wxString evValue;
1065 wxGetEnv( evName, &evValue );
1066 m_path_subs_grid->SetCellValue( row, 1, evValue );
1067 m_path_subs_grid->SetCellEditor( row, 1, new GRID_CELL_READONLY_TEXT_EDITOR() );
1068 }
1069
1070 adjustPathSubsGridColumns( m_path_subs_grid->GetRect().GetWidth() );
1071}
1072
1073
1075{
1076 // Account for scroll bars
1077 aWidth -= ( m_path_subs_grid->GetSize().x - m_path_subs_grid->GetClientSize().x );
1078
1079 m_path_subs_grid->AutoSizeColumn( 0 );
1080 m_path_subs_grid->SetColSize( 0, std::max( 72, m_path_subs_grid->GetColSize( 0 ) ) );
1081 m_path_subs_grid->SetColSize( 1, std::max( 120, aWidth - m_path_subs_grid->GetColSize( 0 ) ) );
1082}
1083
1084
1085void PANEL_SYM_LIB_TABLE::onSizeGrid( wxSizeEvent& event )
1086{
1087 adjustPathSubsGridColumns( event.GetSize().GetX() );
1088
1089 event.Skip();
1090}
1091
1092
1093void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
1094{
1095 auto symbolEditor = static_cast<SYMBOL_EDIT_FRAME*>( aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false ) );
1096 wxString msg;
1097
1098 // Refuse to open the dialog re-entrantly while a library sync is running. A
1099 // sync can yield the event loop (via the progress dialog), which dispatches any
1100 // pending UI events — including clicks that accumulated while the app was busy.
1101 // Opening the dialog mid-sync corrupts the library tree. Reschedule instead.
1102 if( symbolEditor && symbolEditor->IsSyncLibrariesInProgress() )
1103 {
1104 symbolEditor->CallAfter( [aKiway, aParent]()
1105 {
1106 InvokeSchEditSymbolLibTable( aKiway, aParent );
1107 } );
1108 return;
1109 }
1110
1111 if( symbolEditor )
1112 {
1113 // This prevents an ugly crash on OSX (https://bugs.launchpad.net/kicad/+bug/1765286)
1114 symbolEditor->FreezeLibraryTree();
1115
1116 if( symbolEditor->HasLibModifications() )
1117 {
1118 msg = _( "Modifications have been made to one or more symbol libraries.\n"
1119 "Changes must be saved or discarded before the symbol library table can be modified." );
1120
1121 switch( UnsavedChangesDialog( aParent, msg ) )
1122 {
1123 case wxID_YES: symbolEditor->SaveAll(); break;
1124 case wxID_NO: symbolEditor->RevertAll(); break;
1125 default:
1126 case wxID_CANCEL: symbolEditor->ThawLibraryTree(); return;
1127 }
1128 }
1129 }
1130
1131 DIALOG_EDIT_LIBRARY_TABLES dlg( aParent, _( "Symbol Libraries" ) );
1132 dlg.SetKiway( &dlg, aKiway );
1133
1134 PANEL_SYM_LIB_TABLE* panel = new PANEL_SYM_LIB_TABLE( &dlg, &aKiway->Prj() );
1135 dlg.InstallPanel( panel, panel->GetNotebook() );
1136
1137 // User can choose to save changes on a Cancel, so don't exit on wxID_CANCEL.
1138 dlg.ShowModal();
1139
1140 if( dlg.m_GlobalTableChanged )
1142
1143 if( dlg.m_ProjectTableChanged )
1144 {
1145 // Trigger a reload of the table and cancel an in-progress background load
1147 }
1148
1149 // Trigger a reload in case any libraries have been added or removed
1150 if( KIFACE *schface = aKiway->KiFACE( KIWAY::FACE_SCH ) )
1151 schface->PreloadLibraries( aKiway );
1152
1153 if( symbolEditor )
1154 symbolEditor->ThawLibraryTree();
1155}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
Edits every setting of a .kicad_dbl file and previews the resulting symbols.
void InstallPanel(wxPanel *aPanel, wxAuiNotebook *aNotebook)
An options editor in the form of a two column name/value spreadsheet like (table) UI.
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition dialog_shim.h:80
int ShowModal() override
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:57
WX_GRID * m_grid
I don't own the grid, but he owns me.
void SetTooltipEnable(int aCol, bool aEnable=true)
Enable the tooltip for a column.
Definition grid_tricks.h:71
void SetKiway(wxWindow *aDest, KIWAY *aKiway)
It is only used for debugging, since "this" is not a wxWindow*.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:348
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:401
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition kiway.cpp:214
@ FACE_SCH
eeschema DSO
Definition kiway.h:355
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition kiway.cpp:208
static wxString ExpandURI(const wxString &aShortURI, const PROJECT &aProject)
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
void ApplyLibOverrides(LIBRARY_TABLE &aTable)
Applies stored user overrides (disabled/hidden) to rows of a read-only table.
static bool CreateGlobalTable(LIBRARY_TABLE_TYPE aType, bool aPopulateDefaultLibraries)
void LoadGlobalTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the global library tables in the given list, or all tables if no list is given
void ProjectChanged()
Notify all adapters that the project has changed.
void SetOptions(const wxString &aOptions)
const wxString & Type() const
static const wxString TABLE_TYPE_NAME
const wxString & URI() const
const wxString & Nickname() const
const wxString & Options() const
LIBRARY_RESULT< void > Save()
static std::map< std::string, UTF8 > ParseOptions(const std::string &aOptionsList)
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition lib_id.cpp:205
This abstract base class mixes any object derived from LIBRARY_TABLE into wxGridTableBase so the resu...
virtual LIBRARY_TABLE_ROW & at(size_t aIndex)
void SetChangeCallback(std::function< void()> aCallback)
LIBRARY_TABLE_ROW & At(size_t aIndex)
void SetValue(int aRow, int aCol, const wxString &aValue) override
LIB_TABLE_GRID_DATA_MODEL(DIALOG_SHIM *aParent, WX_GRID *aGrid, const LIBRARY_TABLE &aTableToEdit, LIBRARY_MANAGER_ADAPTER *aAdapter, const wxArrayString &aPluginChoices, wxString *aMRUDirectory, const wxString &aProjectPath)
static void MoveUpHandler(WX_GRID *aGrid)
LIB_TABLE_GRID_TRICKS(WX_GRID *aGrid)
static void DeleteRowHandler(WX_GRID *aGrid)
static void AppendRowHandler(WX_GRID *aGrid, const wxString &aType)
static bool VerifyTable(WX_GRID *aGrid, bool aSupportsVisibilityColumn, std::function< void(int aRow, int aCol)> aErrorHandler)
static void MoveDownHandler(WX_GRID *aGrid)
static void AddTable(wxAuiNotebook *aNotebook, const wxString &aTitle, bool aClosable)
PANEL_SYM_LIB_TABLE_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
STD_BITMAP_BUTTON * m_move_down_button
Dialog to show and edit symbol library tables.
void moveUpHandler(wxCommandEvent &event) override
SYMBOL_LIB_TABLE_GRID_DATA_MODEL * get_model(int aPage) const
void onReset(wxCommandEvent &event) override
void browseLibrariesHandler(wxCommandEvent &event)
void deleteRowHandler(wxCommandEvent &event) override
WX_GRID * get_grid(int aPage) const
void onNotebookPageCloseRequest(wxAuiNotebookEvent &aEvent)
void onPageChange(wxAuiNotebookEvent &event) override
void AddTable(LIBRARY_TABLE *table, const wxString &aTitle, bool aClosable)
bool verifyTables()
Trim important fields, removes blank row entries, and checks for duplicates.
void adjustPathSubsGridColumns(int aWidth)
wxAuiNotebook * GetNotebook() const
void OpenTable(const std::shared_ptr< LIBRARY_TABLE > &table, const wxString &aTitle)
void onSizeGrid(wxSizeEvent &event) override
std::vector< std::shared_ptr< LIBRARY_TABLE > > m_nestedTables
void onConvertLegacyLibraries(wxCommandEvent &event) override
void onNotebookPageChangeRequest(wxAuiNotebookEvent &aEvent)
std::map< SCH_IO_MGR::SCH_FILE_T, IO_BASE::IO_FILE_DESC > m_supportedSymFiles
void newDatabaseLibraryHandler(wxCommandEvent &event)
Creates or opens a .kicad_dbl in the settings editor and adds it to the current table.
bool TransferDataToWindow() override
void appendLibraryRow(const wxString &aNickname, SCH_IO_MGR::SCH_FILE_T aType, const wxString &aFilePath)
Appends a row for aFilePath, storing the path relative to an environment variable if possible.
wxArrayString m_pluginChoices
void moveDownHandler(wxCommandEvent &event) override
PANEL_SYM_LIB_TABLE(DIALOG_EDIT_LIBRARY_TABLES *aParent, PROJECT *m_project)
SYMBOL_LIB_TABLE_GRID_DATA_MODEL * cur_model() const
void populateEnvironReadOnlyTable()
Populate the readonly environment variable table with names and values by examining all the full_uri ...
WX_GRID * cur_grid() const
DIALOG_EDIT_LIBRARY_TABLES * m_parent
bool TransferDataFromWindow() override
void appendRowHandler(wxCommandEvent &event) override
static wxString GetDefaultUserSymbolsPath()
Gets the default path we point users to create projects.
Definition paths.cpp:82
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:125
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Container for project specific data.
Definition project.h:63
static bool ConvertLibrary(std::map< std::string, UTF8 > *aOldFileProps, const wxString &aOldFilePath, const wxString &aNewFilepath, REPORTER *aReporter=nullptr)
Convert a schematic symbol library to the latest KiCad format.
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the file type from the corresponding plugin type name: "kicad", "legacy", etc.
static const wxString ShowType(SCH_FILE_T aFileType)
Return a brief name for a plugin, given aFileType enum.
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.
The symbol library editor main window.
SYMBOL_GRID_TRICKS(PANEL_SYM_LIB_TABLE *aPanel, WX_GRID *aGrid, std::function< void(wxCommandEvent &)> aAddHandler)
bool supportsVisibilityColumn() override
wxString getTablePreamble() override
PANEL_SYM_LIB_TABLE * m_panel
void openTable(const LIBRARY_TABLE_ROW &aRow) override
void optionsEditor(int aRow) override
static bool SupportsVisibilityColumn()
An interface to the global shared library manager that is schematic-specific and linked to one projec...
SYMBOL_LIB_TABLE_GRID_DATA_MODEL(DIALOG_SHIM *aParent, WX_GRID *aGrid, const LIBRARY_TABLE &aTableToEdit, SYMBOL_LIBRARY_ADAPTER *aAdapter, const wxArrayString &aPluginChoices, wxString *aMRUDirectory, const wxString &aProjectPath)
void SetValue(int aRow, int aCol, const wxString &aValue) override
wxString getFileTypes(WX_GRID *aGrid, int aRow) override
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject, bool aAllowEscapes)
Replace any environment variable & text variable references with their values.
Definition common.cpp:777
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
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
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 _(s)
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const wxString &aProjectPath)
Normalize a file path to an environmental variable, if possible.
Definition env_paths.cpp:73
Helper functions to substitute paths with environmental variables.
Functions related to environment variables, including help functions.
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
static const std::string SymbolLibraryTableFileName
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
PROJECT & Prj()
Definition kicad.cpp:737
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
Definition env_vars.cpp:78
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:640
static constexpr int ID_PANEL_SYM_LIB_NEW_DATABASE
static constexpr int FIRST_MENU_ID
Special menu ID for folder-based KiCad symbol library format.
static constexpr int ID_PANEL_SYM_LIB_KICAD_FOLDER
void InvokeSchEditSymbolLibTable(KIWAY *aKiway, wxWindow *aParent)
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
Definition project.h:37
T * GetAppSettings(const char *aFilename)
std::vector< FAB_LAYER_COLOR > dummy
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
Container that describes file type info.
Definition io_base.h:43
bool m_IsFile
Whether the library is a folder or a file.
Definition io_base.h:51
wxString FileFilter() const
Definition io_base.cpp:40
Implement a participant in the KIWAY alchemy.
Definition kiway.h:153
wxString message
Container that describes file type info for the add a library options.
bool m_IsFile
Whether the library is a folder or a file.
wxString m_Description
Description shown in the file picker dialog.
wxString m_FileFilter
Filter used for file pickers if m_IsFile is true.
DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T m_Plugin
wxString m_FolderSearchExtension
In case of folders it stands for extensions of files stored inside.
std::string path
KIBIS_MODEL * model
wxString result
Test unit parsing edge cases and error handling.
Definition of file extensions used in Kicad.