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>
35#include <confirm.h>
36#include <bitmaps.h>
37#include <lib_table_grid.h>
39#include <env_paths.h>
40#include <functional>
41#include <eeschema_id.h>
42#include <env_vars.h>
43#include <sch_io/sch_io.h>
44#include <symbol_edit_frame.h>
45#include <symbol_viewer_frame.h>
46#include <sch_edit_frame.h>
47#include <kiway.h>
48#include <lib_table_base.h>
49#include <paths.h>
50#include <pgm_base.h>
55#include <sch_file_versions.h>
56#include <wx/filedlg.h>
57#include <wx/msgdlg.h>
58#include <project_sch.h>
60#include <widgets/grid_button.h>
61
62
63// clang-format off
64
69{
70 wxString m_Description;
71 wxString m_FileFilter;
72
75 bool m_IsFile;
76 SCH_IO_MGR::SCH_FILE_T m_Plugin;
77};
78
79
83enum {
86};
87
88// clang-format on
89
91{
92 friend class PANEL_SYM_LIB_TABLE;
93 friend class SYMBOL_GRID_TRICKS;
94
95public:
97 LIB_TABLE_GRID( aTableToEdit, aAdapter )
98 {
99 }
100
101 void SetValue( int aRow, int aCol, const wxString &aValue ) override
102 {
103 wxCHECK( aRow < (int) size(), /* void */ );
104
105 LIB_TABLE_GRID::SetValue( aRow, aCol, aValue );
106
107 // If setting a filepath, attempt to auto-detect the format
108 if( aCol == COL_URI )
109 {
110 LIBRARY_TABLE_ROW& row = at( static_cast<size_t>( aRow ) );
111 wxString uri = LIBRARY_MANAGER::ExpandURI( row.URI(), Pgm().GetSettingsManager().Prj() );
112
113 wxFileName fn( uri );
114
115 if( fn.GetName() == FILEEXT::SymbolLibraryTableFileName )
116 {
117 SetValue( aRow, COL_TYPE, _( "Table" ) );
118 }
119 else
120 {
121 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( uri );
122
123 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
124 pluginType = SCH_IO_MGR::SCH_KICAD;
125
126 SetValue( aRow, COL_TYPE, SCH_IO_MGR::ShowType( pluginType ) );
127 }
128 }
129 }
130};
131
132
134{
135public:
137 LIB_TABLE_GRID_TRICKS( aGrid ),
138 m_dialog( aParent ),
139 m_project( aProject )
140 {
142 }
143
145 std::function<void( wxCommandEvent& )> aAddHandler ) :
146 LIB_TABLE_GRID_TRICKS( aGrid, aAddHandler ),
147 m_dialog( aParent ),
148 m_project( aProject )
149 {
150 }
151
152protected:
154
155 void onGridCellLeftClick( wxGridEvent& aEvent ) override
156 {
157 if( aEvent.GetCol() == COL_STATUS )
158 {
159 // Status column button action depends on row:
160 // Normal rows should have no button, so they are a no-op
161 // Errored rows should have the warning button, so we show their error
162 // Configurable libraries will have the options button, so we launch the config
163 // Chained tables will have the open button, so we request the table be opened
165
166 auto libTable = static_cast<SYMBOL_LIB_TABLE_GRID*>( m_grid->GetTable() );
167 const LIBRARY_TABLE_ROW& row = libTable->at( aEvent.GetRow() );
168
169 wxString title = row.Type() == "Table"
170 ? wxString::Format( _( "Error loading library table '%s'" ), row.Nickname() )
171 : wxString::Format( _( "Error loading library '%s'" ), row.Nickname() );
172
173 if( !row.IsOk() )
174 {
176 }
177 else if( std::optional<LIBRARY_ERROR> e = adapter->LibraryError( row.Nickname() ) )
178 {
179 DisplayErrorMessage( m_grid, title, e->message );
180 }
181 else if( adapter->SupportsConfigurationDialog( row.Nickname() ) )
182 {
183 adapter->ShowConfigurationDialog( row.Nickname(), m_dialog );
184 }
185
186 aEvent.Skip();
187 }
188 else
189 {
191 }
192 }
193
194 void optionsEditor( int aRow ) override
195 {
196 auto tbl = static_cast<SYMBOL_LIB_TABLE_GRID*>( m_grid->GetTable() );
197
198 if( tbl->GetNumberRows() > aRow )
199 {
200 LIBRARY_TABLE_ROW& row = tbl->at( static_cast<size_t>( aRow ) );
201 const wxString& options = row.Options();
202 wxString result = options;
203 std::map<std::string, UTF8> choices;
204
205 SCH_IO_MGR::SCH_FILE_T pi_type = SCH_IO_MGR::EnumFromStr( row.Type() );
206 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pi_type ) );
207 pi->GetLibraryOptions( &choices );
208
209 DIALOG_PLUGIN_OPTIONS dlg( m_dialog, row.Nickname(), choices, options, &result );
210 dlg.ShowModal();
211
212 if( options != result )
213 {
214 row.SetOptions( result );
215 m_grid->Refresh();
216 }
217 }
218
219 }
220
223 void paste_text( const wxString& cb_text ) override
224 {
225 SYMBOL_LIB_TABLE_GRID* tbl = static_cast<SYMBOL_LIB_TABLE_GRID*>( m_grid->GetTable() );
226
227 if( size_t ndx = cb_text.find( "(sym_lib_table" ); ndx != std::string::npos )
228 {
229 // paste the SYMBOL_LIB_TABLE_ROWs of s-expression (sym_lib_table), starting
230 // at column 0 regardless of current cursor column.
231
232 if( LIBRARY_TABLE tempTable( cb_text, tbl->Table().Scope() ); tempTable.IsOk() )
233 {
234 std::ranges::copy( tempTable.Rows(),
235 std::inserter( tbl->Table().Rows(), tbl->Table().Rows().begin() ) );
236
237 if( tbl->GetView() )
238 {
239 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, 0, 0 );
240 tbl->GetView()->ProcessTableMessage( msg );
241 }
242 }
243 else
244 {
245 DisplayError( m_dialog, tempTable.ErrorDescription() );
246 }
247 }
248 else
249 {
250 wxString text = cb_text;
251
252 if( !text.Contains( '\t' ) && text.Contains( ',' ) )
253 text.Replace( ',', '\t' );
254
255 if( text.Contains( '\t' ) )
256 {
257 int row = m_grid->GetGridCursorRow();
258 m_grid->ClearSelection();
259 m_grid->SelectRow( row );
260 m_grid->SetGridCursor( row, 0 );
262 }
263
265
266 m_grid->AutoSizeColumns( false );
267 }
268
269 m_grid->AutoSizeColumns( false );
270 }
271
273 {
274 return true;
275 }
276
277private:
279};
280
281
283{
284 auto autoSizeCol =
285 [&]( WX_GRID* aCurrGrid, int aCol )
286 {
287 int prevWidth = aCurrGrid->GetColSize( aCol );
288
289 aCurrGrid->AutoSizeColumn( aCol, false );
290 aCurrGrid->SetColSize( aCol, std::max( prevWidth, aCurrGrid->GetColSize( aCol ) ) );
291 };
292
294
295 for( int ii = 0; ii < aGrid->GetNumberRows(); ++ii )
296 {
297 auto libTable = static_cast<SYMBOL_LIB_TABLE_GRID*>( aGrid->GetTable() );
298
299 if( LIBRARY_TABLE_ROW& tableRow = libTable->at( ii ); tableRow.IsOk() )
300 {
301 if( std::optional<LIBRARY_ERROR> error = adapter->LibraryError( tableRow.Nickname() ) )
302 {
303 aGrid->SetCellValue( ii, COL_STATUS, error->message );
304 aGrid->SetCellRenderer( ii, COL_STATUS,
306 }
307 else if( adapter->SupportsConfigurationDialog( tableRow.Nickname() ) )
308 {
309 aGrid->SetCellValue( ii, COL_STATUS,
310 wxString::Format( _( "Library settings for %s..." ),
311 tableRow.Nickname() ) );
312 aGrid->SetCellRenderer( ii, COL_STATUS,
314 }
315 }
316 else
317 {
318 aGrid->SetCellValue( ii, COL_STATUS, tableRow.ErrorDescription() );
319 aGrid->SetCellRenderer( ii, COL_STATUS,
321 }
322 }
323
324 // add Cut, Copy, and Paste to wxGrids
325 aGrid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, aGrid, m_parent->Kiway().Prj(),
326 [this]( wxCommandEvent& event )
327 {
328 appendRowHandler( event );
329 } ) );
330
331 aGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
332
333 // Set special attributes
334 wxGridCellAttr* attr = new wxGridCellAttr;
335
337 {
338 attr->SetEditor( new GRID_CELL_PATH_EDITOR(
339 m_parent, aGrid, &cfg->m_lastSymbolLibDir, true, m_project->GetProjectPath(),
340 []( WX_GRID* grid, int row ) -> wxString
341 {
342 auto libTable = static_cast<SYMBOL_LIB_TABLE_GRID*>( grid->GetTable() );
343 LIBRARY_TABLE_ROW& tableRow = libTable->at( row );
344 SCH_IO_MGR::SCH_FILE_T pi_type = SCH_IO_MGR::EnumFromStr( tableRow.Type() );
345
346 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pi_type ) );
347
348 if( pi )
349 {
350 const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc();
351
352 if( desc.m_IsFile )
353 return desc.FileFilter();
354 }
355 else if( tableRow.Type() == LIBRARY_TABLE_ROW::TABLE_TYPE_NAME )
356 {
357 // TODO(JE) library tables - wxWidgets doesn't allow filtering on no-extension filenames
358 return wxString::Format( _( "Symbol Library Tables (%s)|*" ),
359 FILEEXT::SymbolLibraryTableFileName,
360 FILEEXT::SymbolLibraryTableFileName );
361 }
362
363 return wxEmptyString;
364 } ) );
365 }
366
367 aGrid->SetColAttr( COL_URI, attr );
368
369 attr = new wxGridCellAttr;
370 attr->SetEditor( new wxGridCellChoiceEditor( m_pluginChoices ) );
371 aGrid->SetColAttr( COL_TYPE, attr );
372
373 attr = new wxGridCellAttr;
374 attr->SetReadOnly();
375 aGrid->SetColAttr( COL_STATUS, attr );
376
377 attr = new wxGridCellAttr;
378 attr->SetRenderer( new wxGridCellBoolRenderer() );
379 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
380 attr->SetAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE );
381 aGrid->SetColAttr( COL_ENABLED, attr );
382
383 attr = new wxGridCellAttr;
384 attr->SetRenderer( new wxGridCellBoolRenderer() );
385 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
386 attr->SetAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE );
387 aGrid->SetColAttr( COL_VISIBLE, attr );
388
389 aGrid->DisableColResize( COL_STATUS );
390 aGrid->DisableColResize( COL_VISIBLE );
391 aGrid->DisableColResize( COL_ENABLED );
392
393 aGrid->AutoSizeColumn( COL_STATUS, true );
394 aGrid->AutoSizeColumn( COL_VISIBLE, true );
395 aGrid->AutoSizeColumn( COL_ENABLED, true );
396
397 // all but COL_OPTIONS, which is edited with Option Editor anyways.
398 autoSizeCol( aGrid, COL_NICKNAME );
399 autoSizeCol( aGrid, COL_TYPE );
400 autoSizeCol( aGrid, COL_URI );
401 autoSizeCol( aGrid, COL_DESCR );
402
403 // Gives a selection to each grid, mainly for delete button. wxGrid's wake up with
404 // a currentCell which is sometimes not highlighted.
405 if( aGrid->GetNumberRows() > 0 )
406 aGrid->SelectRow( 0 );
407};
408
409
411 PANEL_SYM_LIB_TABLE_BASE( aParent ),
412 m_project( aProject ),
413 m_parent( aParent )
414{
415 std::optional<LIBRARY_TABLE*> table = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
417 wxASSERT( table );
418
420
421 // wxGrid only supports user owned tables if they exist past end of ~wxGrid(),
422 // so make it a grid owned table.
423 m_global_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *table.value(), adapter ) );
424
425 // TODO(JE) should use translated string here but type is stored as untranslated string
426 // Maybe type storage needs to be enum?
427 m_pluginChoices.Add( wxT( "Table" ) );
428
429 for( const SCH_IO_MGR::SCH_FILE_T& type : SCH_IO_MGR::SCH_FILE_T_vector )
430 {
431 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( type ) );
432
433 if( !pi )
434 continue;
435
436 if( const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc() )
438 }
439
441 {
442 if( cfg->m_lastSymbolLibDir.IsEmpty() )
443 cfg->m_lastSymbolLibDir = PATHS::GetDefaultUserSymbolsPath();
444 }
445
446 m_lastProjectLibDir = m_project->GetProjectPath();
447
449
450 std::optional<LIBRARY_TABLE*> projectTable = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
452
453 if( projectTable )
454 {
455 m_project_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *projectTable.value(), adapter ), true );
457 }
458 else
459 {
460 m_pageNdx = 0;
461 m_notebook->DeletePage( 1 );
462 m_project_grid = nullptr;
463 }
464
465 // add Cut, Copy, and Paste to wxGrids
466 m_path_subs_grid->PushEventHandler( new GRID_TRICKS( m_path_subs_grid ) );
467
469
470 // select the last selected page
471 m_notebook->SetSelection( m_pageNdx );
473
474 m_path_subs_grid->SetColLabelValue( 0, _( "Name" ) );
475 m_path_subs_grid->SetColLabelValue( 1, _( "Value" ) );
476
477 // for ALT+A handling, we want the initial focus to be on the first selected grid.
478 m_parent->SetInitialFocus( m_cur_grid );
479
480 // Configure button logos
486}
487
488
490{
491 // Delete the GRID_TRICKS.
492 // Any additional event handlers should be popped before the window is deleted.
493 m_global_grid->PopEventHandler( true );
494
495 if( m_project_grid )
496 m_project_grid->PopEventHandler( true );
497
498 m_path_subs_grid->PopEventHandler( true );
499}
500
501
503{
504 // When the plugin type depends only of the file extension, return true.
505 // if it needs to read the actual file (that can be not available), return false
506
507 wxFileName fn( aLibraryPath );
508 wxString ext = fn.GetExt().Lower();
509
510 // Currently, only the extension .lib is common to legacy libraries and Cadstar libraries
511 // so return false in this case
513 return false;
514
515 return true;
516}
517
518
520{
521 wxString msg;
522 int cursorCol;
523 std::unique_ptr<wxBusyCursor> wait;
524 wait.reset( new wxBusyCursor );
525
526 for( SYMBOL_LIB_TABLE_GRID* model : { global_model(), project_model() } )
527 {
528 if( !model )
529 continue;
530
531 for( int r = 0; r < model->GetNumberRows(); ++r )
532 {
533 wxString nick = model->GetValue( r, COL_NICKNAME ).Trim( false ).Trim();
534 wxString uri = model->GetValue( r, COL_URI ).Trim( false ).Trim();
535 unsigned illegalCh = 0;
536
537 if( !nick || !uri )
538 {
539 if( !nick && !uri )
540 {
541 msg = _( "Nickname and path cannot be empty." );
542 cursorCol = COL_NICKNAME;
543 }
544 else if( !nick )
545 {
546 msg = _( "Nickname cannot be empty." );
547 cursorCol = COL_NICKNAME;
548 }
549 else
550 {
551 msg = _( "Path cannot be empty." );
552 cursorCol = COL_URI;
553 }
554
555 // show the tabbed panel holding the grid we have flunked:
556 if( model != cur_model() )
557 m_notebook->SetSelection( model == global_model() ? 0 : 1 );
558
559 m_cur_grid->MakeCellVisible( r, 0 );
560 m_cur_grid->SetGridCursor( r, cursorCol );
561
562 wxWindow* topLevelParent = wxGetTopLevelParent( this );
563
564 wxMessageDialog errdlg( topLevelParent, msg, _( "Library Table Error" ) );
565
566 wait.reset();
567 errdlg.ShowModal();
568 return false;
569 }
570 else if( ( illegalCh = LIB_ID::FindIllegalLibraryNameChar( nick ) ) )
571 {
572 msg = wxString::Format( _( "Illegal character '%c' in nickname '%s'" ),
573 illegalCh,
574 nick );
575
576 // show the tabbed panel holding the grid we have flunked:
577 if( model != cur_model() )
578 m_notebook->SetSelection( model == global_model() ? 0 : 1 );
579
580 m_cur_grid->MakeCellVisible( r, 0 );
581 m_cur_grid->SetGridCursor( r, COL_NICKNAME );
582
583 wxWindow* topLevelParent = wxGetTopLevelParent( this );
584
585 wxMessageDialog errdlg( topLevelParent, msg, _( "Library Nickname Error" ) );
586
587 wait.reset();
588 errdlg.ShowModal();
589 return false;
590 }
591 else
592 {
593 // set the trimmed values back into the table so they get saved to disk.
594 model->SetValue( r, COL_NICKNAME, nick );
595
597 {
598 model->SetValue( r, COL_URI, uri );
599 }
600 else
601 {
602 wxString ltype = model->GetValue( r, COL_TYPE );
603 model->LIB_TABLE_GRID::SetValue( r, COL_URI, uri );
604 model->SetValue( r, COL_TYPE, ltype );
605 }
606 }
607 }
608 }
609
610 // check for duplicate nickNames, separately in each table.
611 for( SYMBOL_LIB_TABLE_GRID* model : { global_model(), project_model() } )
612 {
613 if( !model )
614 continue;
615
616 for( int r1 = 0; r1 < model->GetNumberRows() - 1; ++r1 )
617 {
618 wxString nick1 = model->GetValue( r1, COL_NICKNAME );
619
620 for( int r2 = r1 + 1; r2 < model->GetNumberRows(); ++r2 )
621 {
622 wxString nick2 = model->GetValue( r2, COL_NICKNAME );
623
624 if( nick1 == nick2 )
625 {
626 msg = wxString::Format( _( "Multiple libraries cannot share the same nickname ('%s')." ),
627 nick1 );
628
629 // show the tabbed panel holding the grid we have flunked:
630 if( model != cur_model() )
631 m_notebook->SetSelection( model == global_model() ? 0 : 1 );
632
633 // go to the lower of the two rows, it is technically the duplicate:
634 m_cur_grid->MakeCellVisible( r2, 0 );
635 m_cur_grid->SetGridCursor( r2, COL_NICKNAME );
636
637 wxWindow* topLevelParent = wxGetTopLevelParent( this );
638
639 wait.reset();
640 wxMessageDialog errdlg( topLevelParent, msg, _( "Library Nickname Error" ) );
641 errdlg.ShowModal();
642
643 return false;
644 }
645 }
646 }
647 }
648
649 return true;
650}
651
652
653void PANEL_SYM_LIB_TABLE::OnUpdateUI( wxUpdateUIEvent& event )
654{
655}
656
657
659{
660 wxString fileFiltersStr;
661 wxString allWildcardsStr;
662
663 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
664 {
665 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
666
667 if( !pi )
668 continue;
669
670 const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc();
671
672 if( desc.m_FileExtensions.empty() )
673 continue;
674
675 if( !fileFiltersStr.IsEmpty() )
676 fileFiltersStr += wxChar( '|' );
677
678 fileFiltersStr += desc.FileFilter();
679
680 for( const std::string& ext : desc.m_FileExtensions )
681 allWildcardsStr << wxT( "*." ) << formatWildcardExt( ext ) << wxT( ";" );
682 }
683
684 fileFiltersStr = _( "All supported formats" ) + wxT( "|" ) + allWildcardsStr + wxT( "|" )
685 + fileFiltersStr;
686
688 wxString dummy;
689 wxString* lastDir;
690
692 lastDir = &m_lastProjectLibDir;
693 else
694 lastDir = cfg ? &cfg->m_lastSymbolLibDir : &dummy;
695
696 wxWindow* topLevelParent = wxGetTopLevelParent( this );
697
698 wxFileDialog dlg( topLevelParent, _( "Add Library" ), *lastDir, wxEmptyString, fileFiltersStr,
699 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE );
700
701 if( dlg.ShowModal() == wxID_CANCEL )
702 return;
703
704 *lastDir = dlg.GetDirectory();
705
706 const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
707 bool addDuplicates = false;
708 bool applyToAll = false;
709
710 wxArrayString filePathsList;
711 dlg.GetPaths( filePathsList );
712
713 for( const wxString& filePath : filePathsList )
714 {
715 wxFileName fn( filePath );
716 wxString nickname = LIB_ID::FixIllegalChars( fn.GetName(), true );
717 bool doAdd = true;
718
719 if( cur_model()->ContainsNickname( nickname ) )
720 {
721 if( !applyToAll )
722 {
723 // The cancel button adds the library to the table anyway
724 addDuplicates = OKOrCancelDialog( wxGetTopLevelParent( this ), _( "Warning: Duplicate Nickname" ),
725 wxString::Format( _( "A library nicknamed '%s' already exists." ),
726 nickname ),
727 _( "One of the nicknames will need to be changed after adding "
728 "this library." ),
729 _( "Skip" ), _( "Add Anyway" ),
730 &applyToAll ) == wxID_CANCEL;
731 }
732
733 doAdd = addDuplicates;
734 }
735
736 if( doAdd && m_cur_grid->AppendRows( 1 ) )
737 {
738 int last_row = m_cur_grid->GetNumberRows() - 1;
739
740 m_cur_grid->SetCellValue( last_row, COL_NICKNAME, nickname );
741
742 // attempt to auto-detect the plugin type
743 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( filePath );
744
745 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
746 pluginType = SCH_IO_MGR::SCH_KICAD;
747
748 m_cur_grid->SetCellValue( last_row, COL_TYPE, SCH_IO_MGR::ShowType( pluginType ) );
749
750 // try to use path normalized to an environmental variable or project path
751 wxString path = NormalizePath( filePath, &envVars, m_project->GetProjectPath() );
752
753 // Do not use the project path in the global library table. This will almost
754 // assuredly be wrong for a different project.
755 if( m_pageNdx == 0 && path.Contains( "${KIPRJMOD}" ) )
756 path = fn.GetFullPath();
757
758 m_cur_grid->SetCellValue( last_row, COL_URI, path );
759 }
760 }
761
762 if( !filePathsList.IsEmpty() )
763 {
764 m_cur_grid->MakeCellVisible( m_cur_grid->GetNumberRows() - 1, COL_ENABLED );
765 m_cur_grid->SetGridCursor( m_cur_grid->GetNumberRows() - 1, COL_NICKNAME );
766 }
767}
768
769
770void PANEL_SYM_LIB_TABLE::appendRowHandler( wxCommandEvent& event )
771{
772 m_cur_grid->OnAddRow(
773 [&]() -> std::pair<int, int>
774 {
775 m_cur_grid->AppendRows( 1 );
776 return { m_cur_grid->GetNumberRows() - 1, COL_NICKNAME };
777 } );
778}
779
780
781void PANEL_SYM_LIB_TABLE::deleteRowHandler( wxCommandEvent& event )
782{
783 if( !m_cur_grid->CommitPendingChanges() )
784 return;
785
786 wxGridUpdateLocker noUpdates( m_cur_grid );
787
788 int curRow = m_cur_grid->GetGridCursorRow();
789 int curCol = m_cur_grid->GetGridCursorCol();
790
791 // In a wxGrid, collect rows that have a selected cell, or are selected
792 // It is not so easy: it depends on the way the selection was made.
793 // Here, we collect rows selected by clicking on a row label, and rows that contain
794 // previously-selected cells.
795 // If no candidate, just delete the row with the grid cursor.
796 wxArrayInt selectedRows = m_cur_grid->GetSelectedRows();
797 wxGridCellCoordsArray cells = m_cur_grid->GetSelectedCells();
798 wxGridCellCoordsArray blockTopLeft = m_cur_grid->GetSelectionBlockTopLeft();
799 wxGridCellCoordsArray blockBotRight = m_cur_grid->GetSelectionBlockBottomRight();
800
801 // Add all row having cell selected to list:
802 for( unsigned ii = 0; ii < cells.GetCount(); ii++ )
803 selectedRows.Add( cells[ii].GetRow() );
804
805 // Handle block selection
806 if( !blockTopLeft.IsEmpty() && !blockBotRight.IsEmpty() )
807 {
808 for( int i = blockTopLeft[0].GetRow(); i <= blockBotRight[0].GetRow(); ++i )
809 selectedRows.Add( i );
810 }
811
812 // Use the row having the grid cursor only if we have no candidate:
813 if( selectedRows.size() == 0 && m_cur_grid->GetGridCursorRow() >= 0 )
814 selectedRows.Add( m_cur_grid->GetGridCursorRow() );
815
816 if( selectedRows.size() == 0 )
817 {
818 wxBell();
819 return;
820 }
821
822 std::sort( selectedRows.begin(), selectedRows.end() );
823
824 // Remove selected rows (note: a row can be stored more than once in list)
825 int last_row = -1;
826
827 // Needed to avoid a wxWidgets alert if the row to delete is the last row
828 // at least on wxMSW 3.2
829 m_cur_grid->ClearSelection();
830
831 for( int ii = selectedRows.GetCount()-1; ii >= 0; ii-- )
832 {
833 int row = selectedRows[ii];
834
835 if( row != last_row )
836 {
837 last_row = row;
838 m_cur_grid->DeleteRows( row, 1 );
839 }
840 }
841
842 if( m_cur_grid->GetNumberRows() > 0 && curRow >= 0 )
843 m_cur_grid->SetGridCursor( std::min( curRow, m_cur_grid->GetNumberRows() - 1 ), curCol );
844}
845
846
847void PANEL_SYM_LIB_TABLE::moveUpHandler( wxCommandEvent& event )
848{
849 m_cur_grid->OnMoveRowUp(
850 [&]( int row )
851 {
853 int curRow = m_cur_grid->GetGridCursorRow();
854
855 std::vector<LIBRARY_TABLE_ROW>& rows = tbl->Table().Rows();
856
857 auto current = rows.begin() + curRow;
858 auto prev = rows.begin() + curRow - 1;
859
860 std::iter_swap( current, prev );
861
862 // Update the wxGrid
863 wxGridTableMessage msg( cur_model(), wxGRIDTABLE_NOTIFY_ROWS_INSERTED, row - 1, 0 );
864 cur_model()->GetView()->ProcessTableMessage( msg );
865 } );
866}
867
868
869void PANEL_SYM_LIB_TABLE::moveDownHandler( wxCommandEvent& event )
870{
871 m_cur_grid->OnMoveRowDown(
872 [&]( int row )
873 {
875 int curRow = m_cur_grid->GetGridCursorRow();
876 std::vector<LIBRARY_TABLE_ROW>& rows = tbl->Table().Rows();
877
878 auto current = rows.begin() + curRow;
879 auto next = rows.begin() + curRow + 1;
880
881 std::iter_swap( current, next );
882
883 // Update the wxGrid
884 wxGridTableMessage msg( cur_model(), wxGRIDTABLE_NOTIFY_ROWS_INSERTED, row, 0 );
885 cur_model()->GetView()->ProcessTableMessage( msg );
886 } );
887}
888
889
890void PANEL_SYM_LIB_TABLE::onReset( wxCommandEvent& event )
891{
892 if( !m_cur_grid->CommitPendingChanges() )
893 return;
894
895 // No need to prompt to preserve an empty table
896 if( m_global_grid->GetNumberRows() > 0 &&
897 !IsOK( this, wxString::Format( _( "This action will reset your global library table on "
898 "disk and cannot be undone." ) ) ) )
899 {
900 return;
901 }
902
904
905 // Go ahead and reload here because this action takes place even if the dialog is canceled
907
908 if( KIFACE *schface = m_parent->Kiway().KiFACE( KIWAY::FACE_SCH ) )
909 schface->PreloadLibraries( &m_parent->Kiway() );
910
911 m_global_grid->Freeze();
912
913 wxGridTableBase* table = m_global_grid->GetTable();
914 m_global_grid->DestroyTable( table );
915
916 std::optional<LIBRARY_TABLE*> newTable =
919 wxASSERT( newTable );
920
922
923 m_global_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *newTable.value(), adapter ) );
924 m_global_grid->PopEventHandler( true );
926 m_parent->m_GlobalTableChanged = true;
927
928 m_global_grid->Thaw();
929}
930
931
932void PANEL_SYM_LIB_TABLE::onPageChange( wxBookCtrlEvent& event )
933{
934 m_pageNdx = (unsigned) std::max( 0, m_notebook->GetSelection() );
935
936 if( m_pageNdx == 0 )
937 {
939 m_resetGlobal->Enable();
940 }
941 else
942 {
944 m_resetGlobal->Disable();
945 }
946}
947
948
950{
951 if( !m_cur_grid->CommitPendingChanges() )
952 return;
953
954 wxArrayInt selectedRows = m_cur_grid->GetSelectedRows();
955
956 if( selectedRows.empty() && m_cur_grid->GetGridCursorRow() >= 0 )
957 selectedRows.push_back( m_cur_grid->GetGridCursorRow() );
958
959 wxArrayInt legacyRows;
960 wxString databaseType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_DATABASE );
961 wxString kicadType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_KICAD );
962 wxString msg;
963
964 for( int row : selectedRows )
965 {
966 if( m_cur_grid->GetCellValue( row, COL_TYPE ) != databaseType &&
967 m_cur_grid->GetCellValue( row, COL_TYPE ) != kicadType )
968 {
969 legacyRows.push_back( row );
970 }
971 }
972
973 if( legacyRows.size() <= 0 )
974 {
975 wxMessageBox( _( "Select one or more rows containing libraries "
976 "to save as current KiCad format (*.kicad_sym)." ) );
977 return;
978 }
979 else
980 {
981 if( legacyRows.size() == 1 )
982 {
983 msg.Printf( _( "Save '%s' as current KiCad format (*.kicad_sym) "
984 "and replace legacy entry in table?" ),
985 m_cur_grid->GetCellValue( legacyRows[0], COL_NICKNAME ) );
986 }
987 else
988 {
989 msg.Printf( _( "Save %d libraries as current KiCad format (*.kicad_sym) "
990 "and replace legacy entries in table?" ),
991 (int) legacyRows.size() );
992 }
993
994 if( !IsOK( m_parent, msg ) )
995 return;
996 }
997
998 for( int row : legacyRows )
999 {
1000 wxString relPath = m_cur_grid->GetCellValue( row, COL_URI );
1001 wxString resolvedPath = ExpandEnvVarSubstitutions( relPath, m_project );
1002 wxFileName legacyLib( resolvedPath );
1003
1004 if( !legacyLib.Exists() )
1005 {
1006 msg.Printf( _( "Library '%s' not found." ), relPath );
1007
1008 wxWindow* topLevelParent = wxGetTopLevelParent( this );
1009
1010 DisplayErrorMessage( topLevelParent, msg );
1011 continue;
1012 }
1013
1014 wxFileName newLib( resolvedPath );
1015 newLib.SetExt( "kicad_sym" );
1016
1017 if( newLib.Exists() )
1018 {
1019 msg.Printf( _( "File '%s' already exists. Do you want overwrite this file?" ),
1020 newLib.GetFullPath() );
1021
1022 switch( wxMessageBox( msg, _( "Migrate Library" ),
1023 wxYES_NO | wxCANCEL | wxICON_QUESTION, m_parent ) )
1024 {
1025 case wxYES: break;
1026 case wxNO: continue;
1027 case wxCANCEL: return;
1028 }
1029 }
1030
1031 wxString options = m_cur_grid->GetCellValue( row, COL_OPTIONS );
1032 std::map<std::string, UTF8> props( LIB_TABLE::ParseOptions( options.ToStdString() ) );
1033
1034 if( SCH_IO_MGR::ConvertLibrary( &props, legacyLib.GetFullPath(), newLib.GetFullPath() ) )
1035 {
1036 relPath = NormalizePath( newLib.GetFullPath(), &Pgm().GetLocalEnvVariables(), m_project );
1037
1038 // Do not use the project path in the global library table. This will almost
1039 // assuredly be wrong for a different project.
1040 if( m_cur_grid == m_global_grid && relPath.Contains( "${KIPRJMOD}" ) )
1041 relPath = newLib.GetFullPath();
1042
1043 m_cur_grid->SetCellValue( row, COL_URI, relPath );
1044 m_cur_grid->SetCellValue( row, COL_TYPE, kicadType );
1045 m_cur_grid->SetCellValue( row, COL_OPTIONS, wxEmptyString );
1046 }
1047 else
1048 {
1049 msg.Printf( _( "Failed to save symbol library file '%s'." ), newLib.GetFullPath() );
1050
1051 wxWindow* topLevelParent = wxGetTopLevelParent( this );
1052
1053 DisplayErrorMessage( topLevelParent, msg );
1054 }
1055 }
1056}
1057
1058
1060{
1061 if( !m_cur_grid->CommitPendingChanges() )
1062 return false;
1063
1064 if( !verifyTables() )
1065 return false;
1066
1067 std::optional<LIBRARY_TABLE*> optTable =
1069 wxCHECK( optTable, false );
1070 LIBRARY_TABLE* globalTable = *optTable;
1071
1072 if( global_model()->Table() != *globalTable )
1073 {
1074 m_parent->m_GlobalTableChanged = true;
1075 *globalTable = global_model()->Table();
1076 }
1077
1080
1081 if( optTable && project_model() )
1082 {
1083 LIBRARY_TABLE* projectTable = *optTable;
1084
1085 if( project_model()->Table() != *projectTable )
1086 {
1087 m_parent->m_ProjectTableChanged = true;
1088 *projectTable = project_model()->Table();
1089 }
1090 }
1091
1092 return true;
1093}
1094
1095
1097{
1098 wxRegEx re( ".*?(\\$\\{(.+?)\\})|(\\$\\((.+?)\\)).*?", wxRE_ADVANCED );
1099 wxASSERT( re.IsValid() ); // wxRE_ADVANCED is required.
1100
1101 std::set< wxString > unique;
1102
1103 // clear the table
1104 m_path_subs_grid->ClearRows();
1105
1106 for( SYMBOL_LIB_TABLE_GRID* tbl : { global_model(), project_model() } )
1107 {
1108 if( !tbl )
1109 continue;
1110
1111 for( int row = 0; row < tbl->GetNumberRows(); ++row )
1112 {
1113 wxString uri = tbl->GetValue( row, COL_URI );
1114
1115 while( re.Matches( uri ) )
1116 {
1117 wxString envvar = re.GetMatch( uri, 2 );
1118
1119 // if not ${...} form then must be $(...)
1120 if( envvar.IsEmpty() )
1121 envvar = re.GetMatch( uri, 4 );
1122
1123 // ignore duplicates
1124 unique.insert( envvar );
1125
1126 // delete the last match and search again
1127 uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString );
1128 }
1129 }
1130 }
1131
1132 // Make sure this special environment variable shows up even if it was
1133 // not used yet. It is automatically set by KiCad to the directory holding
1134 // the current project.
1135 unique.insert( PROJECT_VAR_NAME );
1136 unique.insert( ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) ) );
1137
1138 for( const wxString& evName : unique )
1139 {
1140 int row = m_path_subs_grid->GetNumberRows();
1141 m_path_subs_grid->AppendRows( 1 );
1142
1143 m_path_subs_grid->SetCellValue( row, 0, wxT( "${" ) + evName + wxT( "}" ) );
1144 m_path_subs_grid->SetCellEditor( row, 0, new GRID_CELL_READONLY_TEXT_EDITOR() );
1145
1146 wxString evValue;
1147 wxGetEnv( evName, &evValue );
1148 m_path_subs_grid->SetCellValue( row, 1, evValue );
1149 m_path_subs_grid->SetCellEditor( row, 1, new GRID_CELL_READONLY_TEXT_EDITOR() );
1150 }
1151
1152 adjustPathSubsGridColumns( m_path_subs_grid->GetRect().GetWidth() );
1153}
1154
1155
1157{
1158 // Account for scroll bars
1159 aWidth -= ( m_path_subs_grid->GetSize().x - m_path_subs_grid->GetClientSize().x );
1160
1161 m_path_subs_grid->AutoSizeColumn( 0 );
1162 m_path_subs_grid->SetColSize( 0, std::max( 72, m_path_subs_grid->GetColSize( 0 ) ) );
1163 m_path_subs_grid->SetColSize( 1, std::max( 120, aWidth - m_path_subs_grid->GetColSize( 0 ) ) );
1164}
1165
1166
1167void PANEL_SYM_LIB_TABLE::onSizeGrid( wxSizeEvent& event )
1168{
1169 adjustPathSubsGridColumns( event.GetSize().GetX() );
1170
1171 event.Skip();
1172}
1173
1174
1176{
1177 return static_cast<SYMBOL_LIB_TABLE_GRID*>( m_global_grid->GetTable() );
1178}
1179
1180
1182{
1183 return m_project_grid ? static_cast<SYMBOL_LIB_TABLE_GRID*>( m_project_grid->GetTable() ) : nullptr;
1184}
1185
1186
1188{
1189 return static_cast<SYMBOL_LIB_TABLE_GRID*>( m_cur_grid->GetTable() );
1190}
1191
1192
1194
1195
1196void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
1197{
1198 auto symbolEditor = static_cast<SYMBOL_EDIT_FRAME*>( aKiway->Player( FRAME_SCH_SYMBOL_EDITOR,
1199 false ) );
1200 wxString msg;
1201
1202 if( symbolEditor )
1203 {
1204 // This prevents an ugly crash on OSX (https://bugs.launchpad.net/kicad/+bug/1765286)
1205 symbolEditor->FreezeLibraryTree();
1206
1207 if( symbolEditor->HasLibModifications() )
1208 {
1209 msg = _( "Modifications have been made to one or more symbol libraries.\n"
1210 "Changes must be saved or discarded before the symbol library table can be modified." );
1211
1212 switch( UnsavedChangesDialog( aParent, msg ) )
1213 {
1214 case wxID_YES: symbolEditor->SaveAll(); break;
1215 case wxID_NO: symbolEditor->RevertAll(); break;
1216 default:
1217 case wxID_CANCEL: symbolEditor->ThawLibraryTree(); return;
1218 }
1219 }
1220 }
1221
1222 DIALOG_EDIT_LIBRARY_TABLES dlg( aParent, _( "Symbol Libraries" ) );
1223 dlg.SetKiway( &dlg, aKiway );
1224
1225 dlg.InstallPanel( new PANEL_SYM_LIB_TABLE( &dlg, &aKiway->Prj() ) );
1226
1227 if( dlg.ShowModal() == wxID_CANCEL )
1228 {
1229 if( symbolEditor )
1230 symbolEditor->ThawLibraryTree();
1231
1232 return;
1233 }
1234
1235 if( dlg.m_GlobalTableChanged )
1236 {
1237 std::optional<LIBRARY_TABLE*> optTable =
1239 wxCHECK( optTable, /* void */ );
1240 LIBRARY_TABLE* globalTable = *optTable;
1241
1242 globalTable->Save().map_error(
1243 []( const LIBRARY_ERROR& aError )
1244 {
1245 wxMessageBox( wxString::Format( _( "Error saving global library table:\n\n%s" ), aError.message ),
1246 _( "File Save Error" ), wxOK | wxICON_ERROR );
1247 } );
1248
1250 }
1251
1252 std::optional<LIBRARY_TABLE*> projectTable =
1254
1255 if( projectTable && dlg.m_ProjectTableChanged )
1256 {
1257 ( *projectTable )->Save().map_error(
1258 []( const LIBRARY_ERROR& aError )
1259 {
1260 wxMessageBox( wxString::Format( _( "Error saving project-specific library table:\n\n%s" ),
1261 aError.message ),
1262 _( "File Save Error" ), wxOK | wxICON_ERROR );
1263 } );
1264
1265 // Trigger a reload of the table and cancel an in-progress background load
1267 }
1268
1269 // Trigger a reload in case any libraries have been added or removed
1270 if( KIFACE *schface = aKiway->KiFACE( KIWAY::FACE_SCH ) )
1271 schface->PreloadLibraries( aKiway );
1272
1273 if( symbolEditor )
1274 symbolEditor->ThawLibraryTree();
1275}
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.
int ShowModal() override
Editor for wxGrid cells that adds a file/folder browser to the grid input field.
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:61
virtual void paste_text(const wxString &cb_text)
void getSelectedArea()
Puts the selected area into a sensible rectangle of m_sel_{row,col}_{start,count} above.
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
virtual void onGridCellLeftClick(wxGridEvent &event)
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 & ErrorDescription() const
const wxString & Type() const
static const wxString TABLE_TYPE_NAME
bool IsOk() const
const wxString & URI() const
const wxString & Nickname() const
const wxString & Options() const
LIBRARY_RESULT< void > Save()
LIBRARY_TABLE_SCOPE Scope() const
bool IsOk() const
const std::vector< LIBRARY_TABLE_ROW > & Rows() const
static unsigned FindIllegalLibraryNameChar(const UTF8 &aLibraryName)
Looks for characters that are illegal in library nicknames.
Definition lib_id.cpp:241
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition lib_id.cpp:192
LIB_TABLE_GRID_TRICKS(WX_GRID *aGrid)
LIBRARY_TABLE & Table()
LIB_TABLE_GRID(const LIBRARY_TABLE &aTableToEdit, LIBRARY_MANAGER_ADAPTER *aAdapter=nullptr)
void SetValue(int aRow, int aCol, const wxString &aValue) override
virtual size_t size() const
virtual LIBRARY_TABLE_ROW & at(size_t aIndex)
static std::map< std::string, UTF8 > ParseOptions(const std::string &aOptionsList)
Parses aOptionsList and places the result into a #PROPERTIES object which is returned.
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 OnUpdateUI(wxUpdateUIEvent &event) override
void moveUpHandler(wxCommandEvent &event) override
void onPageChange(wxBookCtrlEvent &event) override
bool allowAutomaticPluginTypeSelection(wxString &aLibraryPath)
static size_t m_pageNdx
Remember the last notebook page selected.
void setupGrid(WX_GRID *aGrid)
void onReset(wxCommandEvent &event) override
void deleteRowHandler(wxCommandEvent &event) override
wxString m_lastProjectLibDir
Transient (unsaved) last browsed folder when adding a project level library.
void browseLibrariesHandler(wxCommandEvent &event) override
SYMBOL_LIB_TABLE_GRID * cur_model() const
bool verifyTables()
Trim important fields, removes blank row entries, and checks for duplicates.
void adjustPathSubsGridColumns(int aWidth)
SYMBOL_LIB_TABLE_GRID * global_model() const
void onSizeGrid(wxSizeEvent &event) override
void onConvertLegacyLibraries(wxCommandEvent &event) override
SYMBOL_LIB_TABLE_GRID * project_model() const
wxArrayString m_pluginChoices
void moveDownHandler(wxCommandEvent &event) override
PANEL_SYM_LIB_TABLE(DIALOG_EDIT_LIBRARY_TABLES *aParent, PROJECT *m_project)
void populateEnvironReadOnlyTable()
Populate the readonly environment variable table with names and values by examining all the full_uri ...
WX_GRID * m_cur_grid
changed based on tab choice
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:130
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Container for project specific data.
Definition project.h:66
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.
bool supportsVisibilityColumn() override
void onGridCellLeftClick(wxGridEvent &aEvent) override
void paste_text(const wxString &cb_text) override
handle specialized clipboard text, with leading "(sym_lib_table" or spreadsheet formatted text.
DIALOG_EDIT_LIBRARY_TABLES * m_dialog
SYMBOL_GRID_TRICKS(DIALOG_EDIT_LIBRARY_TABLES *aParent, WX_GRID *aGrid, PROJECT &aProject, std::function< void(wxCommandEvent &)> aAddHandler)
void optionsEditor(int aRow) override
SYMBOL_GRID_TRICKS(DIALOG_EDIT_LIBRARY_TABLES *aParent, WX_GRID *aGrid, PROJECT &aProject)
An interface to the global shared library manager that is schematic-specific and linked to one projec...
bool SupportsConfigurationDialog(const wxString &aNickname) const override
void ShowConfigurationDialog(const wxString &aNickname, wxWindow *aParent) const override
std::optional< LIBRARY_ERROR > LibraryError(const wxString &aNickname) const
SYMBOL_LIB_TABLE_GRID(const LIBRARY_TABLE &aTableToEdit, SYMBOL_LIBRARY_ADAPTER *aAdapter)
void SetValue(int aRow, int aCol, const wxString &aValue) 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
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
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
static const std::string LegacySymbolLibFileExtension
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:623
@ COL_DESCR
@ COL_NICKNAME
@ COL_OPTIONS
@ COL_STATUS
@ COL_ENABLED
@ COL_URI
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
CITER next(CITER it)
Definition ptree.cpp:124
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
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.