KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_fp_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) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
5 * Copyright (C) 2013-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
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26
27#include <set>
28#include <wx/dir.h>
29#include <wx/regex.h>
30#include <wx/grid.h>
31#include <wx/dirdlg.h>
32#include <wx/filedlg.h>
33#include <wx/msgdlg.h>
34#include <functional>
35
36#include <project.h>
37#include <env_vars.h>
39#include <panel_fp_lib_table.h>
40#include <lib_id.h>
41#include <fp_lib_table.h>
42#include <lib_table_lexer.h>
43#include <invoke_pcb_dialog.h>
44#include <bitmaps.h>
46#include <widgets/wx_grid.h>
48#include <confirm.h>
49#include <lib_table_grid.h>
51#include <pgm_base.h>
52#include <pcb_edit_frame.h>
53#include <env_paths.h>
58#include <kiway.h>
59#include <kiway_express.h>
62#include <pcbnew_id.h> // For ID_PCBNEW_END_LIST
64#include <paths.h>
65#include <macros.h>
66#include <project_pcb.h>
67#include <common.h>
71
72
77{
78 friend class PANEL_FP_LIB_TABLE;
79 friend class FP_GRID_TRICKS;
80
81public:
82
83 FP_LIB_TABLE_GRID( const LIBRARY_TABLE& aTableToEdit ) :
84 LIB_TABLE_GRID( aTableToEdit )
85 {
86 }
87
88 void SetValue( int aRow, int aCol, const wxString &aValue ) override
89 {
90 wxCHECK( aRow < (int) size(), /* void */ );
91
92 LIB_TABLE_GRID::SetValue( aRow, aCol, aValue );
93
94 // If setting a filepath, attempt to auto-detect the format
95 if( aCol == COL_URI )
96 {
97 LIBRARY_TABLE_ROW& row = at( (size_t) aRow );
98 wxString uri = LIBRARY_MANAGER::ExpandURI( row.URI(), Pgm().GetSettingsManager().Prj() );
100
101 if( pluginType == PCB_IO_MGR::FILE_TYPE_NONE )
102 pluginType = PCB_IO_MGR::KICAD_SEXP;
103
104 SetValue( aRow, COL_TYPE, PCB_IO_MGR::ShowType( pluginType ) );
105 }
106 }
107};
108
109
110
112{
113public:
115 LIB_TABLE_GRID_TRICKS( aGrid ),
116 m_dialog( aParent )
117 { }
118
120 std::function<void( wxCommandEvent& )> aAddHandler ) :
121 LIB_TABLE_GRID_TRICKS( aGrid, aAddHandler ),
122 m_dialog( aParent )
123 { }
124
125protected:
127
128 void optionsEditor( int aRow ) override
129 {
130 FP_LIB_TABLE_GRID* tbl = (FP_LIB_TABLE_GRID*) m_grid->GetTable();
131
132 if( tbl->GetNumberRows() > aRow )
133 {
134 LIBRARY_TABLE_ROW& row = tbl->at( static_cast<size_t>( aRow ) );
135 const wxString& options = row.Options();
136 wxString result = options;
137 std::map<std::string, UTF8> choices;
138
141 pi->GetLibraryOptions( &choices );
142
143 DIALOG_PLUGIN_OPTIONS dlg( m_dialog, row.Nickname(), choices, options, &result );
144 dlg.ShowModal();
145
146 if( options != result )
147 {
148 row.SetOptions( result );
149 m_grid->Refresh();
150 }
151 }
152 }
153
156 void paste_text( const wxString& cb_text ) override
157 {
158 // TODO(JE) library tables
159 FP_LIB_TABLE_GRID* tbl = static_cast<FP_LIB_TABLE_GRID*>( m_grid->GetTable() );
160
161 if( size_t ndx = cb_text.find( "(fp_lib_table" ); ndx != std::string::npos )
162 {
163 // paste the FP_LIB_TABLE_ROWs of s-expression (fp_lib_table), starting
164 // at column 0 regardless of current cursor column.
165
166 if( LIBRARY_TABLE tempTable( cb_text, tbl->Table().Scope() ); tempTable.IsOk() )
167 {
168 std::ranges::copy( tempTable.Rows(),
169 std::inserter( tbl->Table().Rows(), tbl->Table().Rows().begin() ) );
170
171 if( tbl->GetView() )
172 {
173 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, 0, 0 );
174 tbl->GetView()->ProcessTableMessage( msg );
175 }
176 }
177 else
178 {
179 DisplayError( m_dialog, tempTable.ErrorDescription() );
180 }
181 }
182 else
183 {
184 wxString text = cb_text;
185
186 if( !text.Contains( '\t' ) && text.Contains( ',' ) )
187 text.Replace( ',', '\t' );
188
189 if( text.Contains( '\t' ) )
190 {
191 int row = m_grid->GetGridCursorRow();
192 m_grid->ClearSelection();
193 m_grid->SelectRow( row );
194 m_grid->SetGridCursor( row, 0 );
196 }
197
199
200 m_grid->AutoSizeColumns( false );
201 }
202
203 m_grid->AutoSizeColumns( false );
204 }
205
206
207 bool toggleCell( int aRow, int aCol, bool aPreserveSelection ) override
208 {
209 if( aCol == COL_VISIBLE )
210 {
211 m_dialog->ShowInfoBarError( _( "Hidden footprint libraries are not yet supported." ) );
212 return true;
213 }
214
215 return LIB_TABLE_GRID_TRICKS::toggleCell( aRow, aCol, aPreserveSelection );
216 }
217};
218
219
221{
222 auto autoSizeCol =
223 [&]( WX_GRID* aLocGrid, int aCol )
224 {
225 int prevWidth = aLocGrid->GetColSize( aCol );
226
227 aLocGrid->AutoSizeColumn( aCol, false );
228 aLocGrid->SetColSize( aCol, std::max( prevWidth, aLocGrid->GetColSize( aCol ) ) );
229 };
230
231 // add Cut, Copy, and Paste to wxGrids
232 aGrid->PushEventHandler( new FP_GRID_TRICKS( m_parent, aGrid,
233 [this]( wxCommandEvent& event )
234 {
235 appendRowHandler( event );
236 } ) );
237
238 aGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
239
240 wxGridCellAttr* attr;
241
242 attr = new wxGridCellAttr;
243
244 if( PCBNEW_SETTINGS* cfg = GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" ) )
245 {
246 attr->SetEditor( new GRID_CELL_PATH_EDITOR(
247 m_parent, aGrid, &cfg->m_LastFootprintLibDir, true, m_project->GetProjectPath(),
248 [this]( WX_GRID* grid, int row ) -> wxString
249 {
250 auto* libTable = static_cast<FP_LIB_TABLE_GRID*>( grid->GetTable() );
251 LIBRARY_TABLE_ROW& tableRow = libTable->at( row );
252 PCB_IO_MGR::PCB_FILE_T fileType = PCB_IO_MGR::EnumFromStr( tableRow.Type() );
253 const IO_BASE::IO_FILE_DESC& pluginDesc = m_supportedFpFiles.at( fileType );
254
255 if( pluginDesc.m_IsFile )
256 return pluginDesc.FileFilter();
257 else
258 return wxEmptyString;
259 } ) );
260 }
261
262 aGrid->SetColAttr( COL_URI, attr );
263
264 attr = new wxGridCellAttr;
265 attr->SetEditor( new wxGridCellChoiceEditor( m_pluginChoices ) );
266 aGrid->SetColAttr( COL_TYPE, attr );
267
268 attr = new wxGridCellAttr;
269 attr->SetRenderer( new wxGridCellBoolRenderer() );
270 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
271 aGrid->SetColAttr( COL_ENABLED, attr );
272
273 attr = new wxGridCellAttr;
274 attr->SetRenderer( new wxGridCellBoolRenderer() );
275 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
276 aGrid->SetColAttr( COL_VISIBLE, attr );
277 // No visibility control for footprint libraries yet; this feature is primarily
278 // useful for database libraries and it's only implemented for schematic symbols
279 // at the moment.
280 aGrid->HideCol( COL_VISIBLE );
281
282 // all but COL_OPTIONS, which is edited with Option Editor anyways.
283 autoSizeCol( aGrid, COL_NICKNAME );
284 autoSizeCol( aGrid, COL_TYPE );
285 autoSizeCol( aGrid, COL_URI );
286 autoSizeCol( aGrid, COL_DESCR );
287
288 // Gives a selection to each grid, mainly for delete button. wxGrid's wake up with
289 // a currentCell which is sometimes not highlighted.
290 if( aGrid->GetNumberRows() > 0 )
291 aGrid->SelectRow( 0 );
292};
293
294
296 PANEL_FP_LIB_TABLE_BASE( aParent ),
297 m_project( aProject ),
298 m_parent( aParent )
299{
300 std::optional<LIBRARY_TABLE*> table = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::FOOTPRINT,
302 wxASSERT( table );
303
304 m_global_grid->SetTable( new FP_LIB_TABLE_GRID( *table.value() ), true );
305
306 // add Cut, Copy, and Paste to wxGrids
307 m_path_subs_grid->PushEventHandler( new GRID_TRICKS( m_path_subs_grid ) );
308
310
311 for( auto& [fileType, desc] : m_supportedFpFiles )
313
314 if( PCBNEW_SETTINGS* cfg = GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" ) )
315 {
316 if( cfg->m_LastFootprintLibDir.IsEmpty() )
317 cfg->m_LastFootprintLibDir = PATHS::GetDefaultUserFootprintsPath();
318 }
319
320 m_lastProjectLibDir = m_project->GetProjectPath();
321
323
325
326 std::optional<LIBRARY_TABLE*> projectTable = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::FOOTPRINT,
328
329 if( projectTable )
330 {
331 m_project_grid->SetTable( new FP_LIB_TABLE_GRID( *projectTable.value() ), true );
333 }
334 else
335 {
336 m_pageNdx = 0;
337 m_notebook->DeletePage( 1 );
338 m_project_grid = nullptr;
339 }
340
341 m_path_subs_grid->SetColLabelValue( 0, _( "Name" ) );
342 m_path_subs_grid->SetColLabelValue( 1, _( "Value" ) );
343
344 // select the last selected page
345 m_notebook->SetSelection( m_pageNdx );
347
348 // for ALT+A handling, we want the initial focus to be on the first selected grid.
349 m_parent->SetInitialFocus( m_cur_grid );
350
351 // Configure button logos
357
358 // For aesthetic reasons, we must set the size of m_browseButton to match the other bitmaps
359 // manually (for instance m_append_button)
360 Layout(); // Needed at least on MSW to compute the actual buttons sizes, after initializing
361 // their bitmaps
362 wxSize buttonSize = m_append_button->GetSize();
363
364 m_browseButton->SetWidthPadding( 4 );
365 m_browseButton->SetMinSize( buttonSize );
366
367 // Populate the browse library options
368 wxMenu* browseMenu = m_browseButton->GetSplitButtonMenu();
369
370 auto joinExts = []( const std::vector<std::string>& aExts )
371 {
372 wxString joined;
373 for( const std::string& ext : aExts )
374 {
375 if( !joined.empty() )
376 joined << wxS( ", " );
377
378 joined << wxS( "*." ) << ext;
379 }
380
381 return joined;
382 };
383
384 for( auto& [type, desc] : m_supportedFpFiles )
385 {
386 wxString entryStr = PCB_IO_MGR::ShowType( type );
387
388 if( desc.m_IsFile && !desc.m_FileExtensions.empty() )
389 {
390 entryStr << wxString::Format( wxS( " (%s)" ), joinExts( desc.m_FileExtensions ) );
391 }
392 else if( !desc.m_IsFile && !desc.m_ExtensionsInDir.empty() )
393 {
394 wxString midPart = wxString::Format( _( "folder with %s files" ),
395 joinExts( desc.m_ExtensionsInDir ) );
396
397 entryStr << wxString::Format( wxS( " (%s)" ), midPart );
398 }
399
400 browseMenu->Append( type, entryStr );
401
402 browseMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_FP_LIB_TABLE::browseLibrariesHandler, this, type );
403 }
404
405 Layout();
406
407 // This is the button only press for the browse button instead of the menu
409}
410
411
413{
414 wxMenu* browseMenu = m_browseButton->GetSplitButtonMenu();
415
416 for( auto& [type, desc] : m_supportedFpFiles )
417 browseMenu->Unbind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_FP_LIB_TABLE::browseLibrariesHandler, this, type );
418
419 m_browseButton->Unbind( wxEVT_BUTTON, &PANEL_FP_LIB_TABLE::browseLibrariesHandler, this );
420
421 // Delete the GRID_TRICKS.
422 // Any additional event handlers should be popped before the window is deleted.
423 m_global_grid->PopEventHandler( true );
424
425 if( m_project_grid )
426 m_project_grid->PopEventHandler( true );
427
428 m_path_subs_grid->PopEventHandler( true );
429}
430
431
433{
434 for( const auto& plugin : PCB_IO_MGR::PLUGIN_REGISTRY::Instance()->AllPlugins() )
435 {
436 IO_RELEASER<PCB_IO> pi( plugin.m_createFunc() );
437
438 if( !pi )
439 continue;
440
441 if( const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc() )
442 m_supportedFpFiles.emplace( plugin.m_type, desc );
443 }
444}
445
446
448{
449 wxString msg;
450
451 for( FP_LIB_TABLE_GRID* model : { global_model(), project_model() } )
452 {
453 if( !model )
454 continue;
455
456 for( int r = 0; r < model->GetNumberRows(); )
457 {
458 wxString nick = model->GetValue( r, COL_NICKNAME ).Trim( false ).Trim();
459 wxString uri = model->GetValue( r, COL_URI ).Trim( false ).Trim();
460 unsigned illegalCh = 0;
461
462 if( !nick || !uri )
463 {
464 if( !nick && !uri )
465 msg = _( "A library table row nickname and path cells are empty." );
466 else if( !nick )
467 msg = _( "A library table row nickname cell is empty." );
468 else
469 msg = _( "A library table row path cell is empty." );
470
471 wxWindow* topLevelParent = wxGetTopLevelParent( this );
472
473 wxMessageDialog badCellDlg( topLevelParent, msg, _( "Invalid Row Definition" ),
474 wxYES_NO | wxCENTER | wxICON_QUESTION | wxYES_DEFAULT );
475 badCellDlg.SetExtendedMessage( _( "Empty cells will result in all rows that are "
476 "invalid to be removed from the table." ) );
477 badCellDlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Remove Invalid Cells" ) ),
478 wxMessageDialog::ButtonLabel( _( "Cancel Table Update" ) ) );
479
480 if( badCellDlg.ShowModal() == wxID_NO )
481 return false;
482
483 // Delete the "empty" row, where empty means missing nick or uri.
484 // This also updates the UI which could be slow, but there should only be a few
485 // rows to delete, unless the user fell asleep on the Add Row
486 // button.
487 model->DeleteRows( r, 1 );
488 }
489 else if( ( illegalCh = LIB_ID::FindIllegalLibraryNameChar( nick ) ) )
490 {
491 msg = wxString::Format( _( "Illegal character '%c' in nickname '%s'." ),
492 illegalCh,
493 nick );
494
495 // show the tabbed panel holding the grid we have flunked:
496 if( model != cur_model() )
497 m_notebook->SetSelection( model == global_model() ? 0 : 1 );
498
499 m_cur_grid->MakeCellVisible( r, 0 );
500 m_cur_grid->SetGridCursor( r, 1 );
501
502 wxWindow* topLevelParent = wxGetTopLevelParent( this );
503
504 wxMessageDialog errdlg( topLevelParent, msg, _( "Library Nickname Error" ) );
505 errdlg.ShowModal();
506 return false;
507 }
508 else
509 {
510 // set the trimmed values back into the table so they get saved to disk.
511 model->SetValue( r, COL_NICKNAME, nick );
512 model->SetValue( r, COL_URI, uri );
513
514 // Make sure to not save a hidden flag
515 model->SetValue( r, COL_VISIBLE, wxS( "1" ) );
516
517 ++r; // this row was OK.
518 }
519 }
520 }
521
522 // check for duplicate nickNames, separately in each table.
523 for( FP_LIB_TABLE_GRID* model : { global_model(), project_model() } )
524 {
525 if( !model )
526 continue;
527
528 for( int r1 = 0; r1 < model->GetNumberRows() - 1; ++r1 )
529 {
530 wxString nick1 = model->GetValue( r1, COL_NICKNAME );
531
532 for( int r2 = r1 + 1; r2 < model->GetNumberRows(); ++r2 )
533 {
534 wxString nick2 = model->GetValue( r2, COL_NICKNAME );
535
536 if( nick1 == nick2 )
537 {
538 msg = wxString::Format( _( "Multiple libraries cannot share the same nickname ('%s')." ),
539 nick1 );
540
541 // show the tabbed panel holding the grid we have flunked:
542 if( model != cur_model() )
543 m_notebook->SetSelection( model == global_model() ? 0 : 1 );
544
545 // go to the lower of the two rows, it is technically the duplicate:
546 m_cur_grid->MakeCellVisible( r2, 0 );
547 m_cur_grid->SetGridCursor( r2, 1 );
548
549 wxWindow* topLevelParent = wxGetTopLevelParent( this );
550
551 wxMessageDialog errdlg( topLevelParent, msg, _( "Library Nickname Error" ) );
552 errdlg.ShowModal();
553 return false;
554 }
555 }
556 }
557 }
558
559 return true;
560}
561
562
563void PANEL_FP_LIB_TABLE::OnUpdateUI( wxUpdateUIEvent& event )
564{
565}
566
567
568void PANEL_FP_LIB_TABLE::appendRowHandler( wxCommandEvent& event )
569{
570 m_cur_grid->OnAddRow(
571 [&]() -> std::pair<int, int>
572 {
573 m_cur_grid->AppendRows( 1 );
574 return { m_cur_grid->GetNumberRows() - 1, COL_NICKNAME };
575 } );
576}
577
578
579void PANEL_FP_LIB_TABLE::deleteRowHandler( wxCommandEvent& event )
580{
581 if( !m_cur_grid->CommitPendingChanges() )
582 return;
583
584 wxGridUpdateLocker noUpdates( m_cur_grid );
585
586 int curRow = m_cur_grid->GetGridCursorRow();
587 int curCol = m_cur_grid->GetGridCursorCol();
588
589 // In a wxGrid, collect rows that have a selected cell, or are selected
590 // It is not so easy: it depends on the way the selection was made.
591 // Here, we collect rows selected by clicking on a row label, and rows that contain any
592 // previously-selected cells.
593 // If no candidate, just delete the row with the grid cursor.
594 wxArrayInt selectedRows = m_cur_grid->GetSelectedRows();
595 wxGridCellCoordsArray cells = m_cur_grid->GetSelectedCells();
596 wxGridCellCoordsArray blockTopLeft = m_cur_grid->GetSelectionBlockTopLeft();
597 wxGridCellCoordsArray blockBotRight = m_cur_grid->GetSelectionBlockBottomRight();
598
599 // Add all row having cell selected to list:
600 for( unsigned ii = 0; ii < cells.GetCount(); ii++ )
601 selectedRows.Add( cells[ii].GetRow() );
602
603 // Handle block selection
604 if( !blockTopLeft.IsEmpty() && !blockBotRight.IsEmpty() )
605 {
606 for( int i = blockTopLeft[0].GetRow(); i <= blockBotRight[0].GetRow(); ++i )
607 selectedRows.Add( i );
608 }
609
610 // Use the row having the grid cursor only if we have no candidate:
611 if( selectedRows.size() == 0 && m_cur_grid->GetGridCursorRow() >= 0 )
612 selectedRows.Add( m_cur_grid->GetGridCursorRow() );
613
614 if( selectedRows.size() == 0 )
615 {
616 wxBell();
617 return;
618 }
619
620 std::sort( selectedRows.begin(), selectedRows.end() );
621
622 // Remove selected rows (note: a row can be stored more than once in list)
623 int last_row = -1;
624
625 // Needed to avoid a wxWidgets alert if the row to delete is the last row
626 // at least on wxMSW 3.2
627 m_cur_grid->ClearSelection();
628
629 for( int ii = selectedRows.GetCount()-1; ii >= 0; ii-- )
630 {
631 int row = selectedRows[ii];
632
633 if( row != last_row )
634 {
635 last_row = row;
636 m_cur_grid->DeleteRows( row, 1 );
637 }
638 }
639
640 if( m_cur_grid->GetNumberRows() > 0 && curRow >= 0 )
641 m_cur_grid->SetGridCursor( std::min( curRow, m_cur_grid->GetNumberRows() - 1 ), curCol );
642}
643
644
645void PANEL_FP_LIB_TABLE::moveUpHandler( wxCommandEvent& event )
646{
647 m_cur_grid->OnMoveRowUp(
648 [&]( int row )
649 {
651 int curRow = m_cur_grid->GetGridCursorRow();
652
653 std::vector<LIBRARY_TABLE_ROW>& rows = tbl->Table().Rows();
654
655 auto current = rows.begin() + curRow;
656 auto prev = rows.begin() + curRow - 1;
657
658 std::iter_swap( current, prev );
659
660 // Update the wxGrid
661 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, row - 1, 0 );
662 tbl->GetView()->ProcessTableMessage( msg );
663 } );
664}
665
666
667void PANEL_FP_LIB_TABLE::moveDownHandler( wxCommandEvent& event )
668{
669 m_cur_grid->OnMoveRowDown(
670 [&]( int row )
671 {
673 int curRow = m_cur_grid->GetGridCursorRow();
674 std::vector<LIBRARY_TABLE_ROW>& rows = tbl->Table().Rows();
675
676 auto current = rows.begin() + curRow;
677 auto next = rows.begin() + curRow + 1;
678
679 std::iter_swap( current, next );
680
681 // Update the wxGrid
682 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, row, 0 );
683 tbl->GetView()->ProcessTableMessage( msg );
684 } );
685}
686
687
688// @todo refactor this function into single location shared with PANEL_SYM_LIB_TABLE
689void PANEL_FP_LIB_TABLE::onMigrateLibraries( wxCommandEvent& event )
690{
691 if( !m_cur_grid->CommitPendingChanges() )
692 return;
693
694 wxArrayInt selectedRows = m_cur_grid->GetSelectedRows();
695
696 if( selectedRows.empty() && m_cur_grid->GetGridCursorRow() >= 0 )
697 selectedRows.push_back( m_cur_grid->GetGridCursorRow() );
698
699 wxArrayInt rowsToMigrate;
700 wxString kicadType = PCB_IO_MGR::ShowType( PCB_IO_MGR::KICAD_SEXP );
701 wxString msg;
702 DIALOG_HTML_REPORTER errorReporter( this );
703
704 for( int row : selectedRows )
705 {
706 if( m_cur_grid->GetCellValue( row, COL_TYPE ) != kicadType )
707 rowsToMigrate.push_back( row );
708 }
709
710 if( rowsToMigrate.size() <= 0 )
711 {
712 wxMessageBox( wxString::Format( _( "Select one or more rows containing libraries "
713 "to save as current KiCad format." ) ) );
714 return;
715 }
716 else
717 {
718 if( rowsToMigrate.size() == 1 )
719 {
720 msg.Printf( _( "Save '%s' as current KiCad format and replace entry in table?" ),
721 m_cur_grid->GetCellValue( rowsToMigrate[0], COL_NICKNAME ) );
722 }
723 else
724 {
725 msg.Printf( _( "Save %d libraries as current KiCad format and replace entries in table?" ),
726 (int) rowsToMigrate.size() );
727 }
728
729 if( !IsOK( m_parent, msg ) )
730 return;
731 }
732
733 for( int row : rowsToMigrate )
734 {
735 wxString relPath = m_cur_grid->GetCellValue( row, COL_URI );
736 wxString resolvedPath = ExpandEnvVarSubstitutions( relPath, m_project );
737 wxFileName legacyLib( resolvedPath );
738
739 if( !legacyLib.Exists() )
740 {
741 msg.Printf( _( "Library '%s' not found." ), relPath );
742 DisplayErrorMessage( wxGetTopLevelParent( this ), msg );
743 continue;
744 }
745
746 wxFileName newLib( resolvedPath );
747 newLib.AppendDir( newLib.GetName() + "." + FILEEXT::KiCadFootprintLibPathExtension );
748 newLib.SetName( "" );
749 newLib.ClearExt();
750
751 if( newLib.DirExists() )
752 {
753 msg.Printf( _( "Folder '%s' already exists. Do you want overwrite any existing footprints?" ),
754 newLib.GetFullPath() );
755
756 switch( wxMessageBox( msg, _( "Migrate Library" ), wxYES_NO|wxCANCEL|wxICON_QUESTION, m_parent ) )
757 {
758 case wxYES: break;
759 case wxNO: continue;
760 case wxCANCEL: return;
761 }
762 }
763
764 wxString options = m_cur_grid->GetCellValue( row, COL_OPTIONS );
765 std::map<std::string, UTF8> props( LIB_TABLE::ParseOptions( options.ToStdString() ) );
766
767 if( PCB_IO_MGR::ConvertLibrary( props, legacyLib.GetFullPath(), newLib.GetFullPath(),
768 errorReporter.m_Reporter ) )
769 {
770 relPath = NormalizePath( newLib.GetFullPath(), &Pgm().GetLocalEnvVariables(), m_project );
771
772 // Do not use the project path in the global library table. This will almost
773 // assuredly be wrong for a different project.
774 if( m_cur_grid == m_global_grid && relPath.Contains( "${KIPRJMOD}" ) )
775 relPath = newLib.GetFullPath();
776
777 m_cur_grid->SetCellValue( row, COL_URI, relPath );
778 m_cur_grid->SetCellValue( row, COL_TYPE, kicadType );
779 }
780 else
781 {
782 msg.Printf( _( "Failed to save footprint library file '%s'." ), newLib.GetFullPath() );
783 DisplayErrorMessage( wxGetTopLevelParent( this ), msg );
784 }
785 }
786
787 if( errorReporter.m_Reporter->HasMessage() )
788 {
789 errorReporter.m_Reporter->Flush(); // Build HTML messages
790 errorReporter.ShowModal();
791 }
792}
793
794
796{
797 if( !m_cur_grid->CommitPendingChanges() )
798 return;
799
801
802 // We are bound both to the menu and button with this one handler
803 // So we must set the file type based on it
804 if( event.GetEventType() == wxEVT_BUTTON )
805 {
806 // Let's default to adding a kicad footprint file for just the footprint
808 }
809 else
810 {
811 fileType = static_cast<PCB_IO_MGR::PCB_FILE_T>( event.GetId() );
812 }
813
815 {
816 wxLogWarning( wxT( "File type selection event received but could not find the file type in the table" ) );
817 return;
818 }
819
820 const IO_BASE::IO_FILE_DESC& fileDesc = m_supportedFpFiles.at( fileType );
822
823 wxString title = wxString::Format( _( "Select %s Library" ), PCB_IO_MGR::ShowType( fileType ) );
824 wxString dummy;
825 wxString* lastDir;
826
828 lastDir = &m_lastProjectLibDir;
829 else
830 lastDir = cfg ? &cfg->m_LastFootprintLibDir : &dummy;
831
832 wxArrayString files;
833
834 wxWindow* topLevelParent = wxGetTopLevelParent( this );
835
836 if( fileDesc.m_IsFile )
837 {
838 wxFileDialog dlg( topLevelParent, title, *lastDir, wxEmptyString, fileDesc.FileFilter(),
839 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE );
840
841 if( dlg.ShowModal() == wxID_CANCEL )
842 return;
843
844 dlg.GetPaths( files );
845 *lastDir = dlg.GetDirectory();
846 }
847 else
848 {
849 wxDirDialog dlg( topLevelParent, title, *lastDir,
850 wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST | wxDD_MULTIPLE );
851
852 if( dlg.ShowModal() == wxID_CANCEL )
853 return;
854
855 dlg.GetPaths( files );
856
857 if( !files.IsEmpty() )
858 {
859 wxFileName first( files.front() );
860 *lastDir = first.GetPath();
861 }
862 }
863
864 // Drop the last directory if the path is a .pretty folder
866 cfg->m_LastFootprintLibDir = cfg->m_LastFootprintLibDir.BeforeLast( wxFileName::GetPathSeparator() );
867
868 const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
869 bool addDuplicates = false;
870 bool applyToAll = false;
871 wxString warning = _( "Warning: Duplicate Nicknames" );
872 wxString msg = _( "A library nicknamed '%s' already exists." );
873 wxString detailedMsg = _( "One of the nicknames will need to be changed after "
874 "adding this library." );
875
876 for( const wxString& filePath : files )
877 {
878 wxFileName fn( filePath );
879 wxString nickname = LIB_ID::FixIllegalChars( fn.GetName(), true );
880 bool doAdd = true;
881
884 {
885 nickname = LIB_ID::FixIllegalChars( fn.GetFullName(), true ).wx_str();
886 }
887
888 if( cur_model()->ContainsNickname( nickname ) )
889 {
890 if( !applyToAll )
891 {
892 // The cancel button adds the library to the table anyway
893 addDuplicates = OKOrCancelDialog( wxGetTopLevelParent( this ), warning,
894 wxString::Format( msg, nickname ),
895 detailedMsg, _( "Skip" ), _( "Add Anyway" ),
896 &applyToAll ) == wxID_CANCEL;
897 }
898
899 doAdd = addDuplicates;
900 }
901
902 if( doAdd && m_cur_grid->AppendRows( 1 ) )
903 {
904 int last_row = m_cur_grid->GetNumberRows() - 1;
905
906 m_cur_grid->SetCellValue( last_row, COL_NICKNAME, nickname );
907
908 m_cur_grid->SetCellValue( last_row, COL_TYPE, PCB_IO_MGR::ShowType( fileType ) );
909
910 // try to use path normalized to an environmental variable or project path
911 wxString path = NormalizePath( filePath, &envVars, m_project->GetProjectPath() );
912
913 // Do not use the project path in the global library table. This will almost
914 // assuredly be wrong for a different project.
915 if( m_pageNdx == 0 && path.Contains( wxT( "${KIPRJMOD}" ) ) )
916 path = fn.GetFullPath();
917
918 m_cur_grid->SetCellValue( last_row, COL_URI, path );
919 }
920 }
921
922 if( !files.IsEmpty() )
923 {
924 int new_row = m_cur_grid->GetNumberRows() - 1;
925 m_cur_grid->MakeCellVisible( new_row, m_cur_grid->GetGridCursorCol() );
926 m_cur_grid->SetGridCursor( new_row, m_cur_grid->GetGridCursorCol() );
927 }
928}
929
930
932{
933 // Account for scroll bars
934 aWidth -= ( m_path_subs_grid->GetSize().x - m_path_subs_grid->GetClientSize().x );
935
936 m_path_subs_grid->AutoSizeColumn( 0 );
937 m_path_subs_grid->SetColSize( 0, std::max( 72, m_path_subs_grid->GetColSize( 0 ) ) );
938 m_path_subs_grid->SetColSize( 1, std::max( 120, aWidth - m_path_subs_grid->GetColSize( 0 ) ) );
939}
940
941
942void PANEL_FP_LIB_TABLE::onSizeGrid( wxSizeEvent& event )
943{
944 adjustPathSubsGridColumns( event.GetSize().GetX() );
945
946 event.Skip();
947}
948
949
950void PANEL_FP_LIB_TABLE::onReset( wxCommandEvent& event )
951{
952 if( !m_cur_grid->CommitPendingChanges() )
953 return;
954
955 // No need to prompt to preserve an empty table
956 if( m_global_grid->GetNumberRows() > 0 &&
957 !IsOK( this, wxString::Format( _( "This action will reset your global library table on "
958 "disk and cannot be undone." ) ) ) )
959 {
960 return;
961 }
962
964
965 // Go ahead and reload here because this action takes place even if the dialog is canceled
967
968 if( KIFACE *face = m_parent->Kiway().KiFACE( KIWAY::FACE_PCB ) )
969 face->PreloadLibraries( &m_parent->Kiway() );
970
971 m_global_grid->Freeze();
972
973 wxGridTableBase* table = m_global_grid->GetTable();
974 m_global_grid->DestroyTable( table );
975
976 std::optional<LIBRARY_TABLE*> newTable =
979 wxASSERT( newTable );
980
981 m_global_grid->SetTable( new FP_LIB_TABLE_GRID( *newTable.value() ), true );
982 m_global_grid->PopEventHandler( true );
984 m_parent->m_GlobalTableChanged = true;
985
986 m_global_grid->Thaw();
987}
988
989
990void PANEL_FP_LIB_TABLE::onPageChange( wxBookCtrlEvent& event )
991{
992 m_pageNdx = (unsigned) std::max( 0, m_notebook->GetSelection() );
993
994 if( m_pageNdx == 0 )
995 {
997 m_resetGlobal->Enable();
998 }
999 else
1000 {
1002 m_resetGlobal->Disable();
1003 }
1004}
1005
1006
1008{
1009 if( !m_cur_grid->CommitPendingChanges() )
1010 return false;
1011
1012 if( !verifyTables() )
1013 return false;
1014
1015 std::optional<LIBRARY_TABLE*> optTable =
1017 wxCHECK( optTable, false );
1018 LIBRARY_TABLE* globalTable = *optTable;
1019
1020 if( global_model()->Table() != *globalTable )
1021 {
1022 m_parent->m_GlobalTableChanged = true;
1023 *globalTable = global_model()->Table();
1024 }
1025
1028
1029 if( optTable && project_model() )
1030 {
1031 LIBRARY_TABLE* projectTable = *optTable;
1032
1033 if( project_model()->Table() != *projectTable )
1034 {
1035 m_parent->m_ProjectTableChanged = true;
1036 *projectTable = project_model()->Table();
1037 }
1038 }
1039
1040 return true;
1041}
1042
1043
1047{
1048 wxRegEx re( ".*?(\\$\\{(.+?)\\})|(\\$\\((.+?)\\)).*?", wxRE_ADVANCED );
1049 wxASSERT( re.IsValid() ); // wxRE_ADVANCED is required.
1050
1051 std::set< wxString > unique;
1052
1053 // clear the table
1054 m_path_subs_grid->ClearRows();
1055
1056 for( FP_LIB_TABLE_GRID* tbl : { global_model(), project_model() } )
1057 {
1058 if( !tbl )
1059 continue;
1060
1061 for( int row = 0; row < tbl->GetNumberRows(); ++row )
1062 {
1063 wxString uri = tbl->GetValue( row, COL_URI );
1064
1065 while( re.Matches( uri ) )
1066 {
1067 wxString envvar = re.GetMatch( uri, 2 );
1068
1069 // if not ${...} form then must be $(...)
1070 if( envvar.IsEmpty() )
1071 envvar = re.GetMatch( uri, 4 );
1072
1073 // ignore duplicates
1074 unique.insert( envvar );
1075
1076 // delete the last match and search again
1077 uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString );
1078 }
1079 }
1080 }
1081
1082 // Make sure this special environment variable shows up even if it was
1083 // not used yet. It is automatically set by KiCad to the directory holding
1084 // the current project.
1085 unique.insert( PROJECT_VAR_NAME );
1086 unique.insert( FP_LIB_TABLE::GlobalPathEnvVariableName() );
1087
1088 // This special environment variable is used to locate 3d shapes
1089 unique.insert( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ) );
1090
1091 for( const wxString& evName : unique )
1092 {
1093 int row = m_path_subs_grid->GetNumberRows();
1094 m_path_subs_grid->AppendRows( 1 );
1095
1096 m_path_subs_grid->SetCellValue( row, 0, wxT( "${" ) + evName + wxT( "}" ) );
1097 m_path_subs_grid->SetCellEditor( row, 0, new GRID_CELL_READONLY_TEXT_EDITOR() );
1098
1099 wxString evValue;
1100 wxGetEnv( evName, &evValue );
1101 m_path_subs_grid->SetCellValue( row, 1, evValue );
1102 m_path_subs_grid->SetCellEditor( row, 1, new GRID_CELL_READONLY_TEXT_EDITOR() );
1103 }
1104
1105 adjustPathSubsGridColumns( m_path_subs_grid->GetRect().GetWidth() );
1106}
1107
1108
1109//-----</event handlers>---------------------------------
1110
1111
1112
1114
1115
1116void InvokePcbLibTableEditor( KIWAY* aKiway, wxWindow* aCaller )
1117{
1118 wxString msg;
1119
1120 DIALOG_EDIT_LIBRARY_TABLES dlg( aCaller, _( "Footprint Libraries" ) );
1121 dlg.SetKiway( &dlg, aKiway );
1122
1123 dlg.InstallPanel( new PANEL_FP_LIB_TABLE( &dlg, &aKiway->Prj() ) );
1124
1125 if( dlg.ShowModal() == wxID_CANCEL )
1126 return;
1127
1128 if( dlg.m_GlobalTableChanged )
1129 {
1130 std::optional<LIBRARY_TABLE*> optTable =
1132 wxCHECK( optTable, /* void */ );
1133 LIBRARY_TABLE* globalTable = *optTable;
1134
1135 globalTable->Save().map_error(
1136 []( const LIBRARY_ERROR& aError )
1137 {
1138 wxMessageBox( wxString::Format( _( "Error saving global library table:\n\n%s" ), aError.message ),
1139 _( "File Save Error" ), wxOK | wxICON_ERROR );
1140 } );
1141
1143
1144 // TODO(JE) library tables - remove after legacy loading is upgrade
1146 }
1147
1148 std::optional<LIBRARY_TABLE*> projectTable =
1150
1151 if( projectTable && dlg.m_ProjectTableChanged )
1152 {
1153 ( *projectTable )->Save().map_error(
1154 []( const LIBRARY_ERROR& aError )
1155 {
1156 wxMessageBox( wxString::Format( _( "Error saving project-specific library table:\n\n%s" ),
1157 aError.message ),
1158 _( "File Save Error" ), wxOK | wxICON_ERROR );
1159 } );
1160
1161 // Trigger a reload of the table and cancel an in-progress background load
1163
1164 // TODO(JE) library tables - remove after legacy loading is upgrade
1165 PROJECT* prj = &aKiway->Prj();
1167 }
1168
1169 // Trigger a reload in case any libraries have been added or removed
1170 if( KIFACE *face = aKiway->KiFACE( KIWAY::FACE_PCB ) )
1171 face->PreloadLibraries( aKiway );
1172
1173 std::string payload = "";
1176 aKiway->ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload );
1177}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
Class DIALOG_HTML_REPORTER.
WX_HTML_REPORT_BOX * m_Reporter
An options editor in the form of a two column name/value spreadsheet like (table) UI.
int ShowModal() override
void paste_text(const wxString &cb_text) override
handle specialized clipboard text, with leading "(fp_lib_table", OR spreadsheet formatted text.
DIALOG_EDIT_LIBRARY_TABLES * m_dialog
FP_GRID_TRICKS(DIALOG_EDIT_LIBRARY_TABLES *aParent, WX_GRID *aGrid)
void optionsEditor(int aRow) override
FP_GRID_TRICKS(DIALOG_EDIT_LIBRARY_TABLES *aParent, WX_GRID *aGrid, std::function< void(wxCommandEvent &)> aAddHandler)
bool toggleCell(int aRow, int aCol, bool aPreserveSelection) override
This class builds a wxGridTableBase by wrapping an FP_LIB_TABLE object.
void SetValue(int aRow, int aCol, const wxString &aValue) override
FP_LIB_TABLE_GRID(const LIBRARY_TABLE &aTableToEdit)
friend class PANEL_FP_LIB_TABLE
static const wxString GlobalPathEnvVariableName()
Return the name of the environment variable used to hold the directory of locally installed "KiCad sp...
static wxString GetGlobalTableFileName()
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.
virtual bool toggleCell(int aRow, int aCol, bool aPreserveSelection=false)
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 void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr, bool aFromOtherThread=false)
Send aPayload to aDestination from aSource.
Definition kiway.cpp:507
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition kiway.cpp:206
@ FACE_PCB
pcbnew DSO
Definition kiway.h:300
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition kiway.cpp:200
static wxString ExpandURI(const wxString &aShortURI, const PROJECT &aProject)
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
static bool CreateGlobalTable(LIBRARY_TABLE_TYPE aType, bool aPopulateDefaultLibraries)
void LoadGlobalTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the global library tables in the given list, or all tables if no list is given
void ProjectChanged()
Notify all adapters that the project has changed.
void SetOptions(const wxString &aOptions)
const wxString & Type() const
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
int GetNumberRows() override
virtual LIBRARY_TABLE_ROW & at(size_t aIndex)
void Load(const wxString &aFileName)
Load the library table using the path defined by aFileName aFallBackTable.
static std::map< std::string, UTF8 > ParseOptions(const std::string &aOptionsList)
Parses aOptionsList and places the result into a #PROPERTIES object which is returned.
STD_BITMAP_BUTTON * m_move_up_button
STD_BITMAP_BUTTON * m_append_button
STD_BITMAP_BUTTON * m_move_down_button
STD_BITMAP_BUTTON * m_delete_button
PANEL_FP_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)
Dialog to show and edit symbol library tables.
bool verifyTables()
Trim important fields, removes blank row entries, and checks for duplicates.
std::map< PCB_IO_MGR::PCB_FILE_T, IO_BASE::IO_FILE_DESC > m_supportedFpFiles
void onSizeGrid(wxSizeEvent &event) override
void moveUpHandler(wxCommandEvent &event) override
void adjustPathSubsGridColumns(int aWidth)
FP_LIB_TABLE_GRID * cur_model() const
FP_LIB_TABLE_GRID * project_model() const
void moveDownHandler(wxCommandEvent &event) override
wxArrayString m_pluginChoices
void setupGrid(WX_GRID *aGrid)
PANEL_FP_LIB_TABLE(DIALOG_EDIT_LIBRARY_TABLES *aParent, PROJECT *aProject)
FP_LIB_TABLE_GRID * global_model() const
void populateEnvironReadOnlyTable()
Populate the readonly environment variable table with names and values by examining all the full_uri ...
void deleteRowHandler(wxCommandEvent &event) override
void onReset(wxCommandEvent &event) override
void onMigrateLibraries(wxCommandEvent &event) override
void browseLibrariesHandler(wxCommandEvent &event)
bool TransferDataFromWindow() override
DIALOG_EDIT_LIBRARY_TABLES * m_parent
void OnUpdateUI(wxUpdateUIEvent &event) override
void onPageChange(wxBookCtrlEvent &event) override
void appendRowHandler(wxCommandEvent &event) override
static wxString GetDefaultUserFootprintsPath()
Gets the default path we point users to create projects.
Definition paths.cpp:92
wxString m_LastFootprintLibDir
static PLUGIN_REGISTRY * Instance()
Definition pcb_io_mgr.h:94
static PCB_IO * PluginFind(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
static bool ConvertLibrary(const std::map< std::string, UTF8 > &aOldFileProps, const wxString &aOldFilePath, const wxString &aNewFilePath, REPORTER *aReporter)
Convert a schematic symbol library to the latest KiCad format.
static PCB_FILE_T EnumFromStr(const wxString &aFileType)
Return the PCB_FILE_T from the corresponding plugin type name: "kicad", "legacy", etc.
PCB_FILE_T
The set of file types that the PCB_IO_MGR knows about, and for which there has been a plugin written,...
Definition pcb_io_mgr.h:56
@ KICAD_SEXP
S-expression Pcbnew file format.
Definition pcb_io_mgr.h:58
static PCB_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
Return a plugin type given a footprint library's libPath.
static const wxString ShowType(PCB_FILE_T aFileType)
Return a brief name for a plugin given aFileType enum.
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition pgm_base.cpp:783
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:130
static FP_LIB_TABLE * PcbFootprintLibs(PROJECT *aProject)
Return the table of footprint libraries without Kiway.
Container for project specific data.
Definition project.h:66
virtual const wxString FootprintLibTblName() const
Returns the path and filename of this project's footprint library table.
Definition project.cpp:195
wxString wx_str() const
Definition utf8.cpp:45
void Flush()
Build the HTML messages page.
bool HasMessage() const override
Returns true if any messages were reported.
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
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.
FP_LIB_TABLE GFootprintTable
The global footprint library table.
Definition cvpcb.cpp:150
#define _(s)
Declaration of the eda_3d_viewer class.
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_FOOTPRINT_VIEWER
Definition frame_type.h:45
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:43
@ FRAME_CVPCB
Definition frame_type.h:52
static const std::string KiCadFootprintLibPathExtension
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_ENABLED
@ COL_URI
This file contains miscellaneous commonly used macros and functions.
@ MAIL_RELOAD_LIB
Definition mail_type.h:57
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
Definition env_vars.cpp:77
void InvokePcbLibTableEditor(KIWAY *aKiway, wxWindow *aCaller)
Function InvokePcbLibTableEditor shows the modal DIALOG_FP_LIB_TABLE for purposes of editing the glob...
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
bool m_IsFile
Whether the library is a folder or a file.
Definition io_base.h:53
wxString FileFilter() const
Definition io_base.cpp:40
Implement a participant in the KIWAY alchemy.
Definition kiway.h:155
wxString message
wxString result
Test unit parsing edge cases and error handling.
Definition of file extensions used in Kicad.