KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_footprint_fields_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 Oliver Walters
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <advanced_config.h>
22#include <common.h>
23#include <base_units.h>
24#include <confirm.h>
25#include <eda_doc.h>
26#include <pcbnew_settings.h>
28#include <grid_tricks.h>
29#include <string_utils.h>
30#include <template_fieldnames.h>
31#include <kiface_base.h>
32#include <pcb_edit_frame.h>
33#include <footprint.h>
34#include <pcb_group.h>
35#include <widgets/wx_infobar.h>
39#include <widgets/wx_grid.h>
40#include <wx/debug.h>
41#include <wx/grid.h>
42#include <wx/textdlg.h>
43#include <wx/msgdlg.h>
47#include <board_commit.h>
48#include <project_pcb.h>
50#include <jobs/job_export_bom.h>
51#include <tool/tool_manager.h>
52#include <tools/pcb_actions.h>
54
55wxDEFINE_EVENT( EDA_EVT_CLOSE_DIALOG_FOOTPRINT_FIELDS_TABLE, wxCommandEvent );
56
58
59
60enum
61{
70};
71
73{
74public:
76 VIEW_CONTROLS_GRID_DATA_MODEL* aViewFieldsData,
78 EMBEDDED_FILES* aFiles ) :
79 FIELDS_TABLE_GRID_TRICKS( aParent, aGrid, aDataModel ),
80 m_dlg( aParent ),
81 m_viewControlsDataModel( aViewFieldsData ),
82 m_dataModel( aDataModel ),
83 m_files( aFiles )
84 {}
85
86protected:
87 bool toggleCell( int aRow, int aCol, bool aPreserveSelection = false ) override
88 {
89 if( !m_grid->IsEditable() || m_dataModel->IsCellReadOnly( aRow, aCol ) )
90 return false;
91
92 return GRID_TRICKS::toggleCell( aRow, aCol, aPreserveSelection );
93 }
94
95 void showFieldsTablePopupMenu( wxMenu& aMenu, wxGridEvent& aEvent ) override
96 {
97 int row = m_grid->GetGridCursorRow();
98 int col = m_grid->GetGridCursorCol();
99
100 if( row >= 0 && col >= 0 )
101 {
102 if( m_dataModel->GetColFieldName( col ) == GetDefaultFieldName( FIELD_T::DATASHEET, UNTRANSLATED ) )
103 {
104 aMenu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ), _( "Show datasheet in browser" ) );
105 aMenu.AppendSeparator();
106 }
107 }
108
109 GRID_TRICKS::showPopupMenu( aMenu, aEvent );
110 }
111
112 void doFieldsTablePopupSelection( wxCommandEvent& aEvent ) override
113 {
114 int row = m_grid->GetGridCursorRow();
115 int col = m_grid->GetGridCursorCol();
116
117 if( aEvent.GetId() == MYID_SHOW_DATASHEET )
118 {
119 wxString datasheetUri = m_grid->GetCellValue( row, col );
120 GetAssociatedDocument( m_dlg, datasheetUri, &m_dlg->Prj(), nullptr, { m_files } );
121 }
122 else if( aEvent.GetId() >= GRIDTRICKS_FIRST_SHOWHIDE )
123 {
124 if( !m_grid->CommitPendingChanges( false ) )
125 return;
126
127 // Pop-up column order is the order of the shown fields, not the viewControls order
128 col = aEvent.GetId() - GRIDTRICKS_FIRST_SHOWHIDE;
129
130 bool show = !m_dataModel->GetShowColumn( col );
131
132 m_dlg->ShowHideColumn( col, show );
133
134 wxString fieldName = m_dataModel->GetColFieldName( col );
135
136 for( row = 0; row < m_viewControlsDataModel->GetNumberRows(); row++ )
137 {
138 if( m_viewControlsDataModel->GetUntranslatedFieldName( row ) == fieldName )
139 m_viewControlsDataModel->SetValueAsBool( row, SHOW_FIELD_COLUMN, show );
140 }
141
142 if( m_viewControlsDataModel->GetView() )
143 m_viewControlsDataModel->GetView()->ForceRefresh();
144 }
145 else
146 {
148 }
149 }
150
151private:
156};
157
158
160 DIALOG_FIELDS_TABLE( aParent, aParent->GetPcbNewSettings()->m_FieldEditorPanel,
161 aParent->GetBoard()->GetDesignSettings(), aJob ),
162 m_parent( aParent ),
163 m_templateFieldNames( aParent->Prj().GetProjectFile().m_TemplateFieldNames )
164{
165 // Get all footprints from the list of board sheets
166 for( FOOTPRINT* footprint : m_parent->GetBoard()->Footprints() )
167 m_footprintsList.emplace_back( *footprint );
168
170
171 m_grid->UseNativeColHeader( true );
172 m_grid->SetTable( m_dataModel, true );
173
174 // The field-list grid regroups its rows, so the dialog's position-based Ctrl+Z would shift
175 // values onto the wrong field.
177
178 // must be done after SetTable(), which appears to re-set it
179 m_grid->SetSelectionMode( wxGrid::wxGridSelectCells );
180
181 // add Cut, Copy, and Paste to wxGrid
182 m_grid->PushEventHandler( new FOOTPRINT_FIELDS_EDITOR_GRID_TRICKS(
183 this, m_grid, m_viewControlsDataModel, m_dataModel, m_parent->GetBoard()->GetEmbeddedFiles() ) );
184
185 m_variantListBox->Set( m_parent->GetBoard()->GetVariantNamesForUI() );
186
187 // A job keeps its own variant, otherwise follow the board.
188 wxString variantToSelect;
189
190 if( m_job )
191 variantToSelect = m_job->GetSelectedVariant();
192 else
193 variantToSelect = m_parent->GetBoard()->GetCurrentVariant();
194
195 if( !variantToSelect.IsEmpty() )
196 {
197 int toSelect = m_variantListBox->FindString( variantToSelect );
198
199 if( toSelect == wxNOT_FOUND )
200 m_variantListBox->SetSelection( 0 );
201 else
202 m_variantListBox->SetSelection( toSelect );
203 }
204 else
205 {
206 m_variantListBox->SetSelection( 0 );
207 }
208
210
211 if( m_job )
212 SetTitle( m_job->GetSettingsDialogTitle() );
213 else
214 SetTitle( _( "Footprint Fields Table" ) );
215
216 m_buttonApply->SetLabel( _( "Apply, Save Board && Continue" ) );
217
218 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
219 // non-job versions (which have different sizes).
220 m_hash_key = TO_UTF8( GetTitle() );
221
222 // Set the current variant for highlighting variant-specific field values
223 m_dataModel->SetCurrentVariant( resolveVariant() );
224
225 // Disable variant editing controls in for footprint fields table, variants come only from the schematic
226 m_addVariantButton->Hide();
227 m_copyVariantButton->Hide();
228 m_renameVariantButton->Hide();
230 m_deleteVariantButton->Hide();
231
233 m_grid->ClearSelection();
234
236
238
239 SetSize( GetDefaultDialogSize() );
240
242
244
245 if( m_job )
246 m_outputFileName->SetValue( m_job->GetConfiguredOutputPath() );
247 else
248 m_outputFileName->SetValue( m_cfgBomSettings.m_BomExportFileName );
249
250 Center();
251
252 // Connect Events
253 m_grid->Bind( wxEVT_GRID_COL_SORT, &DIALOG_FOOTPRINT_FIELDS_TABLE::OnColSort, this );
254 m_grid->Bind( wxEVT_GRID_COL_MOVE, &DIALOG_FOOTPRINT_FIELDS_TABLE::OnColMove, this );
255 m_grid->GetGridWindow()->Bind( wxEVT_MOTION, &DIALOG_FOOTPRINT_FIELDS_TABLE::OnGridMouseMove, this );
258
259 if( !m_job )
260 {
261 // Start listening for board changes
262 m_parent->GetBoard()->AddListener( this );
263 m_parent->Bind( EDA_EVT_PCB_LAST_SCH_SHEET_CHANGED,
265 }
266 else
267 {
268 // Don't allow editing
269 m_grid->EnableEditing( false );
270 m_buttonApply->Hide();
271 m_buttonExport->Hide();
272 }
273}
274
275
277{
278 if( m_aborted )
279 return;
280
281 if( !m_job )
282 {
283 m_parent->Unbind( EDA_EVT_PCB_LAST_SCH_SHEET_CHANGED,
285 }
286
289
290 // Disconnect Events
291 m_grid->GetGridWindow()->Unbind( wxEVT_MOTION, &DIALOG_FOOTPRINT_FIELDS_TABLE::OnGridMouseMove, this );
292 m_grid->Unbind( wxEVT_GRID_COL_SORT, &DIALOG_FOOTPRINT_FIELDS_TABLE::OnColSort, this );
293 m_grid->Unbind( wxEVT_GRID_COL_MOVE, &DIALOG_FOOTPRINT_FIELDS_TABLE::OnColMove, this );
296
297 // Delete the GRID_TRICKS.
298 m_grid->PopEventHandler( true );
299
300 // we gave ownership of m_viewControlsDataModel & m_dataModel to the wxGrids...
301}
302
303
305{
306 return new GRID_CELL_URL_EDITOR( this, nullptr, { m_parent->GetBoard() } );
307}
308
309
311{
312 if( !wxDialog::TransferDataToWindow() )
313 return false;
314
315 LoadFieldNames(); // loads rows into m_viewControlsDataModel and columns into m_dataModel
316
317 // Load our BOM view presets
318 SetUserBomPresets( m_cfgBomSettings.m_BomPresets );
319
320 BOM_PRESET preset = m_cfgBomSettings.m_BomSettings;
321
322 if( m_job )
323 loadJobBomPreset( *m_job, preset );
324
325 ApplyBomPreset( preset );
327
328 // Load BOM export format presets
329 SetUserBomFmtPresets( m_cfgBomSettings.m_BomFmtPresets );
330 BOM_FMT_PRESET fmtPreset = m_cfgBomSettings.m_BomFmtSettings;
331
332 if( m_job )
333 loadJobBomFmtPreset( *m_job, fmtPreset );
334
335 ApplyBomFmtPreset( fmtPreset );
337
338 if( !m_job )
339 m_outputFileName->SetValue( m_cfgBomSettings.m_BomExportFileName );
340
341 TOOL_MANAGER* toolManager = m_parent->GetToolManager();
342 PCB_SELECTION_TOOL* selectionTool = toolManager->GetTool<PCB_SELECTION_TOOL>();
343 PCB_SELECTION& selection = selectionTool->GetSelection();
344 FOOTPRINT* footprint = nullptr;
345
346 m_dataModel->SetGroupingEnabled( m_groupSymbolsBox->GetValue() );
347
348 setScope( static_cast<SCOPE>( m_scope->GetSelection() ) );
349
350 if( selection.GetSize() == 1 )
351 {
352 EDA_ITEM* item = selection.Front();
353
354 if( item->Type() == PCB_FOOTPRINT_T )
355 footprint = static_cast<FOOTPRINT*>( item );
356 else if( item->GetParent() && item->GetParent()->Type() == PCB_FOOTPRINT_T )
357 footprint = static_cast<FOOTPRINT*>( item->GetParent() );
358 }
359
360 if( footprint )
361 {
362 for( int row = 0; row < m_dataModel->GetNumberRows(); ++row )
363 {
364 std::vector<FOOTPRINT_REF> references = m_dataModel->GetRowReferences( row );
365 bool found = false;
366
367 for( const FOOTPRINT_REF& ref : references )
368 {
369 if( &ref.GetFootprint() == footprint )
370 {
371 found = true;
372 break;
373 }
374 }
375
376 if( found )
377 {
378 // Find the value column and the reference column if they're shown
379 int valueCol = -1;
380 int refCol = -1;
381 int anyCol = -1;
382
383 for( int col = 0; col < m_dataModel->GetNumberCols(); col++ )
384 {
385 if( m_dataModel->ColIsValue( col ) )
386 valueCol = col;
387 else if( m_dataModel->ColIsReference( col ) )
388 refCol = col;
389 else if( anyCol == -1 && m_dataModel->GetShowColumn( col ) )
390 anyCol = col;
391 }
392
393 if( valueCol != -1 && m_dataModel->GetShowColumn( valueCol ) )
394 m_grid->GoToCell( row, valueCol );
395 else if( refCol != -1 && m_dataModel->GetShowColumn( refCol ) )
396 m_grid->GoToCell( row, refCol );
397 else if( anyCol != -1 )
398 m_grid->GoToCell( row, anyCol );
399
400 break;
401 }
402 }
403 }
404
405 // We don't want table range selection events to happen until we've loaded the data or we
406 // we'll clear our selection as the grid is built before the code above can get the
407 // user's current selection.
409
410 return true;
411}
412
413
415{
416 if( !m_grid->CommitPendingChanges() )
417 return false;
418
419 if( !wxDialog::TransferDataFromWindow() )
420 return false;
421
422 if( m_job )
423 {
424 // and exit, don't even dream of saving changes from the data model
425 return true;
426 }
427
428 BOARD_COMMIT commit( m_parent );
429 wxString currentVariant = m_parent->GetBoard()->GetCurrentVariant();
430
431 m_dataModel->ApplyData( commit, m_templateFieldNames, currentVariant );
432
433 if( !commit.Empty() )
434 {
435 commit.Push( wxS( "Footprint Fields Table Edit" ) ); // Push clears the commit buffer.
436 m_parent->OnModify();
437 }
438
439 // Reset the view to where we left the user
440 m_parent->Refresh();
441
442 return true;
443}
444
445
447{
448 auto addMandatoryField =
449 [&]( FIELD_T aFieldId, bool aShow, bool aGroupBy )
450 {
451 m_mandatoryFieldListIndexes[aFieldId] = m_viewControlsDataModel->GetNumberRows();
452
454 aShow, aGroupBy );
455 };
456
457 // Add mandatory fields first show groupBy
458 addMandatoryField( FIELD_T::REFERENCE, true, true );
459 addMandatoryField( FIELD_T::VALUE, true, true );
460 addMandatoryField( FIELD_T::FOOTPRINT, true, true );
461 addMandatoryField( FIELD_T::DATASHEET, true, false );
462 addMandatoryField( FIELD_T::DESCRIPTION, false, false );
463
464 // Generated fields present only in the fields table
467
468 // User field names are stored and matched case-sensitively (see issue #24021), so each
469 // distinct name gets its own column rather than collapsing case variants together.
470 std::set<wxString> userFieldNames;
471
472 for( const FOOTPRINT_REF& ref : m_footprintsList )
473 {
474 FOOTPRINT& footprint = ref.GetFootprint();
475
476 for( const PCB_FIELD* field : footprint.GetFields() )
477 {
478 if( !field->IsMandatory() && !field->IsPrivate() )
479 userFieldNames.insert( field->GetName() );
480 }
481 }
482
483 for( const wxString& fieldName : userFieldNames )
484 AddField( fieldName, GetGeneratedFieldDisplayName( fieldName ), true, false );
485
486 // Add any templateFieldNames which aren't already present.
487 for( const TEMPLATE_FIELDNAME& templateField : m_templateFieldNames.GetResolvedTemplateFieldNames() )
488 {
489 if( userFieldNames.count( templateField.m_Name ) == 0 )
490 AddField( templateField.m_Name, GetGeneratedFieldDisplayName( templateField.m_Name ), false, false );
491 }
492}
493
494
496{
497 m_dataModel->SetPath( m_parent->GetLastSchematicSheetPath() );
498 m_dataModel->SetScope( aScope );
499
500 if( aScope == SCOPE::SCOPE_SELECTION )
502
503 m_dataModel->RebuildRows();
504}
505
506
508{
509 std::unordered_set<KIID_PATH> selectionItems;
510 PCB_SELECTION_TOOL* selectionTool = m_parent->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
511 const PCB_SELECTION& selection = selectionTool->GetSelection();
512
513 auto addSelectionItem = [&]( EDA_ITEM* aItem )
514 {
515 FOOTPRINT* footprint = nullptr;
516
517 if( aItem->Type() == PCB_FOOTPRINT_T )
518 footprint = static_cast<FOOTPRINT*>( aItem );
519 else if( aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
520 footprint = static_cast<FOOTPRINT*>( aItem->GetParent() );
521
522 if( footprint )
523 {
525 path.push_back( footprint->m_Uuid );
526 selectionItems.insert( path );
527 }
528 };
529
530 for( EDA_ITEM* item : selection )
531 {
532 if( item->Type() == PCB_GROUP_T )
533 static_cast<PCB_GROUP*>( item )->RunOnChildren( addSelectionItem, RECURSE_MODE::RECURSE );
534 else
535 addSelectionItem( item );
536 }
537
538 m_dataModel->SetSelectionItems( selectionItems );
539}
540
541
542void DIALOG_FOOTPRINT_FIELDS_TABLE::OnScope( wxCommandEvent& aEvent )
543{
544 switch( aEvent.GetSelection() )
545 {
546 case 0: setScope( SCOPE::SCOPE_ALL ); break;
547 case 1: setScope( SCOPE::SCOPE_SHEET ); break;
548 case 2: setScope( SCOPE::SCOPE_SHEET_RECURSIVE ); break;
549 case 3: setScope( SCOPE::SCOPE_SELECTION ); break;
550 }
551}
552
553
554void DIALOG_FOOTPRINT_FIELDS_TABLE::OnMenu( wxCommandEvent& aEvent )
555{
556 // Build a pop menu:
557 wxMenu menu;
558
559 menu.Append( MYID_INCLUDE_DNP, _( "Include 'DNP' Footprints" ),
560 _( "Show footprints marked 'DNP' in the table. This setting also controls whether or not 'DNP' "
561 "footprints are included on export." ),
562 wxITEM_CHECK );
563 menu.Check( MYID_INCLUDE_DNP, !m_dataModel->GetExcludeDNP() );
564
565 menu.Append( MYID_INCLUDE_EXCLUDED_FROM_BOM, _( "Include 'Exclude from BOM' Footprints" ),
566 _( "Show footprints marked 'Exclude from BOM' in the table. Footprints marked 'Exclude from BOM' "
567 "are never included on export." ),
568 wxITEM_CHECK );
569 menu.Check( MYID_INCLUDE_EXCLUDED_FROM_BOM, m_dataModel->GetIncludeExcludedFromBOM() );
570
571 menu.AppendSeparator();
572
573 menu.Append( MYID_HIGHLIGHT_ON_CROSS_PROBE, _( "Highlight on Cross-probe" ),
574 _( "Highlight corresponding item on canvas when it is selected in the table" ),
575 wxITEM_CHECK );
576 menu.Check( MYID_HIGHLIGHT_ON_CROSS_PROBE, m_cfgDialogSettings.selection_mode == 0 );
577
578 menu.Append( MYID_SELECT_ON_CROSS_PROBE, _( "Select on Cross-probe" ),
579 _( "Select corresponding item on canvas when it is selected in the table" ),
580 wxITEM_CHECK );
581 menu.Check( MYID_SELECT_ON_CROSS_PROBE, m_cfgDialogSettings.selection_mode == 1 );
582
583 // menuId is the selected submenu id from the popup menu or wxID_NONE
584 int menuId = m_bMenu->GetPopupMenuSelectionFromUser( menu );
585
586 if( menuId == 0 || menuId == MYID_INCLUDE_DNP )
587 {
588 m_dataModel->SetExcludeDNP( !m_dataModel->GetExcludeDNP() );
589 m_dataModel->RebuildRows();
590 m_grid->ForceRefresh();
591
593 }
594 else if( menuId == 1 || menuId == MYID_INCLUDE_EXCLUDED_FROM_BOM )
595 {
596 m_dataModel->SetIncludeExcludedFromBOM( !m_dataModel->GetIncludeExcludedFromBOM() );
597 m_dataModel->RebuildRows();
598 m_grid->ForceRefresh();
599
601 }
602 else if( menuId == 3 || menuId == MYID_HIGHLIGHT_ON_CROSS_PROBE )
603 {
604 if( m_cfgDialogSettings.selection_mode != 0 )
605 m_cfgDialogSettings.selection_mode = 0;
606 else
607 m_cfgDialogSettings.selection_mode = 2;
608 }
609 else if( menuId == 4 || menuId == MYID_SELECT_ON_CROSS_PROBE )
610 {
611 if( m_cfgDialogSettings.selection_mode != 1 )
612 m_cfgDialogSettings.selection_mode = 1;
613 else
614 m_cfgDialogSettings.selection_mode = 2;
615 }
616}
617
618
620{
621 // Cross-probing should only work in Edit page
622 if( m_nbPages->GetSelection() != 0 )
623 return;
624
625 // Cross-probing is disabled when we're in selection scope mode, otherwise
626 // we're just in a loop
627 if( m_dataModel->GetScope() == SCOPE::SCOPE_SELECTION )
628 return;
629
630 // Multi-select can grab the rows that are expanded child refs, and also the row
631 // containing the list of all child refs. Make sure we add refs/footprints uniquely
632 std::set<BOARD_ITEM*> footprints;
633
634 for( int row : aRows )
635 {
636 for( const FOOTPRINT_REF& ref : m_dataModel->GetRowReferences( row ) )
637 footprints.insert( &ref.GetFootprint() );
638 }
639
640 std::vector<BOARD_ITEM*> focusItems( footprints.begin(), footprints.end() );
641
642 if( m_cfgDialogSettings.selection_mode == 0 )
643 {
644 m_parent->FocusOnItems( focusItems );
645 }
646 else if( m_cfgDialogSettings.selection_mode == 1 )
647 {
648 m_parent->GetToolManager()->RunAction( PCB_ACTIONS::syncSelection, &focusItems );
649 }
650}
651
652
654{
656 {
657 m_cfgBomSettings.m_BomExportFileName = m_outputFileName->GetValue();
658 m_parent->SaveBoard();
659 ClearModify();
660 }
661}
662
663
664void DIALOG_FOOTPRINT_FIELDS_TABLE::OnCancel( wxCommandEvent& aEvent )
665{
666 if( m_job )
667 {
668 EndModal( wxID_CANCEL );
669 }
670 else
671 {
672 // Discard any unsaved edit in the output filename field
673 m_outputFileName->SetValue( m_cfgBomSettings.m_BomExportFileName );
674 Close();
675 }
676}
677
678
679void DIALOG_FOOTPRINT_FIELDS_TABLE::OnOk( wxCommandEvent& aEvent )
680{
682 return;
683
684 if( m_job )
685 {
687 EndModal( wxID_OK );
688 }
689 else
690 {
691 if( m_cfgBomSettings.m_BomExportFileName != m_outputFileName->GetValue() )
692 {
693 m_cfgBomSettings.m_BomExportFileName = m_outputFileName->GetValue();
694 m_parent->OnModify();
695 }
696
697 Close();
698 }
699}
700
701
702void DIALOG_FOOTPRINT_FIELDS_TABLE::OnClose( wxCloseEvent& aEvent )
703{
704 if( m_job )
705 {
706 aEvent.Skip();
707 return;
708 }
709
710 m_grid->CommitPendingChanges( true );
711
712 if( m_dataModel->IsEdited() && aEvent.CanVeto() )
713 {
714 if( !HandleUnsavedChanges( this, _( "Save changes?" ),
715 [&]() -> bool
716 {
717 return TransferDataFromWindow();
718 } ) )
719 {
720 aEvent.Veto();
721 return;
722 }
723 }
724
725 if( savePresets( true ) )
726 m_parent->OnModify();
727
728 // Stop listening to board events
729 m_parent->GetBoard()->RemoveListener( this );
730 m_parent->ClearFocus();
731
732 wxCommandEvent* event = new wxCommandEvent( EDA_EVT_CLOSE_DIALOG_FOOTPRINT_FIELDS_TABLE, wxID_ANY );
733
734 if( wxWindow* parentWindow = GetParent() )
735 wxQueueEvent( parentWindow, event );
736}
737
738
739void DIALOG_FOOTPRINT_FIELDS_TABLE::OnBoardItemsAdded( BOARD& aPcb, std::vector<BOARD_ITEM*>& aPcbItem )
740{
741 FOOTPRINT_REFERENCE_LIST addedRefs;
742
743 for( BOARD_ITEM* item : aPcbItem )
744 {
745 if( item->Type() == PCB_FOOTPRINT_T )
746 addedRefs.push_back( FOOTPRINT_REF( *static_cast<FOOTPRINT*>( item ) ) );
747 }
748
749 bool selectionScope = m_dataModel->GetScope() == SCOPE::SCOPE_SELECTION;
750
751 if( addedRefs.empty() && !selectionScope )
752 return;
753
754 std::set<KIID_PATH> savedSelection = SaveGridSelection();
755
756 for( FOOTPRINT_REF& ref : addedRefs )
757 {
758 // Add all fields again in case this footprint has a new one
759 for( PCB_FIELD* field : ref.GetFootprint().GetFields() )
760 {
761 if( !field->IsMandatory() && !field->IsPrivate() )
762 AddField( field->GetUntranslatedName(), field->GetName(), true, false, false );
763 }
764 }
765
766
767 m_dataModel->AddReferences( addedRefs );
768 rebuildRowsPreservingSelection( savedSelection );
769}
770
771
772void DIALOG_FOOTPRINT_FIELDS_TABLE::OnBoardItemsRemoved( BOARD& aPcb, std::vector<BOARD_ITEM*>& aPcbItem )
773{
774 std::set<KIID_PATH> savedSelection = SaveGridSelection();
775
776 for( BOARD_ITEM* item : aPcbItem )
777 {
778 if( item->Type() == PCB_FOOTPRINT_T )
779 m_dataModel->RemoveFootprint( FOOTPRINT_REF( *static_cast<FOOTPRINT*>( item ) ) );
780 }
781
782 rebuildRowsPreservingSelection( savedSelection );
783}
784
785
786void DIALOG_FOOTPRINT_FIELDS_TABLE::OnBoardItemsChanged( BOARD& aPcb, std::vector<BOARD_ITEM*>& aPcbItem )
787{
788 FOOTPRINT_REFERENCE_LIST changedRefs;
789
790 for( BOARD_ITEM* item : aPcbItem )
791 {
792 if( item->Type() == PCB_FOOTPRINT_T )
793 changedRefs.push_back( FOOTPRINT_REF( *static_cast<FOOTPRINT*>( item ) ) );
794 }
795
796 bool selectionScope = m_dataModel->GetScope() == SCOPE::SCOPE_SELECTION;
797
798 if( changedRefs.empty() && !selectionScope )
799 return;
800
801 std::set<KIID_PATH> savedSelection = SaveGridSelection();
802
803 for( FOOTPRINT_REF& ref : changedRefs )
804 {
805 // Add all fields again in case this footprint has a new one
806 for( PCB_FIELD* field : ref.GetFootprint().GetFields() )
807 {
808 if( !field->IsMandatory() && !field->IsPrivate() )
809 AddField( field->GetUntranslatedName(), field->GetName(), true, false, false );
810 }
811 }
812
813
814 m_dataModel->UpdateReferences( changedRefs );
815 rebuildRowsPreservingSelection( savedSelection );
816}
817
818
820{
821 wxUnusedVar( aEvent );
822
823 m_dataModel->SetPath( m_parent->GetLastSchematicSheetPath() );
824
825 if( m_dataModel->GetScope() != SCOPE::SCOPE_ALL )
827}
828
829
831{
832 if( m_dataModel->GetScope() == SCOPE::SCOPE_SELECTION )
834}
835
836
841
842
843void DIALOG_FOOTPRINT_FIELDS_TABLE::rebuildRowsPreservingSelection( const std::set<KIID_PATH>& aSavedSelection )
844{
846
847 if( m_dataModel->GetScope() == SCOPE::SCOPE_SELECTION )
849
850 m_dataModel->RebuildRows();
851 RestoreGridSelection( aSavedSelection );
852
854}
855
856
858{
859 return;
860}
861
862
864{
865 return;
866}
867
868
870{
871 return;
872}
873
874
876{
877 return;
878}
879
880
882{
883 return;
884}
885
886
888{
889 wxString currentVariant;
890 wxString selectedVariant = getSelectedVariant();
891
893
894 if( m_job )
895 {
896 m_grid->CommitPendingChanges( true );
897
898 if( m_parent )
899 m_parent->SetCurrentVariant( selectedVariant );
900
901 m_dataModel->SetCurrentVariant( selectedVariant );
902 m_dataModel->UpdateReferences( m_dataModel->GetReferenceList() );
903 m_dataModel->RebuildRows();
904
905 if( m_nbPages->GetSelection() == 1 )
907 else
908 m_grid->ForceRefresh();
909
911 return;
912 }
913
914 if( m_parent )
915 {
916 currentVariant = m_parent->GetBoard()->GetCurrentVariant();
917
918 if( currentVariant != selectedVariant )
919 m_parent->SetCurrentVariant( selectedVariant );
920 }
921
922 // TODO: this is probably the wrong method in both the symbol and footprint fields tables,
923 // changing the variant should ask the user whether to apply the changes to the board.
924 // The rest of the time in the fields table, no data is pushed to the sch/board until the user
925 // explicity clicks Apply or Ok.
926 if( currentVariant != selectedVariant )
927 {
928 m_grid->CommitPendingChanges( true );
929
930 BOARD_COMMIT commit( m_parent );
931
932 m_dataModel->ApplyData( commit, m_templateFieldNames, currentVariant );
933
934 if( !commit.Empty() )
935 {
936 commit.Push( wxS( "Footprint Fields Table Edit" ) ); // Push clears the commit buffer.
937 m_parent->OnModify();
938 }
939
940 // Update the data model's current variant for field highlighting
941 m_dataModel->SetCurrentVariant( selectedVariant );
942 m_dataModel->UpdateReferences( m_dataModel->GetReferenceList() );
943 m_dataModel->RebuildRows();
944
945 if( m_nbPages->GetSelection() == 1 )
947 else
948 m_grid->ForceRefresh();
949
951 }
952}
953
954
956{
957 // All variant modifications are disabled for the footprint fields table
958 m_addVariantButton->Enable( false );
959 m_copyVariantButton->Enable( false );
960 m_renameVariantButton->Enable( false );
961 m_editVariantDescButton->Enable( false );
962 m_deleteVariantButton->Enable( false );
963}
964
965
967{
968 // A job keeps its own variant, otherwise follow the board.
969 if( m_job )
970 return getSelectedVariant();
971
972 return m_parent->GetBoard()->GetCurrentVariant();
973}
974
975
977{
978 return m_parent->GetBoard()->ResolveTextVar( aToken, 0 );
979}
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
bool Empty() const
Definition commit.h:142
STD_BITMAP_BUTTON * m_addVariantButton
STD_BITMAP_BUTTON * m_renameVariantButton
STD_BITMAP_BUTTON * m_copyVariantButton
STD_BITMAP_BUTTON * m_deleteVariantButton
STD_BITMAP_BUTTON * m_editVariantDescButton
void saveJobSettings(JOB_EXPORT_BOM &aJob)
void SetUserBomFmtPresets(std::vector< BOM_FMT_PRESET > &aPresetList)
wxSize GetDefaultDialogSize() const
void OnColMove(wxGridEvent &aEvent)
void OnColSort(wxGridEvent &aEvent)
void OnGridMouseMove(wxMouseEvent &aEvent)
bool savePresets(bool aSaveCurrentSettings)
wxString getSelectedVariant() const
void RestoreGridSelection(const std::set< KIID_PATH > &aItemKeys)
Restore a selection previously returned by SaveGridSelection().
std::map< FIELD_T, int > m_mandatoryFieldListIndexes
void onBomFmtPresetChanged(wxCommandEvent &aEvent)
void SetUserBomPresets(std::vector< BOM_PRESET > &aPresetList)
void ApplyBomFmtPreset(const wxString &aPresetName)
DIALOG_FIELDS_TABLE(wxWindow *aParent, FIELDS_TABLE_SETTINGS &aPanelSettings, FIELDS_TABLE_BOM_SETTINGS &aBomSettings, JOB_EXPORT_BOM *aJob)
FIELDS_TABLE_BOM_SETTINGS & m_cfgBomSettings
static void loadJobBomFmtPreset(const JOB_EXPORT_BOM &aJob, BOM_FMT_PRESET &aPreset)
FIELDS_TABLE_SETTINGS & m_cfgDialogSettings
static void loadJobBomPreset(const JOB_EXPORT_BOM &aJob, BOM_PRESET &aPreset)
void onBomPresetChanged(wxCommandEvent &aEvent)
std::set< KIID_PATH > SaveGridSelection()
Save the grid selection by stable item identity so it can survive a row rebuild.
void ApplyBomPreset(const wxString &aPresetName)
VIEW_CONTROLS_GRID_DATA_MODEL * m_viewControlsDataModel
void AddField(const wxString &aFieldName, const wxString &aLabelValue, bool aShow, bool aGroupBy, bool aAddedByUser=false)
bool resolveTextVar(wxString *aToken) const override
void onAddVariant(wxCommandEvent &aEvent) override
void OnClose(wxCloseEvent &aEvent) override
void OnSaveAndContinue(wxCommandEvent &aEvent) override
void setScope(FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE aScope)
DIALOG_FOOTPRINT_FIELDS_TABLE(PCB_EDIT_FRAME *aParent, JOB_EXPORT_BOM *aJob=nullptr)
void OnTableSelectionChanged(const std::set< int > &aRows) override
void OnCancel(wxCommandEvent &aEvent) override
void OnMenu(wxCommandEvent &aEvent) override
void onRenameVariant(wxCommandEvent &aEvent) override
void OnBoardItemsAdded(BOARD &aPcb, std::vector< BOARD_ITEM * > &aPcbItem) override
void OnOk(wxCommandEvent &aEvent) override
void onDeleteVariant(wxCommandEvent &aEvent) override
void OnBoardItemsRemoved(BOARD &aPcb, std::vector< BOARD_ITEM * > &aPcbItem) override
void OnBoardSelectionChanged(BOARD &aPcb) override
FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL * m_dataModel
void onCopyVariant(wxCommandEvent &aEvent) override
void OnBoardItemsChanged(BOARD &aPcb, std::vector< BOARD_ITEM * > &aPcbItem) override
void LoadFieldNames()
Construct the rows of m_fieldsCtrl and the columns of m_dataModel from a union of all field names in ...
void onVariantSelectionChange(wxCommandEvent &aEvent) override
void onEditVariantDescription(wxCommandEvent &aEvent) override
void OnCurrentSchematicSheetChanged(wxCommandEvent &aEvent)
void OnScope(wxCommandEvent &aEvent) override
wxGridCellEditor * createDatasheetEditor() override
void ExcludeFromControlUndoRedo(wxWindow *aWindow)
Opt a control out of the dialog's generic Ctrl+Z/Ctrl+Y undo/redo.
void OptOut(wxWindow *aWindow)
Opt out of control state saving.
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:94
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const KIID m_Uuid
Definition eda_item.h:597
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM * GetParent() const
Definition eda_item.h:112
static const wxString ITEM_NUMBER_VARIABLE
FIELDS_TABLE_GRID_TRICKS(DIALOG_FIELDS_TABLE *aDialog, WX_GRID *aGrid, FIELDS_TABLE_DATA_MODEL_BASE *aDataModel)
static constexpr int FIRST_CLIENT_ID
bool toggleCell(int aRow, int aCol, bool aPreserveSelection=false) override
VIEW_CONTROLS_GRID_DATA_MODEL * m_viewControlsDataModel
FOOTPRINT_FIELDS_EDITOR_GRID_TRICKS(DIALOG_FOOTPRINT_FIELDS_TABLE *aParent, WX_GRID *aGrid, VIEW_CONTROLS_GRID_DATA_MODEL *aViewFieldsData, FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL *aDataModel, EMBEDDED_FILES *aFiles)
FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL * m_dataModel
void showFieldsTablePopupMenu(wxMenu &aMenu, wxGridEvent &aEvent) override
void doFieldsTablePopupSelection(wxCommandEvent &aEvent) override
This is the minimal equivalent to the SCH_REFERENCE so we can provide similar non-null guarantees thr...
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
virtual void doPopupSelection(wxCommandEvent &event)
virtual void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent)
WX_GRID * m_grid
I don't own the grid, but he owns me.
virtual bool toggleCell(int aRow, int aCol, bool aPreserveSelection=false)
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
virtual wxString GetFootprint()
For items with footprint fields.
static TOOL_ACTION syncSelection
Sets selection to specified items, zooms to fit, if enabled.
Definition pcb_actions.h:62
The main frame for Pcbnew.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:51
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
Master controller class:
wxString GetGeneratedFieldDisplayName(const wxString &aSource)
Returns any variables unexpanded, e.g.
Definition common.cpp:481
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition confirm.cpp:146
This file is part of the common library.
wxDEFINE_EVENT(EDA_EVT_CLOSE_DIALOG_FOOTPRINT_FIELDS_TABLE, wxCommandEvent)
LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE SCOPE
@ MYID_INCLUDE_EXCLUDED_FROM_BOM
@ MYID_HIGHLIGHT_ON_CROSS_PROBE
#define _(s)
bool GetAssociatedDocument(wxWindow *aParent, const wxString &aDocName, PROJECT *aProject, SEARCH_STACK *aPaths, std::vector< EMBEDDED_FILES * > aFilesStack)
Open a document (file) with the suitable browser.
Definition eda_doc.cpp:59
This file is part of the common library.
@ RECURSE
Definition eda_item.h:51
std::vector< FOOTPRINT_REF > FOOTPRINT_REFERENCE_LIST
@ GRIDTRICKS_FIRST_SHOWHIDE
Definition grid_tricks.h:47
Class to handle a set of BOARD_ITEMs.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Hold a name of a symbol's field, field value, and default visibility.
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
@ UNTRANSLATED
@ TRANSLATED
std::string path
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:103
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:78