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
430 m_dataModel->ApplyData( commit, m_templateFieldNames );
431
432 if( !commit.Empty() )
433 {
434 commit.Push( wxS( "Footprint Fields Table Edit" ) ); // Push clears the commit buffer.
435 m_parent->OnModify();
436 }
437
438 // Reset the view to where we left the user
439 m_parent->Refresh();
440
441 return true;
442}
443
444
446{
447 auto addMandatoryField =
448 [&]( FIELD_T aFieldId, bool aShow, bool aGroupBy )
449 {
450 m_mandatoryFieldListIndexes[aFieldId] = m_viewControlsDataModel->GetNumberRows();
451
453 aShow, aGroupBy );
454 };
455
456 // Add mandatory fields first show groupBy
457 addMandatoryField( FIELD_T::REFERENCE, true, true );
458 addMandatoryField( FIELD_T::VALUE, true, true );
459 addMandatoryField( FIELD_T::FOOTPRINT, true, true );
460 addMandatoryField( FIELD_T::DATASHEET, true, false );
461 addMandatoryField( FIELD_T::DESCRIPTION, false, false );
462
463 // Generated fields present only in the fields table
466
467 // User field names are stored and matched case-sensitively (see issue #24021), so each
468 // distinct name gets its own column rather than collapsing case variants together.
469 std::set<wxString> userFieldNames;
470
471 for( const FOOTPRINT_REF& ref : m_footprintsList )
472 {
473 FOOTPRINT& footprint = ref.GetFootprint();
474
475 for( const PCB_FIELD* field : footprint.GetFields() )
476 {
477 if( !field->IsMandatory() && !field->IsPrivate() )
478 userFieldNames.insert( field->GetName() );
479 }
480 }
481
482 for( const wxString& fieldName : userFieldNames )
483 AddField( fieldName, GetGeneratedFieldDisplayName( fieldName ), true, false );
484
485 // Add any templateFieldNames which aren't already present.
486 for( const TEMPLATE_FIELDNAME& templateField : m_templateFieldNames.GetResolvedTemplateFieldNames() )
487 {
488 if( userFieldNames.count( templateField.m_Name ) == 0 )
489 AddField( templateField.m_Name, GetGeneratedFieldDisplayName( templateField.m_Name ), false, false );
490 }
491}
492
493
495{
496 m_dataModel->SetPath( m_parent->GetLastSchematicSheetPath() );
497 m_dataModel->SetScope( aScope );
498
499 if( aScope == SCOPE::SCOPE_SELECTION )
501
502 m_dataModel->RebuildRows();
503}
504
505
507{
508 std::unordered_set<KIID_PATH> selectionItems;
509 PCB_SELECTION_TOOL* selectionTool = m_parent->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
510 const PCB_SELECTION& selection = selectionTool->GetSelection();
511
512 auto addSelectionItem = [&]( EDA_ITEM* aItem )
513 {
514 FOOTPRINT* footprint = nullptr;
515
516 if( aItem->Type() == PCB_FOOTPRINT_T )
517 footprint = static_cast<FOOTPRINT*>( aItem );
518 else if( aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
519 footprint = static_cast<FOOTPRINT*>( aItem->GetParent() );
520
521 if( footprint )
522 {
524 path.push_back( footprint->m_Uuid );
525 selectionItems.insert( path );
526 }
527 };
528
529 for( EDA_ITEM* item : selection )
530 {
531 if( item->Type() == PCB_GROUP_T )
532 static_cast<PCB_GROUP*>( item )->RunOnChildren( addSelectionItem, RECURSE_MODE::RECURSE );
533 else
534 addSelectionItem( item );
535 }
536
537 m_dataModel->SetSelectionItems( selectionItems );
538}
539
540
541void DIALOG_FOOTPRINT_FIELDS_TABLE::OnScope( wxCommandEvent& aEvent )
542{
543 switch( aEvent.GetSelection() )
544 {
545 case 0: setScope( SCOPE::SCOPE_ALL ); break;
546 case 1: setScope( SCOPE::SCOPE_SHEET ); break;
547 case 2: setScope( SCOPE::SCOPE_SHEET_RECURSIVE ); break;
548 case 3: setScope( SCOPE::SCOPE_SELECTION ); break;
549 }
550}
551
552
553void DIALOG_FOOTPRINT_FIELDS_TABLE::OnMenu( wxCommandEvent& aEvent )
554{
555 // Build a pop menu:
556 wxMenu menu;
557
558 menu.Append( MYID_INCLUDE_DNP, _( "Include 'DNP' Footprints" ),
559 _( "Show footprints marked 'DNP' in the table. This setting also controls whether or not 'DNP' "
560 "footprints are included on export." ),
561 wxITEM_CHECK );
562 menu.Check( MYID_INCLUDE_DNP, !m_dataModel->GetExcludeDNP() );
563
564 menu.Append( MYID_INCLUDE_EXCLUDED_FROM_BOM, _( "Include 'Exclude from BOM' Footprints" ),
565 _( "Show footprints marked 'Exclude from BOM' in the table. Footprints marked 'Exclude from BOM' "
566 "are never included on export." ),
567 wxITEM_CHECK );
568 menu.Check( MYID_INCLUDE_EXCLUDED_FROM_BOM, m_dataModel->GetIncludeExcludedFromBOM() );
569
570 menu.AppendSeparator();
571
572 menu.Append( MYID_HIGHLIGHT_ON_CROSS_PROBE, _( "Highlight on Cross-probe" ),
573 _( "Highlight corresponding item on canvas when it is selected in the table" ),
574 wxITEM_CHECK );
575 menu.Check( MYID_HIGHLIGHT_ON_CROSS_PROBE, m_cfgDialogSettings.selection_mode == 0 );
576
577 menu.Append( MYID_SELECT_ON_CROSS_PROBE, _( "Select on Cross-probe" ),
578 _( "Select corresponding item on canvas when it is selected in the table" ),
579 wxITEM_CHECK );
580 menu.Check( MYID_SELECT_ON_CROSS_PROBE, m_cfgDialogSettings.selection_mode == 1 );
581
582 // menuId is the selected submenu id from the popup menu or wxID_NONE
583 int menuId = m_bMenu->GetPopupMenuSelectionFromUser( menu );
584
585 if( menuId == 0 || menuId == MYID_INCLUDE_DNP )
586 {
587 m_dataModel->SetExcludeDNP( !m_dataModel->GetExcludeDNP() );
588 m_dataModel->RebuildRows();
589 m_grid->ForceRefresh();
590
592 }
593 else if( menuId == 1 || menuId == MYID_INCLUDE_EXCLUDED_FROM_BOM )
594 {
595 m_dataModel->SetIncludeExcludedFromBOM( !m_dataModel->GetIncludeExcludedFromBOM() );
596 m_dataModel->RebuildRows();
597 m_grid->ForceRefresh();
598
600 }
601 else if( menuId == 3 || menuId == MYID_HIGHLIGHT_ON_CROSS_PROBE )
602 {
603 if( m_cfgDialogSettings.selection_mode != 0 )
604 m_cfgDialogSettings.selection_mode = 0;
605 else
606 m_cfgDialogSettings.selection_mode = 2;
607 }
608 else if( menuId == 4 || menuId == MYID_SELECT_ON_CROSS_PROBE )
609 {
610 if( m_cfgDialogSettings.selection_mode != 1 )
611 m_cfgDialogSettings.selection_mode = 1;
612 else
613 m_cfgDialogSettings.selection_mode = 2;
614 }
615}
616
617
619{
620 // Cross-probing should only work in Edit page
621 if( m_nbPages->GetSelection() != 0 )
622 return;
623
624 // Cross-probing is disabled when we're in selection scope mode, otherwise
625 // we're just in a loop
626 if( m_dataModel->GetScope() == SCOPE::SCOPE_SELECTION )
627 return;
628
629 // Multi-select can grab the rows that are expanded child refs, and also the row
630 // containing the list of all child refs. Make sure we add refs/footprints uniquely
631 std::set<BOARD_ITEM*> footprints;
632
633 for( int row : aRows )
634 {
635 for( const FOOTPRINT_REF& ref : m_dataModel->GetRowReferences( row ) )
636 footprints.insert( &ref.GetFootprint() );
637 }
638
639 std::vector<BOARD_ITEM*> focusItems( footprints.begin(), footprints.end() );
640
641 if( m_cfgDialogSettings.selection_mode == 0 )
642 {
643 m_parent->FocusOnItems( focusItems );
644 }
645 else if( m_cfgDialogSettings.selection_mode == 1 )
646 {
647 m_parent->GetToolManager()->RunAction( PCB_ACTIONS::syncSelection, &focusItems );
648 }
649}
650
651
653{
655 {
656 m_cfgBomSettings.m_BomExportFileName = m_outputFileName->GetValue();
657 m_parent->SaveBoard();
658 ClearModify();
659 }
660}
661
662
663void DIALOG_FOOTPRINT_FIELDS_TABLE::OnCancel( wxCommandEvent& aEvent )
664{
665 if( m_job )
666 {
667 EndModal( wxID_CANCEL );
668 }
669 else
670 {
671 // Discard any unsaved edit in the output filename field
672 m_outputFileName->SetValue( m_cfgBomSettings.m_BomExportFileName );
673 Close();
674 }
675}
676
677
678void DIALOG_FOOTPRINT_FIELDS_TABLE::OnOk( wxCommandEvent& aEvent )
679{
681 return;
682
683 if( m_job )
684 {
686 EndModal( wxID_OK );
687 }
688 else
689 {
690 if( m_cfgBomSettings.m_BomExportFileName != m_outputFileName->GetValue() )
691 {
692 m_cfgBomSettings.m_BomExportFileName = m_outputFileName->GetValue();
693 m_parent->OnModify();
694 }
695
696 Close();
697 }
698}
699
700
701void DIALOG_FOOTPRINT_FIELDS_TABLE::OnClose( wxCloseEvent& aEvent )
702{
703 if( m_job )
704 {
705 aEvent.Skip();
706 return;
707 }
708
709 m_grid->CommitPendingChanges( true );
710
711 if( m_dataModel->IsEdited() && aEvent.CanVeto() )
712 {
713 if( !HandleUnsavedChanges( this, _( "Save changes?" ),
714 [&]() -> bool
715 {
716 return TransferDataFromWindow();
717 } ) )
718 {
719 aEvent.Veto();
720 return;
721 }
722 }
723
724 if( savePresets( true ) )
725 m_parent->OnModify();
726
727 // Stop listening to board events
728 m_parent->GetBoard()->RemoveListener( this );
729 m_parent->ClearFocus();
730
731 wxCommandEvent* event = new wxCommandEvent( EDA_EVT_CLOSE_DIALOG_FOOTPRINT_FIELDS_TABLE, wxID_ANY );
732
733 if( wxWindow* parentWindow = GetParent() )
734 wxQueueEvent( parentWindow, event );
735}
736
737
738void DIALOG_FOOTPRINT_FIELDS_TABLE::OnBoardItemsAdded( BOARD& aPcb, std::vector<BOARD_ITEM*>& aPcbItem )
739{
740 FOOTPRINT_REFERENCE_LIST addedRefs;
741
742 for( BOARD_ITEM* item : aPcbItem )
743 {
744 if( item->Type() == PCB_FOOTPRINT_T )
745 addedRefs.push_back( FOOTPRINT_REF( *static_cast<FOOTPRINT*>( item ) ) );
746 }
747
748 bool selectionScope = m_dataModel->GetScope() == SCOPE::SCOPE_SELECTION;
749
750 if( addedRefs.empty() && !selectionScope )
751 return;
752
753 std::set<KIID_PATH> savedSelection = SaveGridSelection();
754
755 for( FOOTPRINT_REF& ref : addedRefs )
756 {
757 // Add all fields again in case this footprint has a new one
758 for( PCB_FIELD* field : ref.GetFootprint().GetFields() )
759 {
760 if( !field->IsMandatory() && !field->IsPrivate() )
761 AddField( field->GetUntranslatedName(), field->GetName(), true, false, false );
762 }
763 }
764
765
766 m_dataModel->AddReferences( addedRefs );
767 rebuildRowsPreservingSelection( savedSelection );
768}
769
770
771void DIALOG_FOOTPRINT_FIELDS_TABLE::OnBoardItemsRemoved( BOARD& aPcb, std::vector<BOARD_ITEM*>& aPcbItem )
772{
773 std::set<KIID_PATH> savedSelection = SaveGridSelection();
774
775 for( BOARD_ITEM* item : aPcbItem )
776 {
777 if( item->Type() == PCB_FOOTPRINT_T )
778 m_dataModel->RemoveFootprint( FOOTPRINT_REF( *static_cast<FOOTPRINT*>( item ) ) );
779 }
780
781 rebuildRowsPreservingSelection( savedSelection );
782}
783
784
785void DIALOG_FOOTPRINT_FIELDS_TABLE::OnBoardItemsChanged( BOARD& aPcb, std::vector<BOARD_ITEM*>& aPcbItem )
786{
787 FOOTPRINT_REFERENCE_LIST changedRefs;
788
789 for( BOARD_ITEM* item : aPcbItem )
790 {
791 if( item->Type() == PCB_FOOTPRINT_T )
792 changedRefs.push_back( FOOTPRINT_REF( *static_cast<FOOTPRINT*>( item ) ) );
793 }
794
795 bool selectionScope = m_dataModel->GetScope() == SCOPE::SCOPE_SELECTION;
796
797 if( changedRefs.empty() && !selectionScope )
798 return;
799
800 std::set<KIID_PATH> savedSelection = SaveGridSelection();
801
802 for( FOOTPRINT_REF& ref : changedRefs )
803 {
804 // Add all fields again in case this footprint has a new one
805 for( PCB_FIELD* field : ref.GetFootprint().GetFields() )
806 {
807 if( !field->IsMandatory() && !field->IsPrivate() )
808 AddField( field->GetUntranslatedName(), field->GetName(), true, false, false );
809 }
810 }
811
812
813 m_dataModel->UpdateReferences( changedRefs );
814 rebuildRowsPreservingSelection( savedSelection );
815}
816
817
819{
820 wxUnusedVar( aEvent );
821
822 m_dataModel->SetPath( m_parent->GetLastSchematicSheetPath() );
823
824 if( m_dataModel->GetScope() != SCOPE::SCOPE_ALL )
826}
827
828
830{
831 if( m_dataModel->GetScope() == SCOPE::SCOPE_SELECTION )
833}
834
835
840
841
842void DIALOG_FOOTPRINT_FIELDS_TABLE::rebuildRowsPreservingSelection( const std::set<KIID_PATH>& aSavedSelection )
843{
845
846 if( m_dataModel->GetScope() == SCOPE::SCOPE_SELECTION )
848
849 m_dataModel->RebuildRows();
850 RestoreGridSelection( aSavedSelection );
851
853}
854
855
857{
858 return;
859}
860
861
863{
864 return;
865}
866
867
869{
870 return;
871}
872
873
875{
876 return;
877}
878
879
881{
882 return;
883}
884
885
887{
888 if( !m_grid->CommitPendingChanges() )
889 return;
890
891 wxString selectedVariant = getSelectedVariant();
892
893 // Activating a variant only selects its staged values. Apply writes all edited variants.
894 m_dataModel->SetCurrentVariant( selectedVariant );
895
896 if( m_parent )
897 m_parent->SetCurrentVariant( selectedVariant );
898
899 m_dataModel->RebuildRows();
900
901 if( m_nbPages->GetSelection() == 1 )
903 else
904 m_grid->ForceRefresh();
905
908}
909
910
912{
913 // All variant modifications are disabled for the footprint fields table
914 m_addVariantButton->Enable( false );
915 m_copyVariantButton->Enable( false );
916 m_renameVariantButton->Enable( false );
917 m_editVariantDescButton->Enable( false );
918 m_deleteVariantButton->Enable( false );
919}
920
921
923{
924 // A job keeps its own variant, otherwise follow the board.
925 if( m_job )
926 return getSelectedVariant();
927
928 return m_parent->GetBoard()->GetCurrentVariant();
929}
930
931
933{
934 return m_parent->GetBoard()->ResolveTextVar( aToken, 0 );
935}
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:410
bool Empty() const
Definition commit.h:145
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:599
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() const
For items with footprint fields.
static TOOL_ACTION syncSelection
Sets selection to specified items, zooms to fit, if enabled.
Definition pcb_actions.h:63
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:
T * GetTool()
Return the tool of given type or nullptr if there is no such tool registered.
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
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition idf_helpers.h:37
Class to handle a set of BOARD_ITEMs.
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