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 along
19 * with this program. If not, see <http://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>
37#include <confirm.h>
38#include <bitmaps.h>
41#include <env_paths.h>
42#include <functional>
43#include <eeschema_id.h>
44#include <env_vars.h>
45#include <sch_io/sch_io.h>
46#include <symbol_edit_frame.h>
47#include <sch_edit_frame.h>
48#include <kiway.h>
49#include <paths.h>
50#include <pgm_base.h>
52#include <wx/filedlg.h>
53#include <wx/msgdlg.h>
54#include <project_sch.h>
58
59
64{
65 wxString m_Description;
66 wxString m_FileFilter;
67
70 bool m_IsFile;
71 SCH_IO_MGR::SCH_FILE_T m_Plugin;
72};
73
74
78enum {
81};
82
83
85{
86public:
87 SYMBOL_LIB_TABLE_GRID_DATA_MODEL( DIALOG_SHIM* aParent, WX_GRID* aGrid, const LIBRARY_TABLE& aTableToEdit,
88 SYMBOL_LIBRARY_ADAPTER* aAdapter, const wxArrayString& aPluginChoices,
89 wxString* aMRUDirectory, const wxString& aProjectPath ) :
90 LIB_TABLE_GRID_DATA_MODEL( aParent, aGrid, aTableToEdit, aAdapter, aPluginChoices, aMRUDirectory,
91 aProjectPath )
92 {
93 }
94
95 void SetValue( int aRow, int aCol, const wxString &aValue ) override
96 {
97 wxCHECK( aRow < (int) size(), /* void */ );
98
99 LIB_TABLE_GRID_DATA_MODEL::SetValue( aRow, aCol, aValue );
100
101 // If setting a filepath, attempt to auto-detect the format
102 if( aCol == COL_URI )
103 {
104 LIBRARY_TABLE_ROW& row = at( static_cast<size_t>( aRow ) );
105 wxString uri = LIBRARY_MANAGER::ExpandURI( row.URI(), Pgm().GetSettingsManager().Prj() );
106 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( uri );
107
108 if( pluginType != SCH_IO_MGR::SCH_FILE_UNKNOWN )
109 SetValue( aRow, COL_TYPE, SCH_IO_MGR::ShowType( pluginType ) );
110 }
111 }
112
113protected:
114 wxString getFileTypes( WX_GRID* aGrid, int aRow ) override
115 {
116 LIB_TABLE_GRID_DATA_MODEL* table = static_cast<LIB_TABLE_GRID_DATA_MODEL*>( aGrid->GetTable() );
117 LIBRARY_TABLE_ROW& tableRow = table->At( aRow );
118
119 if( tableRow.Type() == LIBRARY_TABLE_ROW::TABLE_TYPE_NAME )
120 return wxEmptyString;
121
122 SCH_IO_MGR::SCH_FILE_T pi_type = SCH_IO_MGR::EnumFromStr( tableRow.Type() );
123 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pi_type ) );
124
125 if( pi )
126 {
127 const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc();
128
129 if( desc.m_IsFile )
130 return desc.FileFilter();
131 }
132 else if( tableRow.Type() == LIBRARY_TABLE_ROW::TABLE_TYPE_NAME )
133 {
134 // TODO(JE) library tables - wxWidgets doesn't allow filtering on no-extension filenames
135 return wxString::Format( _( "Symbol Library Tables (%s)|*" ),
138 }
139
140 return wxEmptyString;
141 }
142};
143
144
146{
147public:
149 std::function<void( wxCommandEvent& )> aAddHandler ) :
150 LIB_TABLE_GRID_TRICKS( aGrid, aAddHandler ),
151 m_panel( aPanel )
152 {
154 }
155
156protected:
157 void optionsEditor( int aRow ) override
158 {
159 LIB_TABLE_GRID_DATA_MODEL* tbl = static_cast<LIB_TABLE_GRID_DATA_MODEL*>( m_grid->GetTable() );
160
161 if( tbl->GetNumberRows() > aRow )
162 {
163 LIBRARY_TABLE_ROW& row = tbl->At( static_cast<size_t>( aRow ) );
164 const wxString& options = row.Options();
165 wxString result = options;
166 std::map<std::string, UTF8> choices;
167
168 SCH_IO_MGR::SCH_FILE_T pi_type = SCH_IO_MGR::EnumFromStr( row.Type() );
169 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pi_type ) );
170 pi->GetLibraryOptions( &choices );
171
172 DIALOG_PLUGIN_OPTIONS dlg( wxGetTopLevelParent( m_grid ), row.Nickname(), choices, options, &result );
173 dlg.ShowModal();
174
175 if( options != result )
176 {
177 row.SetOptions( result );
178 m_grid->Refresh();
179 }
180 }
181 }
182
183 void openTable( const LIBRARY_TABLE_ROW& aRow ) override
184 {
185 wxString uri = LIBRARY_MANAGER::ExpandURI( aRow.URI(), Pgm().GetSettingsManager().Prj() );
186 auto nestedTable = std::make_unique<LIBRARY_TABLE>( uri, LIBRARY_TABLE_SCOPE::GLOBAL );
187
188 m_panel->AddTable( nestedTable.get(), aRow.Nickname(), true );
189 }
190
191 wxString getTablePreamble() override
192 {
193 return wxT( "(sym_lib_table" );
194 }
195
197 {
198 return true;
199 }
200
201protected:
203};
204
205
206void PANEL_SYM_LIB_TABLE::AddTable( LIBRARY_TABLE* table, const wxString& aTitle, bool aClosable )
207{
209 wxString projectPath = m_project->GetProjectPath();
210
212
213 WX_GRID* grid = get_grid( (int) m_notebook->GetPageCount() - 1 );
214
215 if( table->Path().StartsWith( projectPath ) )
216 {
218 &m_lastProjectLibDir, projectPath ),
219 true /* take ownership */ );
220 }
221 else
222 {
223 wxString* lastGlobalLibDir = nullptr;
224
226 {
227 if( cfg->m_lastSymbolLibDir.IsEmpty() )
228 cfg->m_lastSymbolLibDir = PATHS::GetDefaultUserSymbolsPath();
229
230 lastGlobalLibDir = &cfg->m_lastSymbolLibDir;
231 }
232
234 lastGlobalLibDir, wxEmptyString ),
235 true /* take ownership */ );
236 }
237
238 // add Cut, Copy, and Paste to wxGrids
239 grid->PushEventHandler( new SYMBOL_GRID_TRICKS( this, grid,
240 [this]( wxCommandEvent& event )
241 {
242 appendRowHandler( event );
243 } ) );
244
245 auto autoSizeCol =
246 [&]( int aCol )
247 {
248 int prevWidth = grid->GetColSize( aCol );
249
250 grid->AutoSizeColumn( aCol, false );
251 grid->SetColSize( aCol, std::max( prevWidth, grid->GetColSize( aCol ) ) );
252 };
253
254 // all but COL_OPTIONS, which is edited with Option Editor anyways.
255 autoSizeCol( COL_NICKNAME );
256 autoSizeCol( COL_TYPE );
257 autoSizeCol( COL_URI );
258 autoSizeCol( COL_DESCR );
259
260 if( grid->GetNumberRows() > 0 )
261 {
262 grid->SetGridCursor( 0, COL_NICKNAME );
263 grid->SelectRow( 0 );
264 }
265}
266
267
269 PANEL_SYM_LIB_TABLE_BASE( aParent ),
270 m_project( aProject ),
271 m_parent( aParent )
272{
273 m_lastProjectLibDir = m_project->GetProjectPath();
274
275 for( const SCH_IO_MGR::SCH_FILE_T& type : SCH_IO_MGR::SCH_FILE_T_vector )
276 {
277 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( type ) );
278
279 if( !pi )
280 continue;
281
282 if( const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc() )
284 }
285
286 std::optional<LIBRARY_TABLE*> table = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
288 wxASSERT( table.has_value() );
289
290 AddTable( table.value(), _( "Global Libraries" ), false /* closable */ );
291
292 std::optional<LIBRARY_TABLE*> projectTable = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
294
295 if( projectTable.has_value() )
296 AddTable( projectTable.value(), _( "Project Specific Libraries" ), false /* closable */ );
297
298 m_notebook->SetArtProvider( new WX_AUI_TAB_ART() );
299
300 // add Cut, Copy, and Paste to wxGrids
301 m_path_subs_grid->PushEventHandler( new GRID_TRICKS( m_path_subs_grid ) );
302
304
305 m_path_subs_grid->SetColLabelValue( 0, _( "Name" ) );
306 m_path_subs_grid->SetColLabelValue( 1, _( "Value" ) );
307
308 // Configure button logos
314
315 m_notebook->Bind( wxEVT_AUINOTEBOOK_PAGE_CLOSE, &PANEL_SYM_LIB_TABLE::onNotebookPageCloseRequest, this );
316}
317
318
320{
321 // Delete the GRID_TRICKS.
322 // (Notebook page GRID_TRICKS are deleted by LIB_TABLE_NOTEBOOK_PANEL.)
323 m_path_subs_grid->PopEventHandler( true );
324 m_path_subs_grid->PopEventHandler( true );
325}
326
327
329{
330 return static_cast<SYMBOL_LIB_TABLE_GRID_DATA_MODEL*>( get_grid( aPage )->GetTable() );
331}
332
333
335{
336 return static_cast<LIB_TABLE_NOTEBOOK_PANEL*>( m_notebook->GetPage( aPage ) )->GetGrid();
337}
338
339
341{
342 // for ALT+A handling, we want the initial focus to be on the first selected grid.
343 m_parent->SetInitialFocus( cur_grid() );
344
345 return true;
346}
347
348
350{
351 wxString msg;
352
353 for( int page = 0 ; page < (int) m_notebook->GetPageCount(); ++page )
354 {
355 WX_GRID* grid = get_grid( page );
356
358 [&]( int aRow, int aCol )
359 {
360 // show the tabbed panel holding the grid we have flunked:
361 if( m_notebook->GetSelection() != page )
362 m_notebook->SetSelection( page );
363
364 grid->MakeCellVisible( aRow, 0 );
365 grid->SetGridCursor( aRow, aCol );
366 } ) )
367 {
368 return false;
369 }
370 }
371
372 return true;
373}
374
375
377{
378 if( !cur_grid()->CommitPendingChanges() )
379 return;
380
381 wxString fileFiltersStr;
382 wxString allWildcardsStr;
383
384 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
385 {
386 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
387
388 if( !pi )
389 continue;
390
391 const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc();
392
393 if( desc.m_FileExtensions.empty() )
394 continue;
395
396 if( !fileFiltersStr.IsEmpty() )
397 fileFiltersStr += wxChar( '|' );
398
399 fileFiltersStr += desc.FileFilter();
400
401 for( const std::string& ext : desc.m_FileExtensions )
402 allWildcardsStr << wxT( "*." ) << formatWildcardExt( ext ) << wxT( ";" );
403 }
404
405 fileFiltersStr = _( "All supported formats" ) + wxT( "|" ) + allWildcardsStr + wxT( "|" )
406 + fileFiltersStr;
407
409 wxString dummy;
410 wxString* lastDir;
411
412 if( m_notebook->GetSelection() == 0 )
413 lastDir = cfg ? &cfg->m_lastSymbolLibDir : &dummy;
414 else
415 lastDir = &m_lastProjectLibDir;
416
417 wxWindow* topLevelParent = wxGetTopLevelParent( this );
418
419 wxFileDialog dlg( topLevelParent, _( "Add Library" ), *lastDir, wxEmptyString, fileFiltersStr,
420 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE );
421
422 if( dlg.ShowModal() == wxID_CANCEL )
423 return;
424
425 *lastDir = dlg.GetDirectory();
426
427 const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
428 bool addDuplicates = false;
429 bool applyToAll = false;
430
431 wxArrayString filePathsList;
432 dlg.GetPaths( filePathsList );
433
434 for( const wxString& filePath : filePathsList )
435 {
436 wxFileName fn( filePath );
437 wxString nickname = LIB_ID::FixIllegalChars( fn.GetName(), true );
438 bool doAdd = true;
439
440 if( cur_model()->ContainsNickname( nickname ) )
441 {
442 if( !applyToAll )
443 {
444 // The cancel button adds the library to the table anyway
445 addDuplicates = OKOrCancelDialog( wxGetTopLevelParent( this ), _( "Warning: Duplicate Nickname" ),
446 wxString::Format( _( "An item nicknamed '%s' already exists." ),
447 nickname ),
448 _( "One of the nicknames will need to be changed." ),
449 _( "Skip" ), _( "Add Anyway" ),
450 &applyToAll ) == wxID_CANCEL;
451 }
452
453 doAdd = addDuplicates;
454 }
455
456 if( doAdd && cur_grid()->AppendRows( 1 ) )
457 {
458 int last_row = cur_grid()->GetNumberRows() - 1;
459
460 cur_grid()->SetCellValue( last_row, COL_NICKNAME, nickname );
461
462 // attempt to auto-detect the plugin type
463 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( filePath );
464
465 if( pluginType != SCH_IO_MGR::SCH_FILE_UNKNOWN )
466 cur_grid()->SetCellValue( last_row, COL_TYPE, SCH_IO_MGR::ShowType( pluginType ) );
467
468 // try to use path normalized to an environmental variable or project path
469 wxString path = NormalizePath( filePath, &envVars, m_project->GetProjectPath() );
470
471 // Do not use the project path in the global library table. This will almost
472 // assuredly be wrong for a different project.
473 if( m_notebook->GetSelection() == 0 && path.Contains( "${KIPRJMOD}" ) )
474 path = fn.GetFullPath();
475
476 cur_grid()->SetCellValue( last_row, COL_URI, path );
477 }
478 }
479
480 if( !filePathsList.IsEmpty() )
481 {
482 cur_grid()->MakeCellVisible( cur_grid()->GetNumberRows() - 1, COL_ENABLED );
483 cur_grid()->SetGridCursor( cur_grid()->GetNumberRows() - 1, COL_NICKNAME );
484 }
485}
486
487
492
493
498
499
504
505
510
511
512void PANEL_SYM_LIB_TABLE::onReset( wxCommandEvent& event )
513{
514 if( !cur_grid()->CommitPendingChanges() )
515 return;
516
517 WX_GRID* grid = get_grid( 0 );
518
519 // No need to prompt to preserve an empty table
520 if( grid->GetNumberRows() > 0 && !IsOK( this, wxString::Format( _( "This action will reset your global library "
521 "table on disk and cannot be undone." ) ) ) )
522 {
523 return;
524 }
525
526 wxString* lastGlobalLibDir = nullptr;
527
529 {
530 if( cfg->m_lastSymbolLibDir.IsEmpty() )
531 cfg->m_lastSymbolLibDir = PATHS::GetDefaultUserSymbolsPath();
532
533 lastGlobalLibDir = &cfg->m_lastSymbolLibDir;
534 }
535
537
538 // Go ahead and reload here because this action takes place even if the dialog is canceled
540
541 if( KIFACE *schface = m_parent->Kiway().KiFACE( KIWAY::FACE_SCH ) )
542 schface->PreloadLibraries( &m_parent->Kiway() );
543
544 grid->Freeze();
545
546 wxGridTableBase* table = grid->GetTable();
547 grid->DestroyTable( table );
548
549 std::optional<LIBRARY_TABLE*> newTable = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
551 wxASSERT( newTable );
552
554
555 grid->SetTable( new SYMBOL_LIB_TABLE_GRID_DATA_MODEL( m_parent, grid, *newTable.value(), adapter, m_pluginChoices,
556 lastGlobalLibDir, wxEmptyString ),
557 true /* take ownership */ );
558
559 m_parent->m_GlobalTableChanged = true;
560
561 grid->Thaw();
562
563 if( grid->GetNumberRows() > 0 )
564 {
565 grid->SetGridCursor( 0, COL_NICKNAME );
566 grid->SelectRow( 0 );
567 }
568}
569
570
571void PANEL_SYM_LIB_TABLE::onPageChange( wxAuiNotebookEvent& event )
572{
573 m_resetGlobal->Enable( m_notebook->GetSelection() == 0 );
574}
575
576
577void PANEL_SYM_LIB_TABLE::onNotebookPageCloseRequest( wxAuiNotebookEvent& aEvent )
578{
579 wxAuiNotebook* notebook = (wxAuiNotebook*) aEvent.GetEventObject();
580 wxWindow* page = notebook->GetPage( aEvent.GetSelection() );
581
582 if( LIB_TABLE_NOTEBOOK_PANEL* panel = dynamic_cast<LIB_TABLE_NOTEBOOK_PANEL*>( page ) )
583 {
584 if( panel->GetClosable() )
585 {
586 if( !panel->GetCanClose() )
587 aEvent.Veto();
588 }
589 else
590 {
591 aEvent.Veto();
592 }
593 }
594}
595
596
598{
599 if( !cur_grid()->CommitPendingChanges() )
600 return;
601
602 wxArrayInt selectedRows = cur_grid()->GetSelectedRows();
603
604 if( selectedRows.empty() && cur_grid()->GetGridCursorRow() >= 0 )
605 selectedRows.push_back( cur_grid()->GetGridCursorRow() );
606
607 wxArrayInt legacyRows;
608 wxString databaseType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_DATABASE );
609 wxString kicadType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_KICAD );
610 wxString msg;
611
612 for( int row : selectedRows )
613 {
614 if( cur_grid()->GetCellValue( row, COL_TYPE ) != databaseType
615 && cur_grid()->GetCellValue( row, COL_TYPE ) != kicadType )
616 {
617 legacyRows.push_back( row );
618 }
619 }
620
621 if( legacyRows.size() <= 0 )
622 {
623 wxMessageBox( _( "Select one or more rows containing libraries to save as current KiCad format." ) );
624 return;
625 }
626 else
627 {
628 if( legacyRows.size() == 1 )
629 {
630 msg.Printf( _( "Save '%s' as current KiCad format (*.kicad_sym) and replace legacy entry in table?" ),
631 cur_grid()->GetCellValue( legacyRows[0], COL_NICKNAME ) );
632 }
633 else
634 {
635 msg.Printf( _( "Save %d libraries as current KiCad format (*.kicad_sym) and replace legacy entries "
636 "in table?" ),
637 (int) legacyRows.size() );
638 }
639
640 if( !IsOK( m_parent, msg ) )
641 return;
642 }
643
644 for( int row : legacyRows )
645 {
646 wxString relPath = cur_grid()->GetCellValue( row, COL_URI );
647 wxString resolvedPath = ExpandEnvVarSubstitutions( relPath, m_project );
648 wxFileName legacyLib( resolvedPath );
649
650 if( !legacyLib.Exists() )
651 {
652 DisplayErrorMessage( m_parent, wxString::Format( _( "Library '%s' not found." ), relPath ) );
653 continue;
654 }
655
656 wxFileName newLib( resolvedPath );
657 newLib.SetExt( "kicad_sym" );
658
659 if( newLib.Exists() )
660 {
661 msg.Printf( _( "File '%s' already exists. Do you want overwrite this file?" ), newLib.GetFullPath() );
662
663 switch( wxMessageBox( msg, _( "Migrate Library" ), wxYES_NO | wxCANCEL | wxICON_QUESTION, m_parent ) )
664 {
665 case wxYES: break;
666 case wxNO: continue;
667 case wxCANCEL: return;
668 }
669 }
670
671 wxString options = cur_grid()->GetCellValue( row, COL_OPTIONS );
672 std::map<std::string, UTF8> props( LIBRARY_TABLE::ParseOptions( options.ToStdString() ) );
673
674 if( SCH_IO_MGR::ConvertLibrary( &props, legacyLib.GetFullPath(), newLib.GetFullPath() ) )
675 {
676 relPath = NormalizePath( newLib.GetFullPath(), &Pgm().GetLocalEnvVariables(), m_project );
677
678 cur_grid()->SetCellValue( row, COL_URI, relPath );
679 cur_grid()->SetCellValue( row, COL_TYPE, kicadType );
680 cur_grid()->SetCellValue( row, COL_OPTIONS, wxEmptyString );
681 }
682 else
683 {
684 DisplayErrorMessage( m_parent, wxString::Format( _( "Failed to save symbol library file '%s'." ),
685 newLib.GetFullPath() ) );
686 }
687 }
688}
689
690
692{
693 if( !cur_grid()->CommitPendingChanges() )
694 return false;
695
696 if( !verifyTables() )
697 return false;
698
699 std::optional<LIBRARY_TABLE*> optTable = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
701 wxCHECK( optTable, false );
702 LIBRARY_TABLE* globalTable = *optTable;
703
704 if( get_model( 0 )->Table() != *globalTable )
705 {
706 m_parent->m_GlobalTableChanged = true;
707 *globalTable = get_model( 0 )->Table();
708
709 globalTable->Save().map_error(
710 []( const LIBRARY_ERROR& aError )
711 {
712 wxMessageBox( _( "Error saving global library table:\n\n" ) + aError.message,
713 _( "File Save Error" ), wxOK | wxICON_ERROR );
714 } );
715 }
716
718
719 if( optTable.has_value() && get_model( 1 )->Table().Path() == optTable.value()->Path() )
720 {
721 LIBRARY_TABLE* projectTable = *optTable;
722
723 if( get_model( 1 )->Table() != *projectTable )
724 {
725 m_parent->m_ProjectTableChanged = true;
726 *projectTable = get_model( 1 )->Table();
727
728 projectTable->Save().map_error(
729 []( const LIBRARY_ERROR& aError )
730 {
731 wxMessageBox( _( "Error saving project-specific library table:\n\n" ) + aError.message,
732 _( "File Save Error" ), wxOK | wxICON_ERROR );
733 } );
734 }
735 }
736
737 for( int ii = 0; ii < (int) m_notebook->GetPageCount(); ++ii )
738 {
739 LIB_TABLE_NOTEBOOK_PANEL* panel = static_cast<LIB_TABLE_NOTEBOOK_PANEL*>( m_notebook->GetPage( ii ) );
740
741 if( panel->GetClosable() && panel->TableModified() )
742 {
743 panel->SaveTable();
744 m_parent->m_GlobalTableChanged = true;
745 m_parent->m_ProjectTableChanged = true;
746 }
747 }
748
749 return true;
750}
751
752
754{
755 wxRegEx re( ".*?(\\$\\{(.+?)\\})|(\\$\\((.+?)\\)).*?", wxRE_ADVANCED );
756 wxASSERT( re.IsValid() ); // wxRE_ADVANCED is required.
757
758 std::set< wxString > unique;
759
760 // clear the table
761 m_path_subs_grid->ClearRows();
762
763 for( int page = 0 ; page < (int) m_notebook->GetPageCount(); ++page )
764 {
765 LIB_TABLE_GRID_DATA_MODEL* model = get_model( page );
766
767 for( int row = 0; row < model->GetNumberRows(); ++row )
768 {
769 wxString uri = model->GetValue( row, COL_URI );
770
771 while( re.Matches( uri ) )
772 {
773 wxString envvar = re.GetMatch( uri, 2 );
774
775 // if not ${...} form then must be $(...)
776 if( envvar.IsEmpty() )
777 envvar = re.GetMatch( uri, 4 );
778
779 // ignore duplicates
780 unique.insert( envvar );
781
782 // delete the last match and search again
783 uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString );
784 }
785 }
786 }
787
788 // Make sure this special environment variable shows up even if it was
789 // not used yet. It is automatically set by KiCad to the directory holding
790 // the current project.
791 unique.insert( PROJECT_VAR_NAME );
792 unique.insert( ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) ) );
793
794 for( const wxString& evName : unique )
795 {
796 int row = m_path_subs_grid->GetNumberRows();
797 m_path_subs_grid->AppendRows( 1 );
798
799 m_path_subs_grid->SetCellValue( row, 0, wxT( "${" ) + evName + wxT( "}" ) );
800 m_path_subs_grid->SetCellEditor( row, 0, new GRID_CELL_READONLY_TEXT_EDITOR() );
801
802 wxString evValue;
803 wxGetEnv( evName, &evValue );
804 m_path_subs_grid->SetCellValue( row, 1, evValue );
805 m_path_subs_grid->SetCellEditor( row, 1, new GRID_CELL_READONLY_TEXT_EDITOR() );
806 }
807
808 adjustPathSubsGridColumns( m_path_subs_grid->GetRect().GetWidth() );
809}
810
811
813{
814 // Account for scroll bars
815 aWidth -= ( m_path_subs_grid->GetSize().x - m_path_subs_grid->GetClientSize().x );
816
817 m_path_subs_grid->AutoSizeColumn( 0 );
818 m_path_subs_grid->SetColSize( 0, std::max( 72, m_path_subs_grid->GetColSize( 0 ) ) );
819 m_path_subs_grid->SetColSize( 1, std::max( 120, aWidth - m_path_subs_grid->GetColSize( 0 ) ) );
820}
821
822
823void PANEL_SYM_LIB_TABLE::onSizeGrid( wxSizeEvent& event )
824{
825 adjustPathSubsGridColumns( event.GetSize().GetX() );
826
827 event.Skip();
828}
829
830
831void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
832{
833 auto symbolEditor = static_cast<SYMBOL_EDIT_FRAME*>( aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false ) );
834 wxString msg;
835
836 if( symbolEditor )
837 {
838 // This prevents an ugly crash on OSX (https://bugs.launchpad.net/kicad/+bug/1765286)
839 symbolEditor->FreezeLibraryTree();
840
841 if( symbolEditor->HasLibModifications() )
842 {
843 msg = _( "Modifications have been made to one or more symbol libraries.\n"
844 "Changes must be saved or discarded before the symbol library table can be modified." );
845
846 switch( UnsavedChangesDialog( aParent, msg ) )
847 {
848 case wxID_YES: symbolEditor->SaveAll(); break;
849 case wxID_NO: symbolEditor->RevertAll(); break;
850 default:
851 case wxID_CANCEL: symbolEditor->ThawLibraryTree(); return;
852 }
853 }
854 }
855
856 DIALOG_EDIT_LIBRARY_TABLES dlg( aParent, _( "Symbol Libraries" ) );
857 dlg.SetKiway( &dlg, aKiway );
858
859 dlg.InstallPanel( new PANEL_SYM_LIB_TABLE( &dlg, &aKiway->Prj() ) );
860
861 if( dlg.ShowModal() == wxID_CANCEL )
862 {
863 if( symbolEditor )
864 symbolEditor->ThawLibraryTree();
865
866 return;
867 }
868
869 if( dlg.m_GlobalTableChanged )
871
872 if( dlg.m_ProjectTableChanged )
873 {
874 // Trigger a reload of the table and cancel an in-progress background load
876 }
877
878 // Trigger a reload in case any libraries have been added or removed
879 if( KIFACE *schface = aKiway->KiFACE( KIWAY::FACE_SCH ) )
880 schface->PreloadLibraries( aKiway );
881
882 if( symbolEditor )
883 symbolEditor->ThawLibraryTree();
884}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
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:68
int ShowModal() override
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:61
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:75
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:292
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:403
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition kiway.cpp:206
@ FACE_SCH
eeschema DSO
Definition kiway.h:299
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition kiway.cpp:200
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...
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:192
This abstract base class mixes any object derived from #LIB_TABLE into wxGridTableBase so the result ...
virtual LIBRARY_TABLE_ROW & at(size_t aIndex)
wxString GetValue(int aRow, int aCol) override
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 bool VerifyTable(WX_GRID *aGrid, std::function< void(int aRow, int aCol)> aErrorHandler)
static void AppendRowHandler(WX_GRID *aGrid)
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 deleteRowHandler(wxCommandEvent &event) override
WX_GRID * get_grid(int aPage) const
void onNotebookPageCloseRequest(wxAuiNotebookEvent &aEvent)
void onPageChange(wxAuiNotebookEvent &event) override
void browseLibrariesHandler(wxCommandEvent &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)
void onSizeGrid(wxSizeEvent &event) override
void onConvertLegacyLibraries(wxCommandEvent &event) override
bool TransferDataToWindow() override
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:81
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition pgm_base.cpp:783
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:131
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Container for project specific data.
Definition project.h:65
static bool ConvertLibrary(std::map< std::string, UTF8 > *aOldFileProps, const wxString &aOldFilePath, const wxString &aNewFilepath)
Convert a schematic symbol library to the latest KiCad format.
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the #SCH_FILE_T from the corresponding plugin type name: "kicad", "legacy",...
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
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)
Replace any environment variable & text variable references with their values.
Definition common.cpp:365
The common library.
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:150
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:259
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
int UnsavedChangesDialog(wxWindow *parent, const wxString &aMessage, bool *aApplyToAll)
A specialized version of HandleUnsavedChanges which handles an apply-to-all checkbox.
Definition confirm.cpp:64
This file is part of the common library.
#define _(s)
@ ID_END_EESCHEMA_ID_LIST
Definition eeschema_id.h:78
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:35
static const std::string SymbolLibraryTableFileName
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
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:629
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
Definition env_vars.cpp:77
void InvokeSchEditSymbolLibTable(KIWAY *aKiway, wxWindow *aParent)
@ ID_PANEL_SYM_LIB_LEGACY
@ ID_PANEL_SYM_LIB_KICAD
SETTINGS_MANAGER * GetSettingsManager()
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:946
see class PGM_BASE
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
Definition project.h:41
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:45
bool m_IsFile
Whether the library is a folder or a file.
Definition io_base.h:53
std::vector< std::string > m_FileExtensions
Filter used for file pickers if m_IsFile is true.
Definition io_base.h:49
wxString FileFilter() const
Definition io_base.cpp:40
Implement a participant in the KIWAY alchemy.
Definition kiway.h:155
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.
wxString result
Test unit parsing edge cases and error handling.
wxString formatWildcardExt(const wxString &aWildcard)
Format wildcard extension to support case sensitive file dialogs.
Definition of file extensions used in Kicad.