KiCad PCB EDA Suite
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 (C) 2017-2022 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 <common.h> // For ExpandEnvVarSubstitutions
26#include <project.h>
27#include <panel_sym_lib_table.h>
28#include <lib_id.h>
29#include <symbol_lib_table.h>
30#include <lib_table_lexer.h>
32#include <widgets/wx_grid.h>
33#include <confirm.h>
34#include <bitmaps.h>
35#include <lib_table_grid.h>
37#include <env_paths.h>
38#include <eeschema_id.h>
39#include <symbol_edit_frame.h>
40#include <symbol_viewer_frame.h>
41#include <sch_edit_frame.h>
42#include <kiway.h>
43#include <paths.h>
44#include <pgm_base.h>
48#include <sch_file_versions.h>
49#include <wx/filedlg.h>
50
51
52
53// clang-format off
54
59{
60 wxString m_Description;
61 wxString m_FileFilter;
63 bool m_IsFile;
64 SCH_IO_MGR::SCH_FILE_T m_Plugin;
65};
66
67
71enum {
74};
75
76
81{
82 friend class SYMBOL_GRID_TRICKS;
83
84protected:
85 LIB_TABLE_ROW* at( size_t aIndex ) override { return &rows.at( aIndex ); }
86
87 size_t size() const override { return rows.size(); }
88
90 {
91 return dynamic_cast< LIB_TABLE_ROW* >( new SYMBOL_LIB_TABLE_ROW );
92 }
93
94 LIB_TABLE_ROWS_ITER begin() override { return rows.begin(); }
95
97 {
98 return rows.insert( aIterator, aRow );
99 }
100
101 void push_back( LIB_TABLE_ROW* aRow ) override { rows.push_back( aRow ); }
102
104 {
105 return rows.erase( aFirst, aLast );
106 }
107
108public:
109 void SetValue( int aRow, int aCol, const wxString &aValue ) override
110 {
111 LIB_TABLE_GRID::SetValue( aRow, aCol, aValue );
112
113 // If setting a filepath, attempt to auto-detect the format
114 if( aCol == COL_URI )
115 {
116 wxFileName fn( aValue );
117
118 for( SCH_IO_MGR::SCH_FILE_T piType : SCH_IO_MGR::SCH_FILE_T_vector )
119 {
120 if( SCH_IO_MGR::GetLibraryFileExtension( piType ).Lower() == fn.GetExt().Lower() )
121 {
122 SetValue( aRow, COL_TYPE, SCH_IO_MGR::ShowType( piType ) );
123 break;
124 }
125 }
126 }
127 }
128
129
131 {
132 rows = aTableToEdit.rows;
133 }
134};
135
137{
138public:
140 LIB_TABLE_GRID_TRICKS( aGrid ),
141 m_dialog( aParent )
142 {
143 }
144
145protected:
147
150 virtual void paste_text( const wxString& cb_text ) override
151 {
153 size_t ndx = cb_text.find( "(sym_lib_table" );
154
155 if( ndx != std::string::npos )
156 {
157 // paste the SYMBOL_LIB_TABLE_ROWs of s-expression (sym_lib_table), starting
158 // at column 0 regardless of current cursor column.
159
160 STRING_LINE_READER slr( TO_UTF8( cb_text ), "Clipboard" );
161 LIB_TABLE_LEXER lexer( &slr );
162 SYMBOL_LIB_TABLE tmp_tbl;
163 bool parsed = true;
164
165 try
166 {
167 tmp_tbl.Parse( &lexer );
168 }
169 catch( PARSE_ERROR& pe )
170 {
171 DisplayError( m_dialog, pe.What() );
172 parsed = false;
173 }
174
175 if( parsed )
176 {
177 // make sure the table is big enough...
178 if( tmp_tbl.GetCount() > (unsigned) tbl->GetNumberRows() )
179 tbl->AppendRows( tmp_tbl.GetCount() - tbl->GetNumberRows() );
180
181 for( unsigned i = 0; i < tmp_tbl.GetCount(); ++i )
182 tbl->rows.replace( i, tmp_tbl.At( i ).clone() );
183 }
184
185 m_grid->AutoSizeColumns( false );
186 }
187 else
188 {
189 // paste spreadsheet formatted text.
190 GRID_TRICKS::paste_text( cb_text );
191
192 m_grid->AutoSizeColumns( false );
193 }
194 }
195};
196
197
199 SYMBOL_LIB_TABLE* aGlobalTable,
200 const wxString& aGlobalTablePath,
201 SYMBOL_LIB_TABLE* aProjectTable,
202 const wxString& aProjectTablePath ) :
203 PANEL_SYM_LIB_TABLE_BASE( aParent ),
204 m_globalTable( aGlobalTable ),
205 m_projectTable( aProjectTable ),
206 m_project( aProject ),
207 m_parent( aParent )
208{
209 // wxGrid only supports user owned tables if they exist past end of ~wxGrid(),
210 // so make it a grid owned table.
212
213 wxArrayString pluginChoices;
214
215 pluginChoices.Add( SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_KICAD ) );
216 pluginChoices.Add( SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY ) );
217 pluginChoices.Add( SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_DATABASE ) );
218
219 EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>();
220
221 if( cfg->m_lastSymbolLibDir.IsEmpty() )
223
225
226 auto setupGrid =
227 [&]( WX_GRID* aGrid )
228 {
229 // Give a bit more room for combobox editors
230 aGrid->SetDefaultRowSize( aGrid->GetDefaultRowSize() + 4 );
231
232 // add Cut, Copy, and Paste to wxGrids
233 aGrid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, aGrid ) );
234
235 aGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
236 aGrid->AutoSizeColumns( false );
237
238 // Set special attributes
239 wxGridCellAttr* attr;
240
241 attr = new wxGridCellAttr;
242
243 wxString wildcards = AllSymbolLibFilesWildcard()
246 attr->SetEditor( new GRID_CELL_PATH_EDITOR( m_parent, aGrid,
247 &cfg->m_lastSymbolLibDir, wildcards,
248 true, m_project->GetProjectPath() ) );
249 aGrid->SetColAttr( COL_URI, attr );
250
251 attr = new wxGridCellAttr;
252 attr->SetEditor( new wxGridCellChoiceEditor( pluginChoices ) );
253 aGrid->SetColAttr( COL_TYPE, attr );
254
255 attr = new wxGridCellAttr;
256 attr->SetRenderer( new wxGridCellBoolRenderer() );
257 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
258 aGrid->SetColAttr( COL_ENABLED, attr );
259
260 attr = new wxGridCellAttr;
261 attr->SetRenderer( new wxGridCellBoolRenderer() );
262 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
263 aGrid->SetColAttr( COL_VISIBLE, attr );
264
265 // all but COL_OPTIONS, which is edited with Option Editor anyways.
266 aGrid->AutoSizeColumn( COL_NICKNAME, false );
267 aGrid->AutoSizeColumn( COL_TYPE, false );
268 aGrid->AutoSizeColumn( COL_URI, false );
269 aGrid->AutoSizeColumn( COL_DESCR, false );
270 aGrid->AutoSizeColumn( COL_ENABLED, false );
271
272 // would set this to width of title, if it was easily known.
273 aGrid->SetColSize( COL_OPTIONS, 80 );
274
275 // Gives a selection to each grid, mainly for delete button. wxGrid's wake up with
276 // a currentCell which is sometimes not highlighted.
277 if( aGrid->GetNumberRows() > 0 )
278 aGrid->SelectRow( 0 );
279 };
280
281 setupGrid( m_global_grid );
282
283 if( m_projectTable )
284 {
286 setupGrid( m_project_grid );
287 }
288 else
289 {
290 m_pageNdx = 0;
291 m_notebook->DeletePage( 1 );
292 m_project_grid = nullptr;
293 }
294
295 // add Cut, Copy, and Paste to wxGrids
296 m_path_subs_grid->PushEventHandler( new GRID_TRICKS( m_path_subs_grid ) );
297
299
300 // select the last selected page
301 m_notebook->SetSelection( m_pageNdx );
303
304 m_path_subs_grid->SetColLabelValue( 0, _( "Name" ) );
305 m_path_subs_grid->SetColLabelValue( 1, _( "Value" ) );
306
307 // for ALT+A handling, we want the initial focus to be on the first selected grid.
309
310 // Configure button logos
316}
317
318
320{
321 // Delete the GRID_TRICKS.
322 // Any additional event handlers should be popped before the window is deleted.
323 m_global_grid->PopEventHandler( true );
324
325 if( m_project_grid )
326 m_project_grid->PopEventHandler( true );
327
328 m_path_subs_grid->PopEventHandler( true );
329}
330
331
333{
334 wxString msg;
335
336 for( SYMBOL_LIB_TABLE_GRID* model : { global_model(), project_model() } )
337 {
338 if( !model )
339 continue;
340
341 for( int r = 0; r < model->GetNumberRows(); )
342 {
343 wxString nick = model->GetValue( r, COL_NICKNAME ).Trim( false ).Trim();
344 wxString uri = model->GetValue( r, COL_URI ).Trim( false ).Trim();
345 unsigned illegalCh = 0;
346
347 if( !nick || !uri )
348 {
349 if( !nick && !uri )
350 msg = _( "A library table row nickname and path cells are empty." );
351 else if( !nick )
352 msg = _( "A library table row nickname cell is empty." );
353 else
354 msg = _( "A library table row path cell is empty." );
355
356 wxMessageDialog badCellDlg( this, msg, _( "Invalid Row Definition" ),
357 wxYES_NO | wxCENTER | wxICON_QUESTION | wxYES_DEFAULT );
358 badCellDlg.SetExtendedMessage( _( "Empty cells will result in all rows that are "
359 "invalid to be removed from the table." ) );
360 badCellDlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Remove Invalid Cells" ) ),
361 wxMessageDialog::ButtonLabel( _( "Cancel Table Update" ) ) );
362
363 if( badCellDlg.ShowModal() == wxID_NO )
364 return false;
365
366 // Delete the "empty" row, where empty means missing nick or uri.
367 // This also updates the UI which could be slow, but there should only be a few
368 // rows to delete, unless the user fell asleep on the Add Row
369 // button.
370 model->DeleteRows( r, 1 );
371 }
372 else if( ( illegalCh = LIB_ID::FindIllegalLibraryNameChar( nick ) ) )
373 {
374 msg = wxString::Format( _( "Illegal character '%c' in nickname '%s'" ),
375 illegalCh,
376 nick );
377
378 // show the tabbed panel holding the grid we have flunked:
379 if( model != cur_model() )
380 m_notebook->SetSelection( model == global_model() ? 0 : 1 );
381
382 m_cur_grid->MakeCellVisible( r, 0 );
383 m_cur_grid->SetGridCursor( r, 1 );
384
385 wxMessageDialog errdlg( this, msg, _( "Library Nickname Error" ) );
386 errdlg.ShowModal();
387 return false;
388 }
389 else
390 {
391 // set the trimmed values back into the table so they get saved to disk.
392 model->SetValue( r, COL_NICKNAME, nick );
393 model->SetValue( r, COL_URI, uri );
394 ++r; // this row was OK.
395 }
396 }
397 }
398
399 // check for duplicate nickNames, separately in each table.
400 for( SYMBOL_LIB_TABLE_GRID* model : { global_model(), project_model() } )
401 {
402 if( !model )
403 continue;
404
405 for( int r1 = 0; r1 < model->GetNumberRows() - 1; ++r1 )
406 {
407 wxString nick1 = model->GetValue( r1, COL_NICKNAME );
408
409 for( int r2=r1+1; r2 < model->GetNumberRows(); ++r2 )
410 {
411 wxString nick2 = model->GetValue( r2, COL_NICKNAME );
412
413 if( nick1 == nick2 )
414 {
415 msg = wxString::Format( _( "Multiple libraries cannot share the same "
416 "nickname ('%s')." ), nick1 );
417
418 // show the tabbed panel holding the grid we have flunked:
419 if( model != cur_model() )
420 m_notebook->SetSelection( model == global_model() ? 0 : 1 );
421
422 // go to the lower of the two rows, it is technically the duplicate:
423 m_cur_grid->MakeCellVisible( r2, 0 );
424 m_cur_grid->SetGridCursor( r2, 1 );
425
426 wxMessageDialog errdlg( this, msg, _( "Library Nickname Error" ) );
427 errdlg.ShowModal();
428
429 return false;
430 }
431 }
432 }
433 }
434
435 for( SYMBOL_LIB_TABLE* table : { global_model(), project_model() } )
436 {
437 if( !table )
438 continue;
439
440 for( unsigned int r = 0; r < table->GetCount(); ++r )
441 {
442 SYMBOL_LIB_TABLE_ROW& row = dynamic_cast<SYMBOL_LIB_TABLE_ROW&>( table->At( r ) );
443
444 if( !row.GetParent() )
445 row.SetParent( table );
446
447 if( !row.GetIsEnabled() )
448 continue;
449
450 try
451 {
452 if( row.Refresh() )
453 {
454 if( table == global_model() )
456 else
458 }
459 }
460 catch( const IO_ERROR& ioe )
461 {
462 msg.Printf( _( "Symbol library '%s' failed to load." ), row.GetNickName() );
463
464 wxMessageDialog errdlg( this, msg + wxS( "\n" ) + ioe.What(),
465 _( "Error Loading Library" ) );
466 errdlg.ShowModal();
467
468 return true;
469 }
470 }
471 }
472
473 return true;
474}
475
476
477void PANEL_SYM_LIB_TABLE::OnUpdateUI( wxUpdateUIEvent& event )
478{
479 m_pageNdx = (unsigned) std::max( 0, m_notebook->GetSelection() );
481}
482
483
485{
486 wxString wildcards = AllSymbolLibFilesWildcard()
489 + "|" + DatabaseLibFileWildcard();
490
491 EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>();
492
493 wxString openDir = cfg->m_lastSymbolLibDir;
494
496 openDir = m_lastProjectLibDir;
497
498 wxFileDialog dlg( this, _( "Select Library" ), openDir, wxEmptyString, wildcards,
499 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE );
500
501 if( dlg.ShowModal() == wxID_CANCEL )
502 return;
503
505 cfg->m_lastSymbolLibDir = dlg.GetDirectory();
506 else
507 m_lastProjectLibDir = dlg.GetDirectory();
508
509 const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
510 bool addDuplicates = false;
511 bool applyToAll = false;
512 wxString warning = _( "Warning: Duplicate Nickname" );
513 wxString msg = _( "A library nicknamed '%s' already exists." );
514 wxString detailedMsg = _( "One of the nicknames will need to be changed after "
515 "adding this library." );
516
517 wxArrayString filePathsList;
518 dlg.GetPaths( filePathsList );
519
520 for( const wxString& filePath : filePathsList )
521 {
522 wxFileName fn( filePath );
523 wxString nickname = LIB_ID::FixIllegalChars( fn.GetName(), true );
524 bool doAdd = true;
525
526 if( cur_model()->ContainsNickname( nickname ) )
527 {
528 if( !applyToAll )
529 {
530 // The cancel button adds the library to the table anyway
531 addDuplicates = OKOrCancelDialog( this, warning, wxString::Format( msg, nickname ),
532 detailedMsg, _( "Skip" ), _( "Add Anyway" ),
533 &applyToAll ) == wxID_CANCEL;
534 }
535
536 doAdd = addDuplicates;
537 }
538
539 if( doAdd && m_cur_grid->AppendRows( 1 ) )
540 {
541 int last_row = m_cur_grid->GetNumberRows() - 1;
542
543 m_cur_grid->SetCellValue( last_row, COL_NICKNAME, nickname );
544
545 // attempt to auto-detect the plugin type
546 for( SCH_IO_MGR::SCH_FILE_T piType : SCH_IO_MGR::SCH_FILE_T_vector )
547 {
548 if( SCH_IO_MGR::GetLibraryFileExtension( piType ).Lower() == fn.GetExt().Lower() )
549 {
550 m_cur_grid->SetCellValue( last_row, COL_TYPE, SCH_IO_MGR::ShowType( piType ) );
551 break;
552 }
553 }
554
555 // try to use path normalized to an environmental variable or project path
556 wxString path = NormalizePath( filePath, &envVars, m_project->GetProjectPath() );
557
558 // Do not use the project path in the global library table. This will almost
559 // assuredly be wrong for a different project.
560 if( m_pageNdx == 0 && path.Contains( "${KIPRJMOD}" ) )
561 path = fn.GetFullPath();
562
563 m_cur_grid->SetCellValue( last_row, COL_URI, path );
564 }
565 }
566
567 if( !filePathsList.IsEmpty() )
568 {
569 m_cur_grid->MakeCellVisible( m_cur_grid->GetNumberRows() - 1, 0 );
570 m_cur_grid->SetGridCursor( m_cur_grid->GetNumberRows() - 1, 1 );
571 }
572}
573
574
575void PANEL_SYM_LIB_TABLE::appendRowHandler( wxCommandEvent& event )
576{
578 return;
579
580 if( m_cur_grid->AppendRows( 1 ) )
581 {
582 int row = m_cur_grid->GetNumberRows() - 1;
583
584 // wx documentation is wrong, SetGridCursor does not make visible.
585 m_cur_grid->MakeCellVisible( row, 0 );
586 m_cur_grid->SetGridCursor( row, 1 );
587 m_cur_grid->EnableCellEditControl( true );
588 m_cur_grid->ShowCellEditControl();
589 }
590}
591
592
593void PANEL_SYM_LIB_TABLE::deleteRowHandler( wxCommandEvent& event )
594{
596 return;
597
598 int curRow = m_cur_grid->GetGridCursorRow();
599 int curCol = m_cur_grid->GetGridCursorCol();
600
601 // In a wxGrid, collect rows that have a selected cell, or are selected
602 // It is not so easy: it depends on the way the selection was made.
603 // Here, we collect rows selected by clicking on a row label, and rows that contain
604 // previously-selected cells.
605 // If no candidate, just delete the row with the grid cursor.
606 wxArrayInt selectedRows = m_cur_grid->GetSelectedRows();
607 wxGridCellCoordsArray cells = m_cur_grid->GetSelectedCells();
608 wxGridCellCoordsArray blockTopLeft = m_cur_grid->GetSelectionBlockTopLeft();
609 wxGridCellCoordsArray blockBotRight = m_cur_grid->GetSelectionBlockBottomRight();
610
611 // Add all row having cell selected to list:
612 for( unsigned ii = 0; ii < cells.GetCount(); ii++ )
613 selectedRows.Add( cells[ii].GetRow() );
614
615 // Handle block selection
616 if( !blockTopLeft.IsEmpty() && !blockBotRight.IsEmpty() )
617 {
618 for( int i = blockTopLeft[0].GetRow(); i <= blockBotRight[0].GetRow(); ++i )
619 selectedRows.Add( i );
620 }
621
622 // Use the row having the grid cursor only if we have no candidate:
623 if( selectedRows.size() == 0 && m_cur_grid->GetGridCursorRow() >= 0 )
624 selectedRows.Add( m_cur_grid->GetGridCursorRow() );
625
626 if( selectedRows.size() == 0 )
627 {
628 wxBell();
629 return;
630 }
631
632 std::sort( selectedRows.begin(), selectedRows.end() );
633
634 // Remove selected rows (note: a row can be stored more than once in list)
635 int last_row = -1;
636
637 for( int ii = selectedRows.GetCount()-1; ii >= 0; ii-- )
638 {
639 int row = selectedRows[ii];
640
641 if( row != last_row )
642 {
643 last_row = row;
644 m_cur_grid->DeleteRows( row, 1 );
645 }
646 }
647
648 if( m_cur_grid->GetNumberRows() > 0 && curRow >= 0 )
649 m_cur_grid->SetGridCursor( std::min( curRow, m_cur_grid->GetNumberRows() - 1 ), curCol );
650}
651
652
653void PANEL_SYM_LIB_TABLE::moveUpHandler( wxCommandEvent& event )
654{
656 return;
657
659 int curRow = m_cur_grid->GetGridCursorRow();
660
661 // @todo: add multiple selection moves.
662 if( curRow >= 1 )
663 {
664 boost::ptr_vector< LIB_TABLE_ROW >::auto_type move_me =
665 tbl->rows.release( tbl->rows.begin() + curRow );
666
667 --curRow;
668 tbl->rows.insert( tbl->rows.begin() + curRow, move_me.release() );
669
670 if( tbl->GetView() )
671 {
672 // Update the wxGrid
673 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, curRow, 0 );
674 tbl->GetView()->ProcessTableMessage( msg );
675 }
676
677 m_cur_grid->MakeCellVisible( curRow, m_cur_grid->GetGridCursorCol() );
678 m_cur_grid->SetGridCursor( curRow, m_cur_grid->GetGridCursorCol() );
679 }
680}
681
682
683void PANEL_SYM_LIB_TABLE::moveDownHandler( wxCommandEvent& event )
684{
686 return;
687
689 int curRow = m_cur_grid->GetGridCursorRow();
690
691 // @todo: add multiple selection moves.
692 if( unsigned( curRow + 1 ) < tbl->rows.size() )
693 {
694 boost::ptr_vector< LIB_TABLE_ROW >::auto_type move_me =
695 tbl->rows.release( tbl->rows.begin() + curRow );
696
697 ++curRow;
698 tbl->rows.insert( tbl->rows.begin() + curRow, move_me.release() );
699
700 if( tbl->GetView() )
701 {
702 // Update the wxGrid
703 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, curRow - 1, 0 );
704 tbl->GetView()->ProcessTableMessage( msg );
705 }
706
707 m_cur_grid->MakeCellVisible( curRow, m_cur_grid->GetGridCursorCol() );
708 m_cur_grid->SetGridCursor( curRow, m_cur_grid->GetGridCursorCol() );
709 }
710}
711
712
714{
716 return;
717
718 wxArrayInt selectedRows = m_cur_grid->GetSelectedRows();
719
720 if( selectedRows.empty() && m_cur_grid->GetGridCursorRow() >= 0 )
721 selectedRows.push_back( m_cur_grid->GetGridCursorRow() );
722
723 wxArrayInt legacyRows;
724 wxString legacyType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY );
725 wxString kicadType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_KICAD );
726 wxString msg;
727
728 for( int row : selectedRows )
729 {
730 if( m_cur_grid->GetCellValue( row, COL_TYPE ) == legacyType )
731 legacyRows.push_back( row );
732 }
733
734 if( legacyRows.size() <= 0 )
735 {
736 wxMessageBox( _( "Select one or more rows containing libraries in Legacy format (*.lib) "
737 "to save as current KiCad format (*.kicad_sym)." ) );
738 return;
739 }
740 else
741 {
742 if( legacyRows.size() == 1 )
743 {
744 msg.Printf( _( "Save '%s' as current KiCad format (*.kicad_sym) "
745 "and replace legacy entry in table?" ),
746 m_cur_grid->GetCellValue( legacyRows[0], COL_NICKNAME ) );
747 }
748 else
749 {
750 msg.Printf( _( "Save %d Legacy format libraries as current KiCad format (*.kicad_sym) "
751 "and replace legacy entries in table?" ),
752 (int) legacyRows.size() );
753 }
754
755 if( !IsOK( m_parent, msg ) )
756 return;
757 }
758
759 for( int row : legacyRows )
760 {
761 wxString libName = m_cur_grid->GetCellValue( row, COL_NICKNAME );
762 wxString relPath = m_cur_grid->GetCellValue( row, COL_URI );
763 wxString resolvedPath = ExpandEnvVarSubstitutions( relPath, m_project );
764 wxFileName legacyLib( resolvedPath );
765
766 if( !legacyLib.Exists() )
767 {
768 msg.Printf( _( "Library '%s' not found." ), relPath );
769 DisplayErrorMessage( this, msg );
770 continue;
771 }
772
773 wxFileName newLib( resolvedPath );
774 newLib.SetExt( "kicad_sym" );
775
776 if( newLib.Exists() )
777 {
778 msg.Printf( _( "File '%s' already exists. Do you want overwrite this file?" ),
779 newLib.GetFullPath() );
780
781 switch( wxMessageBox( msg, _( "Migrate Library" ),
782 wxYES_NO | wxCANCEL | wxICON_QUESTION, m_parent ) )
783 {
784 case wxYES: break;
785 case wxNO: continue;
786 case wxCANCEL: return;
787 }
788 }
789
790 if( convertLibrary( libName, legacyLib.GetFullPath(), newLib.GetFullPath() ) )
791 {
792 relPath = NormalizePath( newLib.GetFullPath(), &Pgm().GetLocalEnvVariables(),
793 m_project );
794
795 // Do not use the project path in the global library table. This will almost
796 // assuredly be wrong for a different project.
797 if( m_cur_grid == m_global_grid && relPath.Contains( "${KIPRJMOD}" ) )
798 relPath = newLib.GetFullPath();
799
800 m_cur_grid->SetCellValue( row, COL_URI, relPath );
801 m_cur_grid->SetCellValue( row, COL_TYPE, kicadType );
802 }
803 else
804 {
805 msg.Printf( _( "Failed to save symbol library file '%s'." ), newLib.GetFullPath() );
806 DisplayErrorMessage( this, msg );
807 }
808 }
809}
810
811
812bool PANEL_SYM_LIB_TABLE::convertLibrary( const wxString& aLibrary, const wxString& legacyFilepath,
813 const wxString& newFilepath )
814{
815 SCH_PLUGIN::SCH_PLUGIN_RELEASER legacyPI( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
816 SCH_PLUGIN::SCH_PLUGIN_RELEASER kicadPI( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
817 std::vector<LIB_SYMBOL*> symbols;
818 std::vector<LIB_SYMBOL*> newSymbols;
819 std::map<LIB_SYMBOL*, LIB_SYMBOL*> symbolMap;
820
821 try
822 {
823 // Write a stub file; SaveSymbol() expects something to be there already.
824 FILE_OUTPUTFORMATTER* formatter = new FILE_OUTPUTFORMATTER( newFilepath );
825
826 formatter->Print( 0, "(kicad_symbol_lib (version %d) (generator kicad_converter))",
828
829 // This will write the file
830 delete formatter;
831
832 legacyPI->EnumerateSymbolLib( symbols, legacyFilepath );
833
834 // Copy non-aliases first so we can build a map from symbols to newSymbols
835 for( LIB_SYMBOL* symbol : symbols )
836 {
837 if( symbol->IsAlias() )
838 continue;
839
840 symbol->SetName( EscapeString( symbol->GetName(), CTX_LIBID ) );
841
842 newSymbols.push_back( new LIB_SYMBOL( *symbol ) );
843 symbolMap[symbol] = newSymbols.back();
844 }
845
846 // Now do the aliases using the map to hook them up to their newSymbol parents
847 for( LIB_SYMBOL* symbol : symbols )
848 {
849 if( !symbol->IsAlias() )
850 continue;
851
852 symbol->SetName( EscapeString( symbol->GetName(), CTX_LIBID ) );
853
854 newSymbols.push_back( new LIB_SYMBOL( *symbol ) );
855 newSymbols.back()->SetParent( symbolMap[ symbol->GetParent().lock().get() ] );
856 }
857
858 // Finally write out newSymbols
859 for( LIB_SYMBOL* symbol : newSymbols )
860 {
861 kicadPI->SaveSymbol( newFilepath, symbol );
862 }
863 }
864 catch( ... )
865 {
866 return false;
867 }
868
869 return true;
870}
871
872
874{
876 return false;
877
878 if( !verifyTables() )
879 return false;
880
881 if( *global_model() != *m_globalTable )
882 {
884
886 m_globalTable->rows.transfer( m_globalTable->rows.end(), global_model()->rows.begin(),
887 global_model()->rows.end(), global_model()->rows );
889 }
890
892 {
894
896 m_projectTable->rows.transfer( m_projectTable->rows.end(), project_model()->rows.begin(),
897 project_model()->rows.end(), project_model()->rows );
899 }
900
901 return true;
902}
903
904
906{
907 wxRegEx re( ".*?(\\$\\{(.+?)\\})|(\\$\\((.+?)\\)).*?", wxRE_ADVANCED );
908 wxASSERT( re.IsValid() ); // wxRE_ADVANCED is required.
909
910 std::set< wxString > unique;
911
912 // clear the table
914
916 {
917 if( !tbl )
918 continue;
919
920 for( int row = 0; row < tbl->GetNumberRows(); ++row )
921 {
922 wxString uri = tbl->GetValue( row, COL_URI );
923
924 while( re.Matches( uri ) )
925 {
926 wxString envvar = re.GetMatch( uri, 2 );
927
928 // if not ${...} form then must be $(...)
929 if( envvar.IsEmpty() )
930 envvar = re.GetMatch( uri, 4 );
931
932 // ignore duplicates
933 unique.insert( envvar );
934
935 // delete the last match and search again
936 uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString );
937 }
938 }
939 }
940
941 // Make sure this special environment variable shows up even if it was
942 // not used yet. It is automatically set by KiCad to the directory holding
943 // the current project.
944 unique.insert( PROJECT_VAR_NAME );
946
947 for( const wxString& evName : unique )
948 {
949 int row = m_path_subs_grid->GetNumberRows();
950 m_path_subs_grid->AppendRows( 1 );
951
952 m_path_subs_grid->SetCellValue( row, 0, wxT( "${" ) + evName + wxT( "}" ) );
953 m_path_subs_grid->SetCellEditor( row, 0, new GRID_CELL_READONLY_TEXT_EDITOR() );
954
955 wxString evValue;
956 wxGetEnv( evName, &evValue );
957 m_path_subs_grid->SetCellValue( row, 1, evValue );
958 m_path_subs_grid->SetCellEditor( row, 1, new GRID_CELL_READONLY_TEXT_EDITOR() );
959 }
960
961 // No combobox editors here, but it looks better if its consistent with the other
962 // grids in the dialog.
963 m_path_subs_grid->SetDefaultRowSize( m_path_subs_grid->GetDefaultRowSize() + 2 );
964
965 adjustPathSubsGridColumns( m_path_subs_grid->GetRect().GetWidth() );
966}
967
968
970{
971 // Account for scroll bars
972 aWidth -= ( m_path_subs_grid->GetSize().x - m_path_subs_grid->GetClientSize().x );
973
974 m_path_subs_grid->AutoSizeColumn( 0 );
975
976 int remaining_width = aWidth - m_path_subs_grid->GetColSize( 0 );
977
978 if( remaining_width < 0 )
979 m_path_subs_grid->SetColSize( 1, -1 );
980 else
981 m_path_subs_grid->SetColSize( 1, remaining_width );
982}
983
984
985void PANEL_SYM_LIB_TABLE::onSizeGrid( wxSizeEvent& event )
986{
987 adjustPathSubsGridColumns( event.GetSize().GetX() );
988
989 event.Skip();
990}
991
992
994{
995 return (SYMBOL_LIB_TABLE_GRID*) m_global_grid->GetTable();
996}
997
998
1000{
1001 return m_project_grid ? (SYMBOL_LIB_TABLE_GRID*) m_project_grid->GetTable() : nullptr;
1002}
1003
1004
1006{
1007 return (SYMBOL_LIB_TABLE_GRID*) m_cur_grid->GetTable();
1008}
1009
1010
1012
1013
1014void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
1015{
1016 auto* schEditor = (SCH_EDIT_FRAME*) aKiway->Player( FRAME_SCH, false );
1017 auto* symbolEditor = (SYMBOL_EDIT_FRAME*) aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false );
1018 auto* symbolViewer = (SYMBOL_VIEWER_FRAME*) aKiway->Player( FRAME_SCH_VIEWER, false );
1019
1021 wxString globalTablePath = SYMBOL_LIB_TABLE::GetGlobalTableFileName();
1022 SYMBOL_LIB_TABLE* projectTable = nullptr;
1023 wxString projectPath = aKiway->Prj().GetProjectPath();
1024 wxFileName projectTableFn( projectPath, SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
1025 wxString msg;
1026 wxString currentLib;
1027
1028 // Don't allow editing project tables if no project is open
1029 if( !aKiway->Prj().IsNullProject() )
1030 projectTable = aKiway->Prj().SchSymbolLibTable();
1031
1032 if( symbolEditor )
1033 {
1034 currentLib = symbolEditor->GetCurLib();
1035
1036 // This prevents an ugly crash on OSX (https://bugs.launchpad.net/kicad/+bug/1765286)
1037 symbolEditor->FreezeLibraryTree();
1038
1039 if( symbolEditor->HasLibModifications() )
1040 {
1041 msg = _( "Modifications have been made to one or more symbol libraries.\n"
1042 "Changes must be saved or discarded before the symbol library "
1043 "table can be modified." );
1044
1045 switch( UnsavedChangesDialog( aParent, msg ) )
1046 {
1047 case wxID_YES: symbolEditor->SaveAll(); break;
1048 case wxID_NO: symbolEditor->RevertAll(); break;
1049 default:
1050 case wxID_CANCEL: symbolEditor->ThawLibraryTree(); return;
1051 }
1052 }
1053 }
1054
1055 DIALOG_EDIT_LIBRARY_TABLES dlg( aParent, _( "Symbol Libraries" ) );
1056 dlg.SetKiway( &dlg, aKiway );
1057
1058 dlg.InstallPanel( new PANEL_SYM_LIB_TABLE( &dlg, &aKiway->Prj(), globalTable, globalTablePath,
1059 projectTable, projectTableFn.GetFullPath() ) );
1060
1061 if( dlg.ShowModal() == wxID_CANCEL )
1062 {
1063 if( symbolEditor )
1064 symbolEditor->ThawLibraryTree();
1065
1066 return;
1067 }
1068
1069 if( dlg.m_GlobalTableChanged )
1070 {
1071 try
1072 {
1073 globalTable->Save( globalTablePath );
1074 }
1075 catch( const IO_ERROR& ioe )
1076 {
1077 msg.Printf( _( "Error saving global library table:\n\n%s" ), ioe.What() );
1078 wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
1079 }
1080 }
1081
1082 if( projectTable && dlg.m_ProjectTableChanged )
1083 {
1084 try
1085 {
1086 projectTable->Save( projectTableFn.GetFullPath() );
1087 }
1088 catch( const IO_ERROR& ioe )
1089 {
1090 msg.Printf( _( "Error saving project-specific library table:\n\n%s" ), ioe.What() );
1091 wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
1092 }
1093 }
1094
1095 if( schEditor )
1096 schEditor->SyncView();
1097
1098 if( symbolEditor )
1099 {
1100 // Check if the currently selected symbol library been removed or disabled.
1101 if( !currentLib.empty() && projectTable && !projectTable->HasLibrary( currentLib, true ) )
1102 {
1103 symbolEditor->SetCurLib( wxEmptyString );
1104 symbolEditor->emptyScreen();
1105 }
1106
1107 symbolEditor->SyncLibraries( true );
1108 symbolEditor->ThawLibraryTree();
1109 symbolEditor->RefreshLibraryTree();
1110 }
1111
1112 if( symbolViewer )
1113 symbolViewer->ReCreateLibList();
1114}
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
@ small_folder
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:97
Used for text file output.
Definition: richio.h:457
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)
WX_GRID * m_grid
I don't own the grid, but he owns me.
Definition: grid_tricks.h:121
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:76
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
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:267
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:394
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition: kiway.cpp:192
static unsigned FindIllegalLibraryNameChar(const UTF8 &aLibraryName)
Looks for characters that are illegal in library nicknames.
Definition: lib_id.cpp:242
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:190
Define a library symbol object.
Definition: lib_symbol.h:98
This abstract base class mixes any object derived from LIB_TABLE into wxGridTableBase so the result c...
void SetValue(int aRow, int aCol, const wxString &aValue) override
bool AppendRows(size_t aNumRows=1) override
int GetNumberRows() override
Hold a record identifying a library accessed by the appropriate plug in object in the LIB_TABLE.
LIB_TABLE * GetParent() const
void SetParent(LIB_TABLE *aParent)
const wxString & GetNickName() const
LIB_TABLE_ROW * clone() const
bool GetIsEnabled() const
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
LIB_TABLE_ROW & At(unsigned aIndex)
Get the 'n'th LIB_TABLE_ROW object.
LIB_TABLE_ROWS rows
void Clear()
Delete all rows.
unsigned GetCount() const
Get the number of rows contained in the table.
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
void reindex()
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition: richio.cpp:431
Class PANEL_SYM_LIB_TABLE_BASE.
Dialog to show and edit symbol library tables.
void OnUpdateUI(wxUpdateUIEvent &event) override
void moveUpHandler(wxCommandEvent &event) override
SYMBOL_LIB_TABLE * m_projectTable
static size_t m_pageNdx
Remember the last notebook page selected.
void deleteRowHandler(wxCommandEvent &event) override
void browseLibrariesHandler(wxCommandEvent &event) override
SYMBOL_LIB_TABLE_GRID * cur_model() const
PANEL_SYM_LIB_TABLE(DIALOG_EDIT_LIBRARY_TABLES *aParent, PROJECT *m_project, SYMBOL_LIB_TABLE *aGlobal, const wxString &aGlobalTablePath, SYMBOL_LIB_TABLE *aProject, const wxString &aProjectTablePath)
bool verifyTables()
Trim important fields, removes blank row entries, and checks for duplicates.
void adjustPathSubsGridColumns(int aWidth)
bool convertLibrary(const wxString &aLibrary, const wxString &legacyFilepath, const wxString &newFilepath)
SYMBOL_LIB_TABLE_GRID * global_model() const
SYMBOL_LIB_TABLE * m_globalTable
void onSizeGrid(wxSizeEvent &event) override
void onConvertLegacyLibraries(wxCommandEvent &event) override
SYMBOL_LIB_TABLE_GRID * project_model() const
void moveDownHandler(wxCommandEvent &event) override
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:97
Container for project specific data.
Definition: project.h:63
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:125
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
Definition: project.cpp:137
Schematic editor (Eeschema) main window.
static const wxString ShowType(SCH_FILE_T aFileType)
Return a brief name for a plugin, given aFileType enum.
Definition: sch_io_mgr.cpp:81
static const wxString GetLibraryFileExtension(SCH_FILE_T aFileType)
Return the symbol library file extension (if any) for aFileType.
Definition: sch_io_mgr.cpp:141
Helper object to release a SCH_PLUGIN in the context of a potential thrown exception through its dest...
Definition: sch_io_mgr.h:535
virtual void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const PROPERTIES *aProperties=nullptr)
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
Definition: sch_plugin.cpp:67
virtual void SaveSymbol(const wxString &aLibraryPath, const LIB_SYMBOL *aSymbol, const PROPERTIES *aProperties=nullptr)
Write aSymbol to an existing library located at aLibraryPath.
Definition: sch_plugin.cpp:94
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:241
The symbol library editor main window.
DIALOG_EDIT_LIBRARY_TABLES * m_dialog
SYMBOL_GRID_TRICKS(DIALOG_EDIT_LIBRARY_TABLES *aParent, WX_GRID *aGrid)
virtual void paste_text(const wxString &cb_text) override
handle specialized clipboard text, with leading "(sym_lib_table" or spreadsheet formatted text.
Build a wxGridTableBase by wrapping an SYMBOL_LIB_TABLE object.
void SetValue(int aRow, int aCol, const wxString &aValue) override
LIB_TABLE_ROW * at(size_t aIndex) override
LIB_TABLE_ROWS_ITER erase(LIB_TABLE_ROWS_ITER aFirst, LIB_TABLE_ROWS_ITER aLast) override
LIB_TABLE_ROWS_ITER begin() override
LIB_TABLE_ROWS_ITER insert(LIB_TABLE_ROWS_ITER aIterator, LIB_TABLE_ROW *aRow) override
LIB_TABLE_ROW * makeNewRow() override
void push_back(LIB_TABLE_ROW *aRow) override
size_t size() const override
SYMBOL_LIB_TABLE_GRID(const SYMBOL_LIB_TABLE &aTableToEdit)
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
bool Refresh()
Attempt to reload the library.
static SYMBOL_LIB_TABLE & GetGlobalLibTable()
virtual void Parse(LIB_TABLE_LEXER *aLexer) override
Parse the #LIB_TABLE_LEXER s-expression library table format into the appropriate LIB_TABLE_ROW objec...
static const wxString & GetSymbolLibTableFileName()
static wxString GetGlobalTableFileName()
Fetch the global symbol library table file name.
static const wxString GlobalPathEnvVariableName()
Return the name of the environment variable used to hold the directory of locally installed "KiCad sp...
Symbol library viewer main window.
void SetTable(wxGridTableBase *table, bool aTakeOwnership=false)
Hide wxGrid's SetTable() method with one which doesn't mess up the grid column widths when setting th...
Definition: wx_grid.cpp:93
void ClearRows()
wxWidgets recently added an ASSERT which fires if the position is greater than or equal to the number...
Definition: wx_grid.h:109
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:226
const wxString ExpandEnvVarSubstitutions(const wxString &aString, PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:267
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:253
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:342
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:280
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:299
int UnsavedChangesDialog(wxWindow *parent, const wxString &aMessage, bool *aApplyToAll)
A specialized version of HandleUnsavedChanges which handles an apply-to-all checkbox.
Definition: confirm.cpp:177
This file is part of the common library.
#define _(s)
@ ID_END_EESCHEMA_ID_LIST
Definition: eeschema_id.h:83
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:71
E_SERIE r
Definition: eserie.cpp:41
@ FRAME_SCH_SYMBOL_EDITOR
Definition: frame_type.h:35
@ FRAME_SCH_VIEWER
Definition: frame_type.h:36
@ FRAME_SCH
Definition: frame_type.h:34
wxString DatabaseLibFileWildcard()
wxString LegacySymbolLibFileWildcard()
wxString KiCadSymbolLibFileWildcard()
wxString AllSymbolLibFilesWildcard()
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
LIB_TABLE_ROWS::iterator LIB_TABLE_ROWS_ITER
@ COL_DESCR
@ COL_NICKNAME
@ COL_OPTIONS
@ COL_ENABLED
@ COL_URI
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
void InvokeSchEditSymbolLibTable(KIWAY *aKiway, wxWindow *aParent)
@ ID_PANEL_SYM_LIB_LEGACY
@ ID_PANEL_SYM_LIB_KICAD
see class PGM_BASE
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
Definition: project.h:38
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
#define SEXPR_SYMBOL_LIB_FILE_VERSION
This file contains the file format version information for the s-expression schematic and symbol libr...
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:111
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
Definition: string_utils.h:55
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:119
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.
SCH_IO_MGR::SCH_FILE_T m_Plugin
wxString m_FolderSearchExtension
In case of folders it stands for extensions of files stored inside.
Definition of file extensions used in Kicad.