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 (C) 2017-2024 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>
31#include <symbol_lib_table.h>
32#include <lib_table_lexer.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 <eeschema_id.h>
41#include <symbol_edit_frame.h>
42#include <symbol_viewer_frame.h>
43#include <sch_edit_frame.h>
44#include <kiway.h>
45#include <paths.h>
46#include <pgm_base.h>
51#include <sch_file_versions.h>
52#include <wx/filedlg.h>
53#include <project_sch.h>
54
55
56
57// clang-format off
58
63{
64 wxString m_Description;
65 wxString m_FileFilter;
67 bool m_IsFile;
68 SCH_IO_MGR::SCH_FILE_T m_Plugin;
69};
70
71
75enum {
78};
79
80// clang-format on
81
86{
87 friend class PANEL_SYM_LIB_TABLE;
88 friend class SYMBOL_GRID_TRICKS;
89
90protected:
91 LIB_TABLE_ROW* at( size_t aIndex ) override { return &m_rows.at( aIndex ); }
92
93 size_t size() const override { return m_rows.size(); }
94
96 {
97 return dynamic_cast< LIB_TABLE_ROW* >( new SYMBOL_LIB_TABLE_ROW );
98 }
99
100 LIB_TABLE_ROWS_ITER begin() override { return m_rows.begin(); }
101
103 {
104 return m_rows.insert( aIterator, aRow );
105 }
106
107 void push_back( LIB_TABLE_ROW* aRow ) override { m_rows.push_back( aRow ); }
108
110 {
111 return m_rows.erase( aFirst, aLast );
112 }
113
114public:
115 void SetValue( int aRow, int aCol, const wxString &aValue ) override
116 {
117 wxCHECK( aRow < (int) size(), /* void */ );
118
119 LIB_TABLE_GRID::SetValue( aRow, aCol, aValue );
120
121 // If setting a filepath, attempt to auto-detect the format
122 if( aCol == COL_URI )
123 {
124 LIB_TABLE_ROW* row = at( (size_t) aRow );
125 wxString fullURI = row->GetFullURI( true );
126
127 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( fullURI );
128
129 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
130 pluginType = SCH_IO_MGR::SCH_KICAD;
131
132 SetValue( aRow, COL_TYPE, SCH_IO_MGR::ShowType( pluginType ) );
133 }
134 }
135
136
138 {
139 m_rows = aTableToEdit.m_rows;
140 }
141};
142
144{
145public:
147 LIB_TABLE_GRID_TRICKS( aGrid ),
148 m_dialog( aParent )
149 {
150 }
151
152protected:
154
155 virtual void optionsEditor( int aRow ) override
156 {
158
159 if( tbl->GetNumberRows() > aRow )
160 {
161 LIB_TABLE_ROW* row = tbl->at( (size_t) aRow );
162 const wxString& options = row->GetOptions();
163 wxString result = options;
164 STRING_UTF8_MAP choices;
165
166 SCH_IO_MGR::SCH_FILE_T pi_type = SCH_IO_MGR::EnumFromStr( row->GetType() );
167 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pi_type ) );
168 pi->GetLibraryOptions( &choices );
169
170 DIALOG_PLUGIN_OPTIONS dlg( m_dialog, row->GetNickName(), choices, options, &result );
171 dlg.ShowModal();
172
173 if( options != result )
174 {
175 row->SetOptions( result );
176 m_grid->Refresh();
177 }
178 }
179
180 }
181
184 virtual void paste_text( const wxString& cb_text ) override
185 {
187 size_t ndx = cb_text.find( "(sym_lib_table" );
188
189 if( ndx != std::string::npos )
190 {
191 // paste the SYMBOL_LIB_TABLE_ROWs of s-expression (sym_lib_table), starting
192 // at column 0 regardless of current cursor column.
193
194 STRING_LINE_READER slr( TO_UTF8( cb_text ), wxS( "Clipboard" ) );
195 LIB_TABLE_LEXER lexer( &slr );
196 SYMBOL_LIB_TABLE tmp_tbl;
197 bool parsed = true;
198
199 try
200 {
201 tmp_tbl.Parse( &lexer );
202 }
203 catch( PARSE_ERROR& pe )
204 {
205 DisplayError( m_dialog, pe.What() );
206 parsed = false;
207 }
208
209 if( parsed )
210 {
211 // make sure the table is big enough...
212 if( tmp_tbl.GetCount() > (unsigned) tbl->GetNumberRows() )
213 tbl->AppendRows( tmp_tbl.GetCount() - tbl->GetNumberRows() );
214
215 for( unsigned i = 0; i < tmp_tbl.GetCount(); ++i )
216 tbl->ReplaceRow( i, tmp_tbl.At( i ).clone() );
217 }
218
219 m_grid->AutoSizeColumns( false );
220 }
221 else
222 {
223 // paste spreadsheet formatted text.
224 GRID_TRICKS::paste_text( cb_text );
225
226 m_grid->AutoSizeColumns( false );
227 }
228 }
229};
230
231
233 SYMBOL_LIB_TABLE* aGlobalTable,
234 const wxString& aGlobalTablePath,
235 SYMBOL_LIB_TABLE* aProjectTable,
236 const wxString& aProjectTablePath ) :
237 PANEL_SYM_LIB_TABLE_BASE( aParent ),
238 m_globalTable( aGlobalTable ),
239 m_projectTable( aProjectTable ),
240 m_project( aProject ),
241 m_parent( aParent )
242{
243 // wxGrid only supports user owned tables if they exist past end of ~wxGrid(),
244 // so make it a grid owned table.
246
247 wxArrayString pluginChoices;
248
249 for( const SCH_IO_MGR::SCH_FILE_T& type : SCH_IO_MGR::SCH_FILE_T_vector )
250 {
251 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( type ) );
252
253 if( !pi )
254 continue;
255
256 if( const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc() )
257 pluginChoices.Add( SCH_IO_MGR::ShowType( type ) );
258 }
259
260 EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>();
261
262 if( cfg->m_lastSymbolLibDir.IsEmpty() )
264
266
267 auto autoSizeCol =
268 [&]( WX_GRID* aGrid, int aCol )
269 {
270 int prevWidth = aGrid->GetColSize( aCol );
271
272 aGrid->AutoSizeColumn( aCol, false );
273 aGrid->SetColSize( aCol, std::max( prevWidth, aGrid->GetColSize( aCol ) ) );
274 };
275
276 auto setupGrid =
277 [&]( WX_GRID* aGrid )
278 {
279 // Give a bit more room for combobox editors
280 aGrid->SetDefaultRowSize( aGrid->GetDefaultRowSize() + 4 );
281
282 // add Cut, Copy, and Paste to wxGrids
283 aGrid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, aGrid ) );
284
285 aGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
286
287 // Set special attributes
288 wxGridCellAttr* attr;
289
290 attr = new wxGridCellAttr;
291
292 wxString fileFiltersStr;
293 wxString allWildcardsStr;
294
295 attr->SetEditor( new GRID_CELL_PATH_EDITOR( m_parent, aGrid,
296 &cfg->m_lastSymbolLibDir,
297 true, m_project->GetProjectPath(),
298 []( WX_GRID* grid, int row ) -> wxString
299 {
300 auto* libTable = static_cast<SYMBOL_LIB_TABLE_GRID*>( grid->GetTable() );
301 auto* tableRow = static_cast<SYMBOL_LIB_TABLE_ROW*>( libTable->at( row ) );
302
303 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( tableRow->GetFileType() ) );
304
305 if( pi )
306 {
307 const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc();
308
309 if( desc.m_IsFile )
310 return desc.FileFilter();
311 }
312
313 return wxEmptyString;
314 } ) );
315 aGrid->SetColAttr( COL_URI, attr );
316
317 attr = new wxGridCellAttr;
318 attr->SetEditor( new wxGridCellChoiceEditor( pluginChoices ) );
319 aGrid->SetColAttr( COL_TYPE, attr );
320
321 attr = new wxGridCellAttr;
322 attr->SetRenderer( new wxGridCellBoolRenderer() );
323 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
324 aGrid->SetColAttr( COL_ENABLED, attr );
325
326 attr = new wxGridCellAttr;
327 attr->SetRenderer( new wxGridCellBoolRenderer() );
328 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
329 aGrid->SetColAttr( COL_VISIBLE, attr );
330
331 // all but COL_OPTIONS, which is edited with Option Editor anyways.
332 autoSizeCol( aGrid, COL_NICKNAME );
333 autoSizeCol( aGrid, COL_TYPE );
334 autoSizeCol( aGrid, COL_URI );
335 autoSizeCol( aGrid, COL_DESCR );
336 autoSizeCol( aGrid, COL_ENABLED );
337
338 // Gives a selection to each grid, mainly for delete button. wxGrid's wake up with
339 // a currentCell which is sometimes not highlighted.
340 if( aGrid->GetNumberRows() > 0 )
341 aGrid->SelectRow( 0 );
342 };
343
344 setupGrid( m_global_grid );
345
346 if( m_projectTable )
347 {
349 setupGrid( m_project_grid );
350 }
351 else
352 {
353 m_pageNdx = 0;
354 m_notebook->DeletePage( 1 );
355 m_project_grid = nullptr;
356 }
357
358 // add Cut, Copy, and Paste to wxGrids
359 m_path_subs_grid->PushEventHandler( new GRID_TRICKS( m_path_subs_grid ) );
360
362
363 // select the last selected page
364 m_notebook->SetSelection( m_pageNdx );
366
367 m_path_subs_grid->SetColLabelValue( 0, _( "Name" ) );
368 m_path_subs_grid->SetColLabelValue( 1, _( "Value" ) );
369
370 // for ALT+A handling, we want the initial focus to be on the first selected grid.
372
373 // Configure button logos
374 m_append_button->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
375 m_delete_button->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
376 m_move_up_button->SetBitmap( KiBitmapBundle( BITMAPS::small_up ) );
377 m_move_down_button->SetBitmap( KiBitmapBundle( BITMAPS::small_down ) );
378 m_browse_button->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
379}
380
381
383{
384 // Delete the GRID_TRICKS.
385 // Any additional event handlers should be popped before the window is deleted.
386 m_global_grid->PopEventHandler( true );
387
388 if( m_project_grid )
389 m_project_grid->PopEventHandler( true );
390
391 m_path_subs_grid->PopEventHandler( true );
392}
393
394
396{
397 // When the plugin type depends only of the file extension, return true.
398 // if it needs to read the actual file (taht can be not available), return false
399
400 wxFileName fn( aLibraryPath );
401 wxString ext = fn.GetExt().Lower();
402
403 // Currently, only the extension .lib is common to legacy libraries and Cadstar libraries
404 // so return false in this case
406 return false;
407
408 return true;
409}
410
411
413{
414 wxString msg;
415
416 for( SYMBOL_LIB_TABLE_GRID* model : { global_model(), project_model() } )
417 {
418 if( !model )
419 continue;
420
421 for( int r = 0; r < model->GetNumberRows(); )
422 {
423 wxString nick = model->GetValue( r, COL_NICKNAME ).Trim( false ).Trim();
424 wxString uri = model->GetValue( r, COL_URI ).Trim( false ).Trim();
425 unsigned illegalCh = 0;
426
427 if( !nick || !uri )
428 {
429 if( !nick && !uri )
430 msg = _( "A library table row nickname and path cells are empty." );
431 else if( !nick )
432 msg = _( "A library table row nickname cell is empty." );
433 else
434 msg = _( "A library table row path cell is empty." );
435
436 wxWindow* topLevelParent = wxGetTopLevelParent( this );
437
438 wxMessageDialog badCellDlg( topLevelParent, msg, _( "Invalid Row Definition" ),
439 wxYES_NO | wxCENTER | wxICON_QUESTION | wxYES_DEFAULT );
440 badCellDlg.SetExtendedMessage( _( "Empty cells will result in all rows that are "
441 "invalid to be removed from the table." ) );
442 badCellDlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Remove Invalid Cells" ) ),
443 wxMessageDialog::ButtonLabel( _( "Cancel Table Update" ) ) );
444
445 if( badCellDlg.ShowModal() == wxID_NO )
446 return false;
447
448 // Delete the "empty" row, where empty means missing nick or uri.
449 // This also updates the UI which could be slow, but there should only be a few
450 // rows to delete, unless the user fell asleep on the Add Row
451 // button.
452 model->DeleteRows( r, 1 );
453 }
454 else if( ( illegalCh = LIB_ID::FindIllegalLibraryNameChar( nick ) ) )
455 {
456 msg = wxString::Format( _( "Illegal character '%c' in nickname '%s'" ),
457 illegalCh,
458 nick );
459
460 // show the tabbed panel holding the grid we have flunked:
461 if( model != cur_model() )
462 m_notebook->SetSelection( model == global_model() ? 0 : 1 );
463
464 m_cur_grid->MakeCellVisible( r, 0 );
465 m_cur_grid->SetGridCursor( r, 1 );
466
467 wxWindow* topLevelParent = wxGetTopLevelParent( this );
468
469 wxMessageDialog errdlg( topLevelParent, msg, _( "Library Nickname Error" ) );
470 errdlg.ShowModal();
471 return false;
472 }
473 else
474 {
475 // set the trimmed values back into the table so they get saved to disk.
476 model->SetValue( r, COL_NICKNAME, nick );
477
479 model->SetValue( r, COL_URI, uri );
480 else
481 {
482 wxString ltype = model->GetValue( r, COL_TYPE );
483 model->LIB_TABLE_GRID::SetValue( r, COL_URI, uri );
484 model->SetValue( r, COL_TYPE, ltype );
485 }
486
487 ++r; // this row was OK.
488 }
489 }
490 }
491
492 // check for duplicate nickNames, separately in each table.
493 for( SYMBOL_LIB_TABLE_GRID* model : { global_model(), project_model() } )
494 {
495 if( !model )
496 continue;
497
498 for( int r1 = 0; r1 < model->GetNumberRows() - 1; ++r1 )
499 {
500 wxString nick1 = model->GetValue( r1, COL_NICKNAME );
501
502 for( int r2=r1+1; r2 < model->GetNumberRows(); ++r2 )
503 {
504 wxString nick2 = model->GetValue( r2, COL_NICKNAME );
505
506 if( nick1 == nick2 )
507 {
508 msg = wxString::Format( _( "Multiple libraries cannot share the same "
509 "nickname ('%s')." ), nick1 );
510
511 // show the tabbed panel holding the grid we have flunked:
512 if( model != cur_model() )
513 m_notebook->SetSelection( model == global_model() ? 0 : 1 );
514
515 // go to the lower of the two rows, it is technically the duplicate:
516 m_cur_grid->MakeCellVisible( r2, 0 );
517 m_cur_grid->SetGridCursor( r2, 1 );
518
519 wxWindow* topLevelParent = wxGetTopLevelParent( this );
520
521 wxMessageDialog errdlg( topLevelParent, msg, _( "Library Nickname Error" ) );
522 errdlg.ShowModal();
523
524 return false;
525 }
526 }
527 }
528 }
529
530 for( SYMBOL_LIB_TABLE* table : { global_model(), project_model() } )
531 {
532 if( !table )
533 continue;
534
535 for( unsigned int r = 0; r < table->GetCount(); ++r )
536 {
537 SYMBOL_LIB_TABLE_ROW& row = dynamic_cast<SYMBOL_LIB_TABLE_ROW&>( table->At( r ) );
538
539 // Newly-added rows won't have set this yet
540 row.SetParent( table );
541
542 if( !row.GetIsEnabled() )
543 continue;
544
545 try
546 {
547 if( row.Refresh() )
548 {
549 if( table == global_model() )
551 else
553 }
554 }
555 catch( const IO_ERROR& ioe )
556 {
557 msg.Printf( _( "Symbol library '%s' failed to load." ), row.GetNickName() );
558
559 wxWindow* topLevelParent = wxGetTopLevelParent( this );
560
561 wxMessageDialog errdlg( topLevelParent, msg + wxS( "\n" ) + ioe.What(),
562 _( "Error Loading Library" ) );
563 errdlg.ShowModal();
564
565 return true;
566 }
567 }
568 }
569
570 return true;
571}
572
573
574void PANEL_SYM_LIB_TABLE::OnUpdateUI( wxUpdateUIEvent& event )
575{
576 m_pageNdx = (unsigned) std::max( 0, m_notebook->GetSelection() );
578}
579
580
582{
583 wxString fileFiltersStr;
584 wxString allWildcardsStr;
585
586 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
587 {
588 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
589
590 if( !pi )
591 continue;
592
593 const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc();
594
595 if( desc.m_FileExtensions.empty() )
596 continue;
597
598 if( !fileFiltersStr.IsEmpty() )
599 fileFiltersStr += wxChar( '|' );
600
601 fileFiltersStr += desc.FileFilter();
602
603 for( const std::string& ext : desc.m_FileExtensions )
604 allWildcardsStr << wxT( "*." ) << formatWildcardExt( ext ) << wxT( ";" );
605 }
606
607 fileFiltersStr = _( "All supported formats" ) + wxT( "|" ) + allWildcardsStr + wxT( "|" )
608 + fileFiltersStr;
609
610 EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>();
611
612 wxString openDir = cfg->m_lastSymbolLibDir;
613
615 openDir = m_lastProjectLibDir;
616
617 wxWindow* topLevelParent = wxGetTopLevelParent( this );
618
619 wxFileDialog dlg( topLevelParent, _( "Add Library" ), openDir, wxEmptyString, fileFiltersStr,
620 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE );
621
622 if( dlg.ShowModal() == wxID_CANCEL )
623 return;
624
626 cfg->m_lastSymbolLibDir = dlg.GetDirectory();
627 else
628 m_lastProjectLibDir = dlg.GetDirectory();
629
630 const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
631 bool addDuplicates = false;
632 bool applyToAll = false;
633 wxString warning = _( "Warning: Duplicate Nickname" );
634 wxString msg = _( "A library nicknamed '%s' already exists." );
635 wxString detailedMsg = _( "One of the nicknames will need to be changed after "
636 "adding this library." );
637
638 wxArrayString filePathsList;
639 dlg.GetPaths( filePathsList );
640
641 for( const wxString& filePath : filePathsList )
642 {
643 wxFileName fn( filePath );
644 wxString nickname = LIB_ID::FixIllegalChars( fn.GetName(), true );
645 bool doAdd = true;
646
647 if( cur_model()->ContainsNickname( nickname ) )
648 {
649 if( !applyToAll )
650 {
651 // The cancel button adds the library to the table anyway
652 addDuplicates = OKOrCancelDialog( wxGetTopLevelParent( this ), warning,
653 wxString::Format( msg, nickname ),
654 detailedMsg, _( "Skip" ), _( "Add Anyway" ),
655 &applyToAll ) == wxID_CANCEL;
656 }
657
658 doAdd = addDuplicates;
659 }
660
661 if( doAdd && m_cur_grid->AppendRows( 1 ) )
662 {
663 int last_row = m_cur_grid->GetNumberRows() - 1;
664
665 m_cur_grid->SetCellValue( last_row, COL_NICKNAME, nickname );
666
667 // attempt to auto-detect the plugin type
668 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( filePath );
669
670 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
671 pluginType = SCH_IO_MGR::SCH_KICAD;
672
673 m_cur_grid->SetCellValue( last_row, COL_TYPE, SCH_IO_MGR::ShowType( pluginType ) );
674
675 // try to use path normalized to an environmental variable or project path
676 wxString path = NormalizePath( filePath, &envVars, m_project->GetProjectPath() );
677
678 // Do not use the project path in the global library table. This will almost
679 // assuredly be wrong for a different project.
680 if( m_pageNdx == 0 && path.Contains( "${KIPRJMOD}" ) )
681 path = fn.GetFullPath();
682
683 m_cur_grid->SetCellValue( last_row, COL_URI, path );
684 }
685 }
686
687 if( !filePathsList.IsEmpty() )
688 {
689 m_cur_grid->MakeCellVisible( m_cur_grid->GetNumberRows() - 1, COL_ENABLED );
690 m_cur_grid->SetGridCursor( m_cur_grid->GetNumberRows() - 1, COL_NICKNAME );
691 }
692}
693
694
695void PANEL_SYM_LIB_TABLE::appendRowHandler( wxCommandEvent& event )
696{
698 return;
699
700 if( m_cur_grid->AppendRows( 1 ) )
701 {
702 int row = m_cur_grid->GetNumberRows() - 1;
703
704 // wx documentation is wrong, SetGridCursor does not make visible.
705 m_cur_grid->MakeCellVisible( row, COL_ENABLED );
706 m_cur_grid->SetGridCursor( row, COL_NICKNAME );
707 m_cur_grid->EnableCellEditControl( true );
708 m_cur_grid->ShowCellEditControl();
709 }
710}
711
712
713void PANEL_SYM_LIB_TABLE::deleteRowHandler( wxCommandEvent& event )
714{
716 return;
717
718 int curRow = m_cur_grid->GetGridCursorRow();
719 int curCol = m_cur_grid->GetGridCursorCol();
720
721 // In a wxGrid, collect rows that have a selected cell, or are selected
722 // It is not so easy: it depends on the way the selection was made.
723 // Here, we collect rows selected by clicking on a row label, and rows that contain
724 // previously-selected cells.
725 // If no candidate, just delete the row with the grid cursor.
726 wxArrayInt selectedRows = m_cur_grid->GetSelectedRows();
727 wxGridCellCoordsArray cells = m_cur_grid->GetSelectedCells();
728 wxGridCellCoordsArray blockTopLeft = m_cur_grid->GetSelectionBlockTopLeft();
729 wxGridCellCoordsArray blockBotRight = m_cur_grid->GetSelectionBlockBottomRight();
730
731 // Add all row having cell selected to list:
732 for( unsigned ii = 0; ii < cells.GetCount(); ii++ )
733 selectedRows.Add( cells[ii].GetRow() );
734
735 // Handle block selection
736 if( !blockTopLeft.IsEmpty() && !blockBotRight.IsEmpty() )
737 {
738 for( int i = blockTopLeft[0].GetRow(); i <= blockBotRight[0].GetRow(); ++i )
739 selectedRows.Add( i );
740 }
741
742 // Use the row having the grid cursor only if we have no candidate:
743 if( selectedRows.size() == 0 && m_cur_grid->GetGridCursorRow() >= 0 )
744 selectedRows.Add( m_cur_grid->GetGridCursorRow() );
745
746 if( selectedRows.size() == 0 )
747 {
748 wxBell();
749 return;
750 }
751
752 std::sort( selectedRows.begin(), selectedRows.end() );
753
754 // Remove selected rows (note: a row can be stored more than once in list)
755 int last_row = -1;
756
757 // Needed to avoid a wxWidgets alert if the row to delete is the last row
758 // at least on wxMSW 3.2
759 m_cur_grid->ClearSelection();
760
761 for( int ii = selectedRows.GetCount()-1; ii >= 0; ii-- )
762 {
763 int row = selectedRows[ii];
764
765 if( row != last_row )
766 {
767 last_row = row;
768 m_cur_grid->DeleteRows( row, 1 );
769 }
770 }
771
772 if( m_cur_grid->GetNumberRows() > 0 && curRow >= 0 )
773 m_cur_grid->SetGridCursor( std::min( curRow, m_cur_grid->GetNumberRows() - 1 ), curCol );
774}
775
776
777void PANEL_SYM_LIB_TABLE::moveUpHandler( wxCommandEvent& event )
778{
780 return;
781
783 int curRow = m_cur_grid->GetGridCursorRow();
784
785 // @todo: add multiple selection moves.
786 if( curRow >= 1 )
787 {
788 tbl->ChangeRowOrder( curRow--, -1 );
789
790 if( tbl->GetView() )
791 {
792 // Update the wxGrid
793 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, curRow, 0 );
794 tbl->GetView()->ProcessTableMessage( msg );
795 }
796
797 m_cur_grid->MakeCellVisible( curRow, m_cur_grid->GetGridCursorCol() );
798 m_cur_grid->SetGridCursor( curRow, m_cur_grid->GetGridCursorCol() );
799 }
800}
801
802
803void PANEL_SYM_LIB_TABLE::moveDownHandler( wxCommandEvent& event )
804{
806 return;
807
809 int curRow = m_cur_grid->GetGridCursorRow();
810
811 // @todo: add multiple selection moves.
812 if( unsigned( curRow + 1 ) < tbl->m_rows.size() )
813 {
814 tbl->ChangeRowOrder( curRow++, 1 );
815
816 if( tbl->GetView() )
817 {
818 // Update the wxGrid
819 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, curRow - 1, 0 );
820 tbl->GetView()->ProcessTableMessage( msg );
821 }
822
823 m_cur_grid->MakeCellVisible( curRow, m_cur_grid->GetGridCursorCol() );
824 m_cur_grid->SetGridCursor( curRow, m_cur_grid->GetGridCursorCol() );
825 }
826}
827
828
830{
832 return;
833
834 wxArrayInt selectedRows = m_cur_grid->GetSelectedRows();
835
836 if( selectedRows.empty() && m_cur_grid->GetGridCursorRow() >= 0 )
837 selectedRows.push_back( m_cur_grid->GetGridCursorRow() );
838
839 wxArrayInt legacyRows;
840 wxString databaseType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_DATABASE );
841 wxString kicadType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_KICAD );
842 wxString msg;
843
844 for( int row : selectedRows )
845 {
846 if( m_cur_grid->GetCellValue( row, COL_TYPE ) != databaseType &&
847 m_cur_grid->GetCellValue( row, COL_TYPE ) != kicadType )
848 {
849 legacyRows.push_back( row );
850 }
851 }
852
853 if( legacyRows.size() <= 0 )
854 {
855 wxMessageBox( _( "Select one or more rows containing libraries "
856 "to save as current KiCad format (*.kicad_sym)." ) );
857 return;
858 }
859 else
860 {
861 if( legacyRows.size() == 1 )
862 {
863 msg.Printf( _( "Save '%s' as current KiCad format (*.kicad_sym) "
864 "and replace legacy entry in table?" ),
865 m_cur_grid->GetCellValue( legacyRows[0], COL_NICKNAME ) );
866 }
867 else
868 {
869 msg.Printf( _( "Save %d libraries as current KiCad format (*.kicad_sym) "
870 "and replace legacy entries in table?" ),
871 (int) legacyRows.size() );
872 }
873
874 if( !IsOK( m_parent, msg ) )
875 return;
876 }
877
878 for( int row : legacyRows )
879 {
880 wxString libName = m_cur_grid->GetCellValue( row, COL_NICKNAME );
881 wxString relPath = m_cur_grid->GetCellValue( row, COL_URI );
882 wxString resolvedPath = ExpandEnvVarSubstitutions( relPath, m_project );
883 wxFileName legacyLib( resolvedPath );
884
885 if( !legacyLib.Exists() )
886 {
887 msg.Printf( _( "Library '%s' not found." ), relPath );
888
889 wxWindow* topLevelParent = wxGetTopLevelParent( this );
890
891 DisplayErrorMessage( topLevelParent, msg );
892 continue;
893 }
894
895 wxFileName newLib( resolvedPath );
896 newLib.SetExt( "kicad_sym" );
897
898 if( newLib.Exists() )
899 {
900 msg.Printf( _( "File '%s' already exists. Do you want overwrite this file?" ),
901 newLib.GetFullPath() );
902
903 switch( wxMessageBox( msg, _( "Migrate Library" ),
904 wxYES_NO | wxCANCEL | wxICON_QUESTION, m_parent ) )
905 {
906 case wxYES: break;
907 case wxNO: continue;
908 case wxCANCEL: return;
909 }
910 }
911
912 wxString options = m_cur_grid->GetCellValue( row, COL_OPTIONS );
913 std::unique_ptr<STRING_UTF8_MAP> props( LIB_TABLE::ParseOptions( options.ToStdString() ) );
914
915 if( convertLibrary( props.get(), legacyLib.GetFullPath(), newLib.GetFullPath() ) )
916 {
917 relPath = NormalizePath( newLib.GetFullPath(), &Pgm().GetLocalEnvVariables(),
918 m_project );
919
920 // Do not use the project path in the global library table. This will almost
921 // assuredly be wrong for a different project.
922 if( m_cur_grid == m_global_grid && relPath.Contains( "${KIPRJMOD}" ) )
923 relPath = newLib.GetFullPath();
924
925 m_cur_grid->SetCellValue( row, COL_URI, relPath );
926 m_cur_grid->SetCellValue( row, COL_TYPE, kicadType );
927 m_cur_grid->SetCellValue( row, COL_OPTIONS, wxEmptyString );
928 }
929 else
930 {
931 msg.Printf( _( "Failed to save symbol library file '%s'." ), newLib.GetFullPath() );
932
933 wxWindow* topLevelParent = wxGetTopLevelParent( this );
934
935 DisplayErrorMessage( topLevelParent, msg );
936 }
937 }
938}
939
940
941bool PANEL_SYM_LIB_TABLE::convertLibrary( STRING_UTF8_MAP* aOldFileProps, const wxString& aOldFilePath,
942 const wxString& aNewFilepath )
943{
944 SCH_IO_MGR::SCH_FILE_T oldFileType = SCH_IO_MGR::GuessPluginTypeFromLibPath( aOldFilePath );
945
946 if( oldFileType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
947 return false;
948
949 IO_RELEASER<SCH_IO> oldFilePI( SCH_IO_MGR::FindPlugin( oldFileType ) );
950 IO_RELEASER<SCH_IO> kicadPI( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
951 std::vector<LIB_SYMBOL*> symbols;
952 std::vector<LIB_SYMBOL*> newSymbols;
953 std::map<LIB_SYMBOL*, LIB_SYMBOL*> symbolMap;
954
955 try
956 {
957 oldFilePI->EnumerateSymbolLib( symbols, aOldFilePath, aOldFileProps );
958
959 // Copy non-aliases first so we can build a map from symbols to newSymbols
960 for( LIB_SYMBOL* symbol : symbols )
961 {
962 if( symbol->IsAlias() )
963 continue;
964
965 symbol->SetName( EscapeString( symbol->GetName(), CTX_LIBID ) );
966
967 newSymbols.push_back( new LIB_SYMBOL( *symbol ) );
968 symbolMap[symbol] = newSymbols.back();
969 }
970
971 // Now do the aliases using the map to hook them up to their newSymbol parents
972 for( LIB_SYMBOL* symbol : symbols )
973 {
974 if( !symbol->IsAlias() )
975 continue;
976
977 symbol->SetName( EscapeString( symbol->GetName(), CTX_LIBID ) );
978
979 newSymbols.push_back( new LIB_SYMBOL( *symbol ) );
980 newSymbols.back()->SetParent( symbolMap[ symbol->GetParent().lock().get() ] );
981 }
982
983 // Create a blank library
984 kicadPI->SaveLibrary( aNewFilepath );
985
986 // Finally write out newSymbols
987 for( LIB_SYMBOL* symbol : newSymbols )
988 {
989 kicadPI->SaveSymbol( aNewFilepath, symbol );
990 }
991 }
992 catch( ... )
993 {
994 return false;
995 }
996
997 return true;
998}
999
1000
1002{
1004 return false;
1005
1006 if( !verifyTables() )
1007 return false;
1008
1009 if( *global_model() != *m_globalTable )
1010 {
1012
1015 }
1016
1018 {
1020
1023 }
1024
1025 return true;
1026}
1027
1028
1030{
1031 wxRegEx re( ".*?(\\$\\{(.+?)\\})|(\\$\\((.+?)\\)).*?", wxRE_ADVANCED );
1032 wxASSERT( re.IsValid() ); // wxRE_ADVANCED is required.
1033
1034 std::set< wxString > unique;
1035
1036 // clear the table
1038
1039 for( SYMBOL_LIB_TABLE_GRID* tbl : { global_model(), project_model() } )
1040 {
1041 if( !tbl )
1042 continue;
1043
1044 for( int row = 0; row < tbl->GetNumberRows(); ++row )
1045 {
1046 wxString uri = tbl->GetValue( row, COL_URI );
1047
1048 while( re.Matches( uri ) )
1049 {
1050 wxString envvar = re.GetMatch( uri, 2 );
1051
1052 // if not ${...} form then must be $(...)
1053 if( envvar.IsEmpty() )
1054 envvar = re.GetMatch( uri, 4 );
1055
1056 // ignore duplicates
1057 unique.insert( envvar );
1058
1059 // delete the last match and search again
1060 uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString );
1061 }
1062 }
1063 }
1064
1065 // Make sure this special environment variable shows up even if it was
1066 // not used yet. It is automatically set by KiCad to the directory holding
1067 // the current project.
1068 unique.insert( PROJECT_VAR_NAME );
1070
1071 for( const wxString& evName : unique )
1072 {
1073 int row = m_path_subs_grid->GetNumberRows();
1074 m_path_subs_grid->AppendRows( 1 );
1075
1076 m_path_subs_grid->SetCellValue( row, 0, wxT( "${" ) + evName + wxT( "}" ) );
1077 m_path_subs_grid->SetCellEditor( row, 0, new GRID_CELL_READONLY_TEXT_EDITOR() );
1078
1079 wxString evValue;
1080 wxGetEnv( evName, &evValue );
1081 m_path_subs_grid->SetCellValue( row, 1, evValue );
1082 m_path_subs_grid->SetCellEditor( row, 1, new GRID_CELL_READONLY_TEXT_EDITOR() );
1083 }
1084
1085 // No combobox editors here, but it looks better if its consistent with the other
1086 // grids in the dialog.
1087 m_path_subs_grid->SetDefaultRowSize( m_path_subs_grid->GetDefaultRowSize() + 2 );
1088
1089 adjustPathSubsGridColumns( m_path_subs_grid->GetRect().GetWidth() );
1090}
1091
1092
1094{
1095 // Account for scroll bars
1096 aWidth -= ( m_path_subs_grid->GetSize().x - m_path_subs_grid->GetClientSize().x );
1097
1098 m_path_subs_grid->AutoSizeColumn( 0 );
1099 m_path_subs_grid->SetColSize( 0, std::max( 72, m_path_subs_grid->GetColSize( 0 ) ) );
1100 m_path_subs_grid->SetColSize( 1, std::max( 120, aWidth - m_path_subs_grid->GetColSize( 0 ) ) );
1101}
1102
1103
1104void PANEL_SYM_LIB_TABLE::onSizeGrid( wxSizeEvent& event )
1105{
1106 adjustPathSubsGridColumns( event.GetSize().GetX() );
1107
1108 event.Skip();
1109}
1110
1111
1113{
1114 return (SYMBOL_LIB_TABLE_GRID*) m_global_grid->GetTable();
1115}
1116
1117
1119{
1120 return m_project_grid ? (SYMBOL_LIB_TABLE_GRID*) m_project_grid->GetTable() : nullptr;
1121}
1122
1123
1125{
1126 return (SYMBOL_LIB_TABLE_GRID*) m_cur_grid->GetTable();
1127}
1128
1129
1131
1132
1133void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
1134{
1135 auto* symbolEditor = (SYMBOL_EDIT_FRAME*) aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false );
1136
1138 wxString globalTablePath = SYMBOL_LIB_TABLE::GetGlobalTableFileName();
1139 SYMBOL_LIB_TABLE* projectTable = nullptr;
1140 wxString projectPath = aKiway->Prj().GetProjectPath();
1141 wxFileName projectTableFn( projectPath, SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
1142 wxString msg;
1143 wxString currentLib;
1144
1145 // Don't allow editing project tables if no project is open
1146 if( !aKiway->Prj().IsNullProject() )
1147 projectTable = PROJECT_SCH::SchSymbolLibTable( &aKiway->Prj() );
1148
1149 if( symbolEditor )
1150 {
1151 currentLib = symbolEditor->GetCurLib();
1152
1153 // This prevents an ugly crash on OSX (https://bugs.launchpad.net/kicad/+bug/1765286)
1154 symbolEditor->FreezeLibraryTree();
1155
1156 if( symbolEditor->HasLibModifications() )
1157 {
1158 msg = _( "Modifications have been made to one or more symbol libraries.\n"
1159 "Changes must be saved or discarded before the symbol library "
1160 "table can be modified." );
1161
1162 switch( UnsavedChangesDialog( aParent, msg ) )
1163 {
1164 case wxID_YES: symbolEditor->SaveAll(); break;
1165 case wxID_NO: symbolEditor->RevertAll(); break;
1166 default:
1167 case wxID_CANCEL: symbolEditor->ThawLibraryTree(); return;
1168 }
1169 }
1170 }
1171
1172 DIALOG_EDIT_LIBRARY_TABLES dlg( aParent, _( "Symbol Libraries" ) );
1173 dlg.SetKiway( &dlg, aKiway );
1174
1175 dlg.InstallPanel( new PANEL_SYM_LIB_TABLE( &dlg, &aKiway->Prj(), globalTable, globalTablePath,
1176 projectTable, projectTableFn.GetFullPath() ) );
1177
1178 if( dlg.ShowModal() == wxID_CANCEL )
1179 {
1180 if( symbolEditor )
1181 symbolEditor->ThawLibraryTree();
1182
1183 return;
1184 }
1185
1186 if( dlg.m_GlobalTableChanged )
1187 {
1188 try
1189 {
1190 globalTable->Save( globalTablePath );
1191 }
1192 catch( const IO_ERROR& ioe )
1193 {
1194 msg.Printf( _( "Error saving global library table:\n\n%s" ), ioe.What() );
1195 wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
1196 }
1197 }
1198
1199 if( projectTable && dlg.m_ProjectTableChanged )
1200 {
1201 try
1202 {
1203 projectTable->Save( projectTableFn.GetFullPath() );
1204 }
1205 catch( const IO_ERROR& ioe )
1206 {
1207 msg.Printf( _( "Error saving project-specific library table:\n\n%s" ), ioe.What() );
1208 wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
1209 }
1210 }
1211
1212 if( symbolEditor )
1213 {
1214 symbolEditor->ThawLibraryTree();
1215 }
1216
1217 std::string payload = "";
1218 aKiway->ExpressMail( FRAME_SCH, MAIL_RELOAD_LIB, payload );
1220 aKiway->ExpressMail( FRAME_SCH_VIEWER, MAIL_RELOAD_LIB, payload );
1221}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
DIALOG_PLUGIN_OPTIONS is an options editor in the form of a two column name/value spreadsheet like (t...
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:97
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:125
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
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:279
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:432
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr)
Send aPayload to aDestination from aSource.
Definition: kiway.cpp:553
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition: kiway.cpp:196
static unsigned FindIllegalLibraryNameChar(const UTF8 &aLibraryName)
Looks for characters that are illegal in library nicknames.
Definition: lib_id.cpp:243
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:191
Define a library symbol object.
Definition: lib_symbol.h:99
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.
const wxString & GetOptions() const
Return the options string, which may hold a password or anything else needed to instantiate the under...
virtual const wxString GetType() const =0
Return the type of library represented by this row.
void SetParent(LIB_TABLE *aParent)
const wxString & GetNickName() const
const wxString GetFullURI(bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
LIB_TABLE_ROW * clone() const
bool GetIsEnabled() const
void SetOptions(const wxString &aOptions)
Change the library options strings.
bool ReplaceRow(size_t aIndex, LIB_TABLE_ROW *aRow)
Replaces the Nth row with the given new row.
LIB_TABLE_ROW & At(unsigned aIndex)
Get the 'n'th LIB_TABLE_ROW object.
void TransferRows(LIB_TABLE_ROWS &aRowsList)
Takes ownership of another list of rows; the original list will be freed.
LIB_TABLE_ROWS m_rows
Owning set of rows.
void Clear()
Delete all rows.
unsigned GetCount() const
Get the number of rows contained in the table.
bool ChangeRowOrder(size_t aIndex, int aOffset)
Moves a row within the table.
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
static STRING_UTF8_MAP * ParseOptions(const std::string &aOptionsList)
Parses aOptionsList and places the result into a #PROPERTIES object which is returned.
Class PANEL_SYM_LIB_TABLE_BASE.
STD_BITMAP_BUTTON * m_browse_button
STD_BITMAP_BUTTON * m_move_up_button
STD_BITMAP_BUTTON * m_delete_button
STD_BITMAP_BUTTON * m_move_down_button
STD_BITMAP_BUTTON * m_append_button
Dialog to show and edit symbol library tables.
void OnUpdateUI(wxUpdateUIEvent &event) override
void moveUpHandler(wxCommandEvent &event) override
bool allowAutomaticPluginTypeSelection(wxString &aLibraryPath)
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(STRING_UTF8_MAP *aOldFileProps, const wxString &aOldFilePath, const wxString &aNewFilePath)
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:98
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
Container for project specific data.
Definition: project.h:62
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
Definition: project.cpp:153
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the #SCH_FILE_T from the corresponding plugin type name: "kicad", "legacy",...
Definition: sch_io_mgr.cpp:106
static const wxString ShowType(SCH_FILE_T aFileType)
Return a brief name for a plugin, given aFileType enum.
Definition: sch_io_mgr.cpp:82
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.
Definition: sch_io_mgr.cpp:139
void SetBitmap(const wxBitmapBundle &aBmp)
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:253
A name/value tuple with unique names and optional values.
The symbol library editor main window.
DIALOG_EDIT_LIBRARY_TABLES * m_dialog
virtual void optionsEditor(int aRow) override
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_IO object i...
bool Refresh() override
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...
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:156
void ClearRows()
wxWidgets recently added an ASSERT which fires if the position is greater than or equal to the number...
Definition: wx_grid.h:147
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:462
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:334
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:360
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:305
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:71
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
@ FRAME_SCH_SYMBOL_EDITOR
Definition: frame_type.h:35
@ FRAME_SCH_VIEWER
Definition: frame_type.h:36
@ FRAME_SCH
Definition: frame_type.h:34
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
LIB_TABLE_ROWS::iterator LIB_TABLE_ROWS_ITER
@ COL_DESCR
@ COL_NICKNAME
@ COL_OPTIONS
@ COL_ENABLED
@ COL_URI
@ MAIL_RELOAD_LIB
Definition: mail_type.h:56
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:39
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:119
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:391
@ CTX_LIBID
Definition: string_utils.h:54
Container that describes file type info.
Definition: io_base.h:39
bool m_IsFile
Whether the library is a folder or a file.
Definition: io_base.h:43
std::vector< std::string > m_FileExtensions
Filter used for file pickers if m_IsFile is true.
Definition: io_base.h:41
wxString FileFilter() const
Definition: io_base.cpp:38
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:120
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.
wxString formatWildcardExt(const wxString &aWildcard)
Format wildcard extension to support case sensitive file dialogs.
Definition of file extensions used in Kicad.