KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_symbol_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, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25
26#include <common.h>
27#include <base_units.h>
28#include <bitmaps.h>
29#include <symbol_library.h>
30#include <confirm.h>
31#include <eda_doc.h>
33#include <schematic_settings.h>
34#include <general.h>
35#include <grid_tricks.h>
36#include <string_utils.h>
37#include <kiface_base.h>
38#include <sch_commit.h>
39#include <sch_edit_frame.h>
40#include <sch_reference_list.h>
42#include <kiplatform/ui.h>
46#include <widgets/wx_grid.h>
47#include <wx/debug.h>
48#include <wx/ffile.h>
49#include <wx/grid.h>
50#include <wx/textdlg.h>
51#include <wx/filedlg.h>
52#include <wx/msgdlg.h>
55#include <fields_data_model.h>
56#include <eda_list_dialog.h>
57#include <project_sch.h>
59
60wxDEFINE_EVENT( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, wxCommandEvent );
61
62#ifdef __WXMAC__
63#define COLUMN_MARGIN 3
64#else
65#define COLUMN_MARGIN 15
66#endif
67
69
70
71enum
72{
75};
76
78{
79public:
81 wxDataViewListCtrl* aFieldsCtrl,
82 FIELDS_EDITOR_GRID_DATA_MODEL* aDataModel ) :
83 GRID_TRICKS( aGrid ),
84 m_dlg( aParent ),
85 m_fieldsCtrl( aFieldsCtrl ),
86 m_dataModel( aDataModel )
87 {}
88
89protected:
90 void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) override
91 {
92 int col = m_grid->GetGridCursorCol();
93
94 if( m_dataModel->GetColFieldName( col ) == GetCanonicalFieldName( FIELD_T::FOOTPRINT ) )
95 {
96 menu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ),
97 _( "Browse for footprint" ) );
98 menu.AppendSeparator();
99 }
100 else if( m_dataModel->GetColFieldName( col ) == GetCanonicalFieldName( FIELD_T::DATASHEET ) )
101 {
102 menu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ),
103 _( "Show datasheet in browser" ) );
104 menu.AppendSeparator();
105 }
106
107 GRID_TRICKS::showPopupMenu( menu, aEvent );
108 }
109
110 void doPopupSelection( wxCommandEvent& event ) override
111 {
112 int row = m_grid->GetGridCursorRow();
113 int col = m_grid->GetGridCursorCol();
114
115 if( event.GetId() == MYID_SELECT_FOOTPRINT )
116 {
117 // pick a footprint using the footprint picker.
118 wxString fpid = m_grid->GetCellValue( row, col );
119
121 m_dlg ) )
122 {
123 if( frame->ShowModal( &fpid, m_dlg ) )
124 m_grid->SetCellValue( row, col, fpid );
125
126 frame->Destroy();
127 }
128 }
129 else if (event.GetId() == MYID_SHOW_DATASHEET )
130 {
131 wxString datasheet_uri = m_grid->GetCellValue( row, col );
132 GetAssociatedDocument( m_dlg, datasheet_uri, &m_dlg->Prj(),
134 }
135 else
136 {
137 // We have grid tricks events to show/hide the columns from the popup menu
138 // and we need to make sure the data model is updated to match the grid,
139 // so do it through our code instead
140 if( event.GetId() >= GRIDTRICKS_FIRST_SHOWHIDE )
141 {
142 // Pop-up column order is the order of the shown fields, not the
143 // fieldsCtrl order
144 col = event.GetId() - GRIDTRICKS_FIRST_SHOWHIDE;
145
146 bool show = !m_dataModel->GetShowColumn( col );
147
148 // Convert data model column to by iterating over m_fieldsCtrl rows
149 // and finding the matching field name
150 wxString fieldName = m_dataModel->GetColFieldName( col );
151
152 for( row = 0; row < m_fieldsCtrl->GetItemCount(); row++ )
153 {
154 if( m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN ) == fieldName )
155 {
156 if( m_grid->CommitPendingChanges( false ) )
157 m_fieldsCtrl->SetToggleValue( show, row, SHOW_FIELD_COLUMN );
158
159 break;
160 }
161 }
162 }
163 else
164 {
166 }
167 }
168 }
169
171 wxDataViewListCtrl* m_fieldsCtrl;
173};
174
175
177 JOB_EXPORT_SCH_BOM* aJob ) :
179 m_currentBomPreset( nullptr ),
180 m_lastSelectedBomPreset( nullptr ),
181 m_parent( parent ),
182 m_schSettings( parent->Schematic().Settings() ),
183 m_job( aJob )
184{
185 // Get all symbols from the list of schematic sheets
187
188 m_bRefresh->SetBitmap( KiBitmapBundle( BITMAPS::small_refresh ) );
189 m_bRefreshPreview->SetBitmap( KiBitmapBundle( BITMAPS::small_refresh ) );
190 m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
191
192 m_addFieldButton->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
193 m_removeFieldButton->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
194 m_renameFieldButton->SetBitmap( KiBitmapBundle( BITMAPS::small_edit ) );
195
196 m_bomPresetsLabel->SetFont( KIUI::GetInfoFont( this ) );
197 m_labelBomExportPresets->SetFont( KIUI::GetInfoFont( this ) );
198
199 m_fieldsCtrl->AppendTextColumn( _( "Field" ), wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
200 m_fieldsCtrl->AppendTextColumn( _( "Label" ), wxDATAVIEW_CELL_EDITABLE, 0, wxALIGN_LEFT, 0 );
201 m_fieldsCtrl->AppendToggleColumn( _( "Show" ), wxDATAVIEW_CELL_ACTIVATABLE, 0,
202 wxALIGN_CENTER, 0 );
203 m_fieldsCtrl->AppendToggleColumn( _( "Group By" ), wxDATAVIEW_CELL_ACTIVATABLE, 0,
204 wxALIGN_CENTER, 0 );
205
206 // GTK asserts if the number of columns doesn't match the data, but we still don't want
207 // to display the canonical names. So we'll insert a column for them, but keep it 0 width.
208 m_fieldsCtrl->AppendTextColumn( _( "Name" ), wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
209
210 // SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails here on GTK, so we calculate the title sizes and
211 // set the column widths ourselves.
212 wxDataViewColumn* column = m_fieldsCtrl->GetColumn( SHOW_FIELD_COLUMN );
213 m_showColWidth = KIUI::GetTextSize( column->GetTitle(), m_fieldsCtrl ).x + COLUMN_MARGIN;
214 column->SetMinWidth( m_showColWidth );
215
216 column = m_fieldsCtrl->GetColumn( GROUP_BY_COLUMN );
218 column->SetMinWidth( m_groupByColWidth );
219
220 // The fact that we're a list should keep the control from reserving space for the
221 // expander buttons... but it doesn't. Fix by forcing the indent to 0.
222 m_fieldsCtrl->SetIndent( 0 );
223
224 m_filter->SetDescriptiveText( _( "Filter" ) );
225
226 wxGridCellAttr* attr = new wxGridCellAttr;
227 attr->SetEditor( new GRID_CELL_URL_EDITOR( this, PROJECT_SCH::SchSearchS( &Prj() ),
228 &m_parent->Schematic() ) );
230
231 LoadFieldNames(); // loads rows into m_fieldsCtrl and columns into m_dataModel
232
233 // Now that the fields are loaded we can set the initial location of the splitter
234 // based on the list width. Again, SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails us on GTK.
236 m_labelColWidth = 0;
237
238 int colWidth = 0;
239
240 for( int row = 0; row < m_fieldsCtrl->GetItemCount(); ++row )
241 {
242 const wxString& displayName = m_fieldsCtrl->GetTextValue( row, DISPLAY_NAME_COLUMN );
243 colWidth = std::max( colWidth, KIUI::GetTextSize( displayName, m_fieldsCtrl ).x );
244
245 const wxString& label = m_fieldsCtrl->GetTextValue( row, LABEL_COLUMN );
246 colWidth = std::max( colWidth, KIUI::GetTextSize( label, m_fieldsCtrl ).x );
247 }
248
249 m_fieldNameColWidth = colWidth + 20;
250 m_labelColWidth = colWidth + 20;
251
253
254 m_fieldsCtrl->GetColumn( DISPLAY_NAME_COLUMN )->SetWidth( m_fieldNameColWidth );
255 m_fieldsCtrl->GetColumn( LABEL_COLUMN )->SetWidth( m_labelColWidth );
256
257 // This is used for data only. Don't show it to the user.
258 m_fieldsCtrl->GetColumn( FIELD_NAME_COLUMN )->SetHidden( true );
259
260 m_splitterMainWindow->SetMinimumPaneSize( fieldsMinWidth );
261 m_splitterMainWindow->SetSashPosition( fieldsMinWidth + 40 );
262
263 m_grid->UseNativeColHeader( true );
264 m_grid->SetTable( m_dataModel, true );
265
266 // must be done after SetTable(), which appears to re-set it
267 m_grid->SetSelectionMode( wxGrid::wxGridSelectCells );
268
269 // add Cut, Copy, and Paste to wxGrid
270 m_grid->PushEventHandler( new FIELDS_EDITOR_GRID_TRICKS( this, m_grid, m_fieldsCtrl,
271 m_dataModel ) );
272
273 // give a bit more room for comboboxes
274 m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
275
276 // Load our BOM view presets
278
280
281 if( m_job )
282 {
283 SetTitle( m_job->GetSettingsDialogTitle() );
284
285 preset.name = m_job->m_bomPresetName;
286 preset.excludeDNP = m_job->m_excludeDNP;
289 preset.sortAsc = m_job->m_sortAsc;
290 preset.sortField = m_job->m_sortField;
291 preset.groupSymbols = ( m_job->m_fieldsGroupBy.size() > 0 );
292
293 preset.fieldsOrdered.clear();
294
295 size_t i = 0;
296
297 for( const wxString& fieldName : m_job->m_fieldsOrdered )
298 {
299 BOM_FIELD field;
300 field.name = fieldName;
301 field.show = !fieldName.StartsWith( wxT( "__" ), &field.name );
303
304 if( ( m_job->m_fieldsLabels.size() > i ) && !m_job->m_fieldsLabels[i].IsEmpty() )
305 field.label = m_job->m_fieldsLabels[i];
306 else if( IsTextVar( field.name ) )
307 field.label = GetTextVars( field.name );
308 else
309 field.label = field.name;
310
311 preset.fieldsOrdered.emplace_back( field );
312 i++;
313 }
314 }
315
316 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
317 // non-job versions (which have different sizes).
318 m_hash_key = TO_UTF8( GetTitle() );
319
320 ApplyBomPreset( preset );
322
323 // Load BOM export format presets
326
327 if( m_job )
328 {
329 fmtPreset.name = m_job->m_bomFmtPresetName;
332 fmtPreset.keepTabs = m_job->m_keepTabs;
333 fmtPreset.refDelimiter = m_job->m_refDelimiter;
336 }
337
338 ApplyBomFmtPreset( fmtPreset );
340
342 m_grid->ClearSelection();
343
345
347
350
351 wxSize dlgSize( panelCfg.width > 0 ? panelCfg.width : horizPixelsFromDU( 600 ),
352 panelCfg.height > 0 ? panelCfg.height : vertPixelsFromDU( 300 ) );
353 SetSize( dlgSize );
354
355 m_nbPages->SetSelection( cfg->m_FieldEditorPanel.page );
356
358 {
359 case 0: m_radioHighlight->SetValue( true ); break;
360 case 1: m_radioSelect->SetValue( true ); break;
361 case 2: m_radioOff->SetValue( true ); break;
362 }
363
364 switch( cfg->m_FieldEditorPanel.scope )
365 {
366 case SCOPE::SCOPE_ALL: m_radioProject->SetValue( true ); break;
367 case SCOPE::SCOPE_SHEET: m_radioCurrentSheet->SetValue( true ); break;
368 case SCOPE::SCOPE_SHEET_RECURSIVE: m_radioRecursive->SetValue( true ); break;
369 }
370
371 if( m_job )
372 {
374 }
375 else
376 {
378 }
379
380 Center();
381
382 // Connect Events
383 m_grid->Connect( wxEVT_GRID_COL_SORT,
384 wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColSort ), nullptr, this );
385 m_grid->Connect( wxEVT_GRID_COL_MOVE,
386 wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColMove ), nullptr, this );
389 this );
390 m_fieldsCtrl->Bind( wxEVT_DATAVIEW_ITEM_VALUE_CHANGED,
392
393 if( !m_job )
394 {
395 // Start listening for schematic changes
396 m_parent->Schematic().AddListener( this );
397 }
398 else
399 {
400 // Don't allow editing
401 m_grid->EnableEditing( false );
402 m_buttonApply->Hide();
403 m_buttonExport->Hide();
404
406 }
407}
408
409
411{
412 wxGridCellAttr* attr = new wxGridCellAttr;
413 attr->SetReadOnly( false );
414
415 // Set some column types to specific editors
416 if( m_dataModel->ColIsReference( aCol ) )
417 {
418 attr->SetReadOnly();
419 m_dataModel->SetColAttr( attr, aCol );
420 }
421 else if( m_dataModel->GetColFieldName( aCol ) == GetCanonicalFieldName( FIELD_T::FOOTPRINT ) )
422 {
423 attr->SetEditor( new GRID_CELL_FPID_EDITOR( this, wxEmptyString ) );
424 m_dataModel->SetColAttr( attr, aCol );
425 }
426 else if( m_dataModel->GetColFieldName( aCol ) == GetCanonicalFieldName( FIELD_T::DATASHEET ) )
427 {
428 // set datasheet column viewer button
429 attr->SetEditor( new GRID_CELL_URL_EDITOR( this, PROJECT_SCH::SchSearchS( &Prj() ),
430 &m_parent->Schematic() ) );
431 m_dataModel->SetColAttr( attr, aCol );
432 }
433 else if( m_dataModel->ColIsQuantity( aCol ) || m_dataModel->ColIsItemNumber( aCol ) )
434 {
435 attr->SetReadOnly();
436 attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_CENTER );
437 attr->SetRenderer( new wxGridCellNumberRenderer() );
438 m_dataModel->SetColAttr( attr, aCol );
439 }
440 else if( m_dataModel->ColIsAttribute( aCol ) )
441 {
442 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
443 attr->SetRenderer( new wxGridCellBoolRenderer() );
444 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
445 m_dataModel->SetColAttr( attr, aCol );
446 }
447 else if( IsTextVar( m_dataModel->GetColFieldName( aCol ) ) )
448 {
449 attr->SetReadOnly();
450 m_dataModel->SetColAttr( attr, aCol );
451 }
452 else
453 {
454 attr->SetEditor( m_grid->GetDefaultEditor() );
455 m_dataModel->SetColAttr( attr, aCol );
456 }
457}
458
459
461{
463 wxSize defaultDlgSize = ConvertDialogToPixels( wxSize( 600, 300 ) );
464
465 // Restore column sorting order and widths
466 m_grid->AutoSizeColumns( false );
467 int sortCol = 0;
468 bool sortAscending = true;
469
470 for( int col = 0; col < m_grid->GetNumberCols(); ++col )
471 {
473
474 if( col == m_dataModel->GetSortCol() )
475 {
476 sortCol = col;
477 sortAscending = m_dataModel->GetSortAsc();
478 }
479 }
480
481 // sync m_grid's column visibilities to Show checkboxes in m_fieldsCtrl
482 for( int i = 0; i < m_fieldsCtrl->GetItemCount(); ++i )
483 {
484 int col = m_dataModel->GetFieldNameCol( m_fieldsCtrl->GetTextValue( i,
486
487 if( col == -1 )
488 continue;
489
490 bool show = m_fieldsCtrl->GetToggleValue( i, SHOW_FIELD_COLUMN );
491 m_dataModel->SetShowColumn( col, show );
492
493 if( show )
494 {
495 m_grid->ShowCol( col );
496
497 std::string key( m_dataModel->GetColFieldName( col ).ToUTF8() );
498
499 if( cfg->m_FieldEditorPanel.field_widths.count( key )
500 && ( cfg->m_FieldEditorPanel.field_widths.at( key ) > 0 ) )
501 {
502 m_grid->SetColSize( col, cfg->m_FieldEditorPanel.field_widths.at( key ) );
503 }
504 else
505 {
506 int textWidth = m_dataModel->GetDataWidth( col ) + COLUMN_MARGIN;
507 int maxWidth = defaultDlgSize.x / 3;
508
509 m_grid->SetColSize( col, std::clamp( textWidth, 100, maxWidth ) );
510 }
511 }
512 else
513 {
514 m_grid->HideCol( col );
515 }
516 }
517
518 m_dataModel->SetSorting( sortCol, sortAscending );
519 m_grid->SetSortingColumn( sortCol, sortAscending );
520}
521
522
524{
525 // Disconnect Events
526 m_grid->Disconnect( wxEVT_GRID_COL_SORT,
527 wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColSort ), nullptr,
528 this );
529 m_grid->Disconnect( wxEVT_GRID_COL_SORT,
530 wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColMove ), nullptr,
531 this );
532
533 // Delete the GRID_TRICKS.
534 m_grid->PopEventHandler( true );
535
536 // we gave ownership of m_dataModel to the wxGrid...
537}
538
539
541{
542 if( !wxDialog::TransferDataFromWindow() )
543 return false;
544
546 SCH_SELECTION_TOOL* selectionTool = toolMgr->GetTool<SCH_SELECTION_TOOL>();
547 SCH_SELECTION& selection = selectionTool->GetSelection();
548 SCH_SYMBOL* symbol = nullptr;
549
550 UpdateScope();
551
552 if( selection.GetSize() == 1 )
553 {
554 EDA_ITEM* item = selection.Front();
555
556 if( item->Type() == SCH_SYMBOL_T )
557 symbol = (SCH_SYMBOL*) item;
558 else if( item->GetParent() && item->GetParent()->Type() == SCH_SYMBOL_T )
559 symbol = (SCH_SYMBOL*) item->GetParent();
560 }
561
562 if( symbol )
563 {
564 for( int row = 0; row < m_dataModel->GetNumberRows(); ++row )
565 {
566 std::vector<SCH_REFERENCE> references = m_dataModel->GetRowReferences( row );
567 bool found = false;
568
569 for( const SCH_REFERENCE& ref : references )
570 {
571 if( ref.GetSymbol() == symbol )
572 {
573 found = true;
574 break;
575 }
576 }
577
578 if( found )
579 {
580 // Find the value column and the reference column if they're shown
581 int valueCol = -1;
582 int refCol = -1;
583 int anyCol = -1;
584
585 for( int col = 0; col < m_dataModel->GetNumberCols(); col++ )
586 {
587 if( m_dataModel->ColIsValue( col ) )
588 valueCol = col;
589 else if( m_dataModel->ColIsReference( col ) )
590 refCol = col;
591 else if( anyCol == -1 && m_dataModel->GetShowColumn( col ) )
592 anyCol = col;
593 }
594
595 if( valueCol != -1 && m_dataModel->GetShowColumn( valueCol ) )
596 m_grid->GoToCell( row, valueCol );
597 else if( refCol != -1 && m_dataModel->GetShowColumn( refCol ) )
598 m_grid->GoToCell( row, refCol );
599 else if( anyCol != -1 )
600 m_grid->GoToCell( row, anyCol );
601
602 break;
603 }
604 }
605 }
606
607 // We don't want table range selection events to happen until we've loaded the data or we
608 // we'll clear our selection as the grid is built before the code above can get the
609 // user's current selection.
611
612 return true;
613}
614
615
617{
619 return false;
620
621 if( !wxDialog::TransferDataFromWindow() )
622 return false;
623
624 if( m_job )
625 {
626 // and exit, don't even dream of saving changes from the data model
627 return true;
628 }
629
630 SCH_COMMIT commit( m_parent );
631 SCH_SHEET_PATH currentSheet = m_parent->GetCurrentSheet();
632
633 m_dataModel->ApplyData( commit );
634
635 commit.Push( wxS( "Symbol Fields Table Edit" ) );
636
637 // Reset the view to where we left the user
638 m_parent->SetCurrentSheet( currentSheet );
640 m_parent->Refresh();
641
643
644 return true;
645}
646
647
648void DIALOG_SYMBOL_FIELDS_TABLE::AddField( const wxString& aFieldName, const wxString& aLabelValue,
649 bool show, bool groupBy, bool addedByUser )
650{
651 // Users can add fields with variable names that match the special names in the grid,
652 // e.g. ${QUANTITY} so make sure we don't add them twice
653 for( int i = 0; i < m_fieldsCtrl->GetItemCount(); i++ )
654 {
655 if( m_fieldsCtrl->GetTextValue( i, FIELD_NAME_COLUMN ) == aFieldName )
656 return;
657 }
658
659 m_dataModel->AddColumn( aFieldName, aLabelValue, addedByUser );
660
661 wxVector<wxVariant> fieldsCtrlRow;
662 std::string key( aFieldName.ToUTF8() );
663
664 // Don't change these to emplace_back: some versions of wxWidgets don't support it
665 fieldsCtrlRow.push_back( wxVariant( aFieldName ) );
666 fieldsCtrlRow.push_back( wxVariant( aLabelValue ) );
667 fieldsCtrlRow.push_back( wxVariant( show ) );
668 fieldsCtrlRow.push_back( wxVariant( groupBy ) );
669 fieldsCtrlRow.push_back( wxVariant( aFieldName ) );
670
671 m_fieldsCtrl->AppendItem( fieldsCtrlRow );
672
673 wxGridTableMessage msg( m_dataModel, wxGRIDTABLE_NOTIFY_COLS_APPENDED, 1 );
674 m_grid->ProcessTableMessage( msg );
675}
676
677
679{
680 auto addMandatoryField =
681 [&]( FIELD_T fieldId, bool show, bool groupBy )
682 {
683 m_mandatoryFieldListIndexes[fieldId] = m_fieldsCtrl->GetItemCount();
684
686 GetDefaultFieldName( fieldId, DO_TRANSLATE ), show, groupBy );
687 };
688
689 // Add mandatory fields first show groupBy
690 addMandatoryField( FIELD_T::REFERENCE, true, true );
691 addMandatoryField( FIELD_T::VALUE, true, true );
692 addMandatoryField( FIELD_T::FOOTPRINT, true, true );
693 addMandatoryField( FIELD_T::DATASHEET, true, false );
694 addMandatoryField( FIELD_T::DESCRIPTION, false, false );
695
696 // Generated fields present only in the fields table
699
700 // User fields next
701 std::set<wxString> userFieldNames;
702
703 for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
704 {
705 SCH_SYMBOL* symbol = m_symbolsList[ i ].GetSymbol();
706
707 for( const SCH_FIELD& field : symbol->GetFields() )
708 {
709 if( !field.IsMandatory() && !field.IsPrivate() )
710 userFieldNames.insert( field.GetName() );
711 }
712 }
713
714 for( const wxString& fieldName : userFieldNames )
715 AddField( fieldName, GetTextVars( fieldName ), true, false );
716
717 // Add any templateFieldNames which aren't already present in the userFieldNames
718 for( const TEMPLATE_FIELDNAME& templateFieldname :
720 {
721 if( userFieldNames.count( templateFieldname.m_Name ) == 0 )
722 {
723 AddField( templateFieldname.m_Name, GetTextVars( templateFieldname.m_Name ), false,
724 false );
725 }
726 }
727}
728
729
730void DIALOG_SYMBOL_FIELDS_TABLE::OnAddField( wxCommandEvent& event )
731{
732 wxTextEntryDialog dlg( this, _( "New field name:" ), _( "Add Field" ) );
733
734 if( dlg.ShowModal() != wxID_OK )
735 return;
736
737 wxString fieldName = dlg.GetValue();
738
739 if( fieldName.IsEmpty() )
740 {
741 DisplayError( this, _( "Field must have a name." ) );
742 return;
743 }
744
745 for( int i = 0; i < m_dataModel->GetNumberCols(); ++i )
746 {
747 if( fieldName == m_dataModel->GetColFieldName( i ) )
748 {
749 DisplayError( this, wxString::Format( _( "Field name '%s' already in use." ),
750 fieldName ) );
751 return;
752 }
753 }
754
755 AddField( fieldName, GetTextVars( fieldName ), true, false, true );
756
757 SetupColumnProperties( m_dataModel->GetColsCount() - 1 );
758
760 OnModify();
761}
762
763
764void DIALOG_SYMBOL_FIELDS_TABLE::OnRemoveField( wxCommandEvent& event )
765{
766 int col = -1;
767 int row = m_fieldsCtrl->GetSelectedRow();
768
769 if( row == -1 )
770 {
771 wxBell();
772 return;
773 }
774
775 for( FIELD_T id : MANDATORY_FIELDS )
776 {
777 if( m_mandatoryFieldListIndexes[id] == row )
778 {
779 DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
780 (int) m_mandatoryFieldListIndexes.size() ) );
781 return;
782 }
783 }
784
785 wxString fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
786 wxString displayName = m_fieldsCtrl->GetTextValue( row, DISPLAY_NAME_COLUMN );
787
788 wxString confirm_msg = wxString::Format( _( "Are you sure you want to remove the field '%s'?" ),
789 displayName );
790
791 if( !IsOK( this, confirm_msg ) )
792 return;
793
794 for( int i = 0; i < m_dataModel->GetNumberCols(); ++i )
795 {
796 if( fieldName == m_dataModel->GetColFieldName( i ) )
797 col = i;
798 }
799
800 m_fieldsCtrl->DeleteItem( row );
802
803 // Make selection and update the state of "Remove field..." button via
804 // OnFieldsCtrlSelectionChanged().
805 // Safe to decrement row index because we always have mandatory fields.
806 m_fieldsCtrl->SelectRow( --row );
807
808 wxGridTableMessage msg( m_dataModel, wxGRIDTABLE_NOTIFY_COLS_DELETED, col, 1 );
809
810 m_grid->ProcessTableMessage( msg );
811
813 OnModify();
814}
815
816
817void DIALOG_SYMBOL_FIELDS_TABLE::OnRenameField( wxCommandEvent& event )
818{
819 int row = m_fieldsCtrl->GetSelectedRow();
820
821 if( row == -1 )
822 {
823 wxBell();
824 return;
825 }
826
827 for( FIELD_T id : MANDATORY_FIELDS )
828 {
829 if( m_mandatoryFieldListIndexes[id] == row )
830 {
831 wxBell();
832 return;
833 }
834 }
835
836 wxString fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
837
838 int col = m_dataModel->GetFieldNameCol( fieldName );
839 wxCHECK_RET( col != -1, wxS( "Existing field name missing from data model" ) );
840
841 wxTextEntryDialog dlg( this, _( "New field name:" ), _( "Rename Field" ) );
842
843 if( dlg.ShowModal() != wxID_OK )
844 return;
845
846 wxString newFieldName = dlg.GetValue();
847
848 // No change, no-op
849 if( newFieldName == fieldName )
850 return;
851
852 // New field name already exists
853 if( m_dataModel->GetFieldNameCol( newFieldName ) != -1 )
854 {
855 wxString confirm_msg = wxString::Format( _( "Field name %s already exists." ),
856 newFieldName );
857 DisplayError( this, confirm_msg );
858 return;
859 }
860
861 m_dataModel->RenameColumn( col, newFieldName );
862 m_fieldsCtrl->SetTextValue( newFieldName, row, DISPLAY_NAME_COLUMN );
863 m_fieldsCtrl->SetTextValue( newFieldName, row, FIELD_NAME_COLUMN );
864 m_fieldsCtrl->SetTextValue( newFieldName, row, LABEL_COLUMN );
865
867 OnModify();
868}
869
870
871void DIALOG_SYMBOL_FIELDS_TABLE::OnFilterText( wxCommandEvent& aEvent )
872{
873 m_dataModel->SetFilter( m_filter->GetValue() );
875 m_grid->ForceRefresh();
876
878}
879
880
882{
883 wxPoint pos = aEvent.GetPosition();
884 wxRect ctrlRect = m_filter->GetScreenRect();
885 int buttonWidth = ctrlRect.GetHeight(); // Presume buttons are square
886
887 // TODO: restore cursor when mouse leaves the filter field (or is it a MSW bug?)
888 if( m_filter->IsSearchButtonVisible() && pos.x < buttonWidth )
889 SetCursor( wxCURSOR_ARROW );
890 else if( m_filter->IsCancelButtonVisible() && pos.x > ctrlRect.GetWidth() - buttonWidth )
891 SetCursor( wxCURSOR_ARROW );
892 else
893 SetCursor( wxCURSOR_IBEAM );
894}
895
896
898{
899 wxDataViewItem item = event.GetItem();
900 int row = m_fieldsCtrl->ItemToRow( item );
901 int col = event.GetColumn();
902
903 switch ( col )
904 {
906 {
907 wxString name = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
908 bool value = m_fieldsCtrl->GetToggleValue( row, col );
909 int dataCol = m_dataModel->GetFieldNameCol( name );
910
911 m_dataModel->SetShowColumn( dataCol, value );
912
913 if( dataCol != -1 )
914 {
915 if( value )
916 m_grid->ShowCol( dataCol );
917 else
918 m_grid->HideCol( dataCol );
919 }
920
921 break;
922 }
923
924 case GROUP_BY_COLUMN:
925 {
926 wxString name = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
927 bool value = m_fieldsCtrl->GetToggleValue( row, col );
928 int dataCol = m_dataModel->GetFieldNameCol( name );
929
930 if( m_dataModel->ColIsQuantity( dataCol ) && value )
931 {
932 DisplayError( this, _( "The Quantity column cannot be grouped by." ) );
933
934 value = false;
935 m_fieldsCtrl->SetToggleValue( value, row, col );
936 }
937
938 if( m_dataModel->ColIsItemNumber( dataCol ) && value )
939 {
940 DisplayError( this, _( "The Item Number column cannot be grouped by." ) );
941
942 value = false;
943 m_fieldsCtrl->SetToggleValue( value, row, col );
944 }
945
946 wxString fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
947
948 m_dataModel->SetGroupColumn( m_dataModel->GetFieldNameCol( fieldName ), value );
950 m_grid->ForceRefresh();
951 break;
952 }
953
954 default:
955 break;
956 }
957
959}
960
961
963{
966 m_grid->ForceRefresh();
967
969}
970
971
973{
976 m_grid->ForceRefresh();
977
979}
980
981
983{
986 m_grid->ForceRefresh();
987
989}
990
991
992void DIALOG_SYMBOL_FIELDS_TABLE::OnColSort( wxGridEvent& aEvent )
993{
994 int sortCol = aEvent.GetCol();
995 std::string key( m_dataModel->GetColFieldName( sortCol ).ToUTF8() );
996 bool ascending;
997
998 // Don't sort by item number, it is generated by the sort
999 if( m_dataModel->ColIsItemNumber( sortCol ) )
1000 {
1001 aEvent.Veto();
1002 return;
1003 }
1004
1005 // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the event, and
1006 // if we ask it will give us pre-event info.
1007 if( m_grid->IsSortingBy( sortCol ) )
1008 {
1009 // same column; invert ascending
1010 ascending = !m_grid->IsSortOrderAscending();
1011 }
1012 else
1013 {
1014 // different column; start with ascending
1015 ascending = true;
1016 }
1017
1018 m_dataModel->SetSorting( sortCol, ascending );
1020 m_grid->ForceRefresh();
1021
1023}
1024
1025
1026void DIALOG_SYMBOL_FIELDS_TABLE::OnColMove( wxGridEvent& aEvent )
1027{
1028 int origPos = aEvent.GetCol();
1029
1030 // Save column widths since the setup function uses the saved config values
1032
1033 for( int i = 0; i < m_grid->GetNumberCols(); i++ )
1034 {
1035 if( m_grid->IsColShown( i ) )
1036 {
1037 std::string fieldName( m_dataModel->GetColFieldName( i ).ToUTF8() );
1038 cfg->m_FieldEditorPanel.field_widths[fieldName] = m_grid->GetColSize( i );
1039 }
1040 }
1041
1042 CallAfter(
1043 [origPos, this]()
1044 {
1045 int newPos = m_grid->GetColPos( origPos );
1046
1047#ifdef __WXMAC__
1048 if( newPos < origPos )
1049 newPos += 1;
1050#endif
1051
1052 m_dataModel->MoveColumn( origPos, newPos );
1053
1054 // "Unmove" the column since we've moved the column internally
1055 m_grid->ResetColPos();
1056
1057 // We need to reset all the column attr's to the correct column order
1059
1060 m_grid->ForceRefresh();
1061 } );
1062
1064}
1065
1066
1068{
1069 wxDataViewItem item = aEvent.GetItem();
1070 int row = m_fieldsCtrl->ItemToRow( item );
1071 wxString label = m_fieldsCtrl->GetTextValue( row, LABEL_COLUMN );
1072 wxString fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
1073 int col = m_dataModel->GetFieldNameCol( fieldName );
1074
1075 if( col != -1 )
1076 m_dataModel->SetColLabelValue( col, label );
1077
1079
1080 aEvent.Skip();
1081
1082 m_grid->ForceRefresh();
1083}
1084
1085
1087{
1088 m_grid->ForceRefresh();
1089 OnModify();
1090}
1091
1092
1093void DIALOG_SYMBOL_FIELDS_TABLE::OnTableColSize( wxGridSizeEvent& aEvent )
1094{
1095 int col = aEvent.GetRowOrCol();
1096 std::string key( m_dataModel->GetColFieldName( col ).ToUTF8() );
1097
1098 aEvent.Skip();
1099
1100 m_grid->ForceRefresh();
1101}
1102
1103
1105{
1107 m_grid->ForceRefresh();
1108}
1109
1110
1112{
1113 UpdateScope();
1114}
1115
1116
1118{
1120
1121 if( m_radioProject->GetValue() )
1122 m_dataModel->SetScope( FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE::SCOPE_ALL );
1123 else if( m_radioCurrentSheet->GetValue() )
1124 m_dataModel->SetScope( FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE::SCOPE_SHEET );
1125 else if( m_radioRecursive->GetValue() )
1126 m_dataModel->SetScope( FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE::SCOPE_SHEET_RECURSIVE );
1127
1129}
1130
1131
1133{
1134 if( m_dataModel->ColIsReference( event.GetCol() ) )
1135 {
1136 m_grid->ClearSelection();
1137
1138 m_dataModel->ExpandCollapseRow( event.GetRow() );
1139 m_grid->SetGridCursor( event.GetRow(), event.GetCol() );
1140 }
1141 else
1142 {
1143 event.Skip();
1144 }
1145}
1146
1147
1148void DIALOG_SYMBOL_FIELDS_TABLE::OnTableRangeSelected( wxGridRangeSelectEvent& aEvent )
1149{
1150 // Cross-probing should only work in Edit page
1151 if( m_nbPages->GetSelection() != 0 )
1152 return;
1153
1154 // Multi-select can grab the rows that are expanded child refs, and also the row
1155 // containing the list of all child refs. Make sure we add refs/symbols uniquely
1156 std::set<SCH_REFERENCE> refs;
1157 std::set<SCH_ITEM*> symbols;
1158
1159 // This handler handles selecting and deselecting
1160 if( aEvent.Selecting() )
1161 {
1162 for( int i = aEvent.GetTopRow(); i <= aEvent.GetBottomRow(); i++ )
1163 {
1164 for( const SCH_REFERENCE& ref : m_dataModel->GetRowReferences( i ) )
1165 refs.insert( ref );
1166 }
1167
1168 for( const SCH_REFERENCE& ref : refs )
1169 symbols.insert( ref.GetSymbol() );
1170 }
1171
1172 if( m_radioHighlight->GetValue() )
1173 {
1175
1176 if( refs.size() > 0 )
1177 {
1178 // Use of full path based on UUID allows select of not yet annotated or duplicated
1179 // symbols
1180 wxString symbol_path = refs.begin()->GetFullPath();
1181
1182 // Focus only handles one item at this time
1183 editor->FindSymbolAndItem( &symbol_path, nullptr, true, HIGHLIGHT_SYMBOL,
1184 wxEmptyString );
1185 }
1186 else
1187 {
1188 m_parent->FocusOnItem( nullptr );
1189 }
1190 }
1191 else if( m_radioSelect->GetValue() )
1192 {
1194 std::vector<SCH_ITEM*> items( symbols.begin(), symbols.end() );
1195
1196 if( refs.size() > 0 )
1197 selTool->SyncSelection( refs.begin()->GetSheetPath(), nullptr, items );
1198 else
1199 selTool->ClearSelection();
1200 }
1201}
1202
1203
1205{
1206 // TODO: Option to select footprint if FOOTPRINT column selected
1207
1208 event.Skip();
1209}
1210
1211
1213{
1217#ifdef __WXMAC__
1218 // TODO: something in wxWidgets 3.1.x pads checkbox columns with extra space. (It used to
1219 // also be that the width of the column would get set too wide (to 30), but that's patched in
1220 // our local wxWidgets fork.)
1221 width -= 50;
1222#endif
1223
1224 m_fieldNameColWidth = width / 2;
1226
1227 // GTK loses its head and messes these up when resizing the splitter bar:
1228 m_fieldsCtrl->GetColumn( SHOW_FIELD_COLUMN )->SetWidth( m_showColWidth );
1229 m_fieldsCtrl->GetColumn( GROUP_BY_COLUMN )->SetWidth( m_groupByColWidth );
1230
1231 m_fieldsCtrl->GetColumn( FIELD_NAME_COLUMN )->SetHidden( true );
1232 m_fieldsCtrl->GetColumn( DISPLAY_NAME_COLUMN )->SetWidth( m_fieldNameColWidth );
1233 m_fieldsCtrl->GetColumn( LABEL_COLUMN )->SetWidth( m_labelColWidth );
1234
1235 m_fieldsCtrl->Refresh(); // To refresh checkboxes on Windows.
1236
1237 event.Skip();
1238}
1239
1240
1242{
1244 {
1246 ClearModify();
1247 }
1248}
1249
1250
1251void DIALOG_SYMBOL_FIELDS_TABLE::OnPageChanged( wxNotebookEvent& event )
1252{
1254}
1255
1256
1258{
1261}
1262
1263
1265{
1268}
1269
1270
1272{
1273 BOM_FMT_PRESET current;
1274
1275 current.name = m_cbBomFmtPresets->GetStringSelection();
1276 current.fieldDelimiter = m_textFieldDelimiter->GetValue();
1277 current.stringDelimiter = m_textStringDelimiter->GetValue();
1278 current.refDelimiter = m_textRefDelimiter->GetValue();
1279 current.refRangeDelimiter = m_textRefRangeDelimiter->GetValue();
1280 current.keepTabs = m_checkKeepTabs->GetValue();
1281 current.keepLineBreaks = m_checkKeepLineBreaks->GetValue();
1282
1283 return current;
1284}
1285
1286
1288{
1289 m_nbPages->SetSelection( 0 );
1290}
1291
1292
1294{
1295 m_nbPages->SetSelection( 1 );
1296}
1297
1298
1300{
1301 // Build the absolute path of current output directory to preselect it in the file browser.
1302 wxString path = ExpandEnvVarSubstitutions( m_outputFileName->GetValue(), &Prj() );
1303 path = Prj().AbsolutePath( path );
1304
1305
1306 // Calculate the export filename
1307 wxFileName fn( Prj().AbsolutePath( m_parent->Schematic().GetFileName() ) );
1308 fn.SetExt( FILEEXT::CsvFileExtension );
1309
1310 wxFileDialog saveDlg( this, _( "Bill of Materials Output File" ), path, fn.GetFullName(),
1311 FILEEXT::CsvFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1312
1313 if( saveDlg.ShowModal() == wxID_CANCEL )
1314 return;
1315
1316
1317 wxFileName file = wxFileName( saveDlg.GetPath() );
1318 wxString defaultPath = fn.GetPathWithSep();
1319 wxString msg;
1320 msg.Printf( _( "Do you want to use a path relative to\n'%s'?" ), defaultPath );
1321
1322 wxMessageDialog dialog( this, msg, _( "BOM Output File" ),
1323 wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
1324
1325 if( dialog.ShowModal() == wxID_YES )
1326 {
1327 if( !file.MakeRelativeTo( defaultPath ) )
1328 {
1329 wxMessageBox( _( "Cannot make path relative (target volume different from schematic "
1330 "file volume)!" ),
1331 _( "BOM Output File" ), wxOK | wxICON_ERROR );
1332 }
1333 }
1334
1335 m_outputFileName->SetValue( file.GetFullPath() );
1336}
1337
1338
1339void DIALOG_SYMBOL_FIELDS_TABLE::OnExport( wxCommandEvent& aEvent )
1340{
1341 if( m_dataModel->IsEdited() )
1342 {
1343 if( OKOrCancelDialog( nullptr, _( "Unsaved data" ),
1344 _( "Changes have not yet been saved. Export unsaved data?" ), "",
1345 _( "OK" ), _( "Cancel" ) )
1346 == wxID_CANCEL )
1347 {
1348 return;
1349 }
1350 }
1351
1352 // Create output directory if it does not exist (also transform it in absolute form).
1353 // Bail if it fails.
1354
1355 std::function<bool( wxString* )> textResolver =
1356 [&]( wxString* token ) -> bool
1357 {
1358 SCHEMATIC& schematic = m_parent->Schematic();
1359
1360 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
1361 return schematic.ResolveTextVar( &schematic.CurrentSheet(), token, 0 );
1362 };
1363
1364 wxString path = m_outputFileName->GetValue();
1365
1366 if( path.IsEmpty() )
1367 {
1368 DisplayError( this, _( "No output file specified in Export tab." ) );
1369 return;
1370 }
1371
1372 path = ExpandTextVars( path, &textResolver );
1373 path = ExpandEnvVarSubstitutions( path, nullptr );
1374
1375 wxFileName outputFile = wxFileName::FileName( path );
1376 wxString msg;
1377
1378 if( !EnsureFileDirectoryExists( &outputFile,
1379 Prj().AbsolutePath( m_parent->Schematic().GetFileName() ),
1381 {
1382 msg.Printf( _( "Could not open/create path '%s'." ), outputFile.GetPath() );
1383 DisplayError( this, msg );
1384 return;
1385 }
1386
1387 wxFFile out( outputFile.GetFullPath(), "wb" );
1388
1389 if( !out.IsOpened() )
1390 {
1391 msg.Printf( _( "Could not create BOM output '%s'." ), outputFile.GetFullPath() );
1392 DisplayError( this, msg );
1393 return;
1394 }
1395
1397
1398 if( !out.Write( m_textOutput->GetValue() ) )
1399 {
1400 msg.Printf( _( "Could not write BOM output '%s'." ), outputFile.GetFullPath() );
1401 DisplayError( this, msg );
1402 return;
1403 }
1404
1405 // close the file before we tell the user it's done with the info modal :workflow meme:
1406 out.Close();
1407 msg.Printf( _( "Wrote BOM output to '%s'" ), outputFile.GetFullPath() );
1408 DisplayInfoMessage( this, msg );
1409}
1410
1411
1412void DIALOG_SYMBOL_FIELDS_TABLE::OnCancel( wxCommandEvent& aEvent )
1413{
1414 if( m_job )
1415 EndModal( wxID_CANCEL );
1416 else
1417 Close();
1418}
1419
1420
1421void DIALOG_SYMBOL_FIELDS_TABLE::OnOk( wxCommandEvent& aEvent )
1422{
1424
1425 if( m_job )
1426 {
1428
1431 else
1432 m_job->m_bomFmtPresetName = wxEmptyString;
1433
1434 if( m_currentBomPreset )
1436 else
1437 m_job->m_bomPresetName = wxEmptyString;
1438
1440 m_job->m_fieldDelimiter = fmtSettings.fieldDelimiter;
1442 m_job->m_refDelimiter = fmtSettings.refDelimiter;
1444 m_job->m_keepTabs = fmtSettings.keepTabs;
1445 m_job->m_keepLineBreaks = fmtSettings.keepLineBreaks;
1446
1447 BOM_PRESET presetFields = m_dataModel->GetBomSettings();
1448 m_job->m_sortAsc = presetFields.sortAsc;
1449 m_job->m_excludeDNP = presetFields.excludeDNP;
1451 m_job->m_filterString = presetFields.filterString;
1452 m_job->m_sortField = presetFields.sortField;
1453
1454 m_job->m_fieldsOrdered.clear();
1455 m_job->m_fieldsLabels.clear();
1456 m_job->m_fieldsGroupBy.clear();
1457
1458 for( const BOM_FIELD& modelField : m_dataModel->GetFieldsOrdered() )
1459 {
1460 if( modelField.show )
1461 m_job->m_fieldsOrdered.emplace_back( modelField.name );
1462 else
1463 m_job->m_fieldsOrdered.emplace_back( wxT( "__" ) + modelField.name );
1464
1465 m_job->m_fieldsLabels.emplace_back( modelField.label );
1466
1467 if( modelField.groupBy )
1468 m_job->m_fieldsGroupBy.emplace_back( modelField.name );
1469 }
1470
1471 EndModal( wxID_OK );
1472 }
1473 else
1474 {
1475 Close();
1476 }
1477}
1478
1479
1480void DIALOG_SYMBOL_FIELDS_TABLE::OnClose( wxCloseEvent& aEvent )
1481{
1482 if( m_job )
1483 {
1484 aEvent.Skip();
1485 return;
1486 }
1487
1488 // This is a cancel, so commit quietly as we're going to throw the results away anyway.
1490
1491 if( m_dataModel->IsEdited() )
1492 {
1493 if( !HandleUnsavedChanges( this, _( "Save changes?" ),
1494 [&]() -> bool
1495 {
1496 return TransferDataFromWindow();
1497 } ) )
1498 {
1499 aEvent.Veto();
1500 return;
1501 }
1502 }
1503
1504 // Stop listening to schematic events
1506
1507 // Save all our settings since we're really closing
1510
1512
1513 cfg->m_FieldEditorPanel.width = GetSize().x;
1514 cfg->m_FieldEditorPanel.height = GetSize().y;
1515 cfg->m_FieldEditorPanel.page = m_nbPages->GetSelection();
1516
1517 if( m_radioHighlight->GetValue() )
1519 else if( m_radioSelect->GetValue() )
1521 else if( m_radioOff->GetValue() )
1523
1524 if( m_radioProject->GetValue() )
1525 cfg->m_FieldEditorPanel.scope = SCOPE::SCOPE_ALL;
1526 else if( m_radioCurrentSheet->GetValue() )
1527 cfg->m_FieldEditorPanel.scope = SCOPE::SCOPE_SHEET;
1528 else if( m_radioRecursive->GetValue() )
1529 cfg->m_FieldEditorPanel.scope = SCOPE::SCOPE_SHEET_RECURSIVE;
1530
1531 for( int i = 0; i < m_grid->GetNumberCols(); i++ )
1532 {
1533 if( m_grid->IsColShown( i ) )
1534 {
1535 std::string fieldName( m_dataModel->GetColFieldName( i ).ToUTF8() );
1536 cfg->m_FieldEditorPanel.field_widths[fieldName] = m_grid->GetColSize( i );
1537 }
1538 }
1539
1540 m_parent->FocusOnItem( nullptr );
1541
1542 wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, wxID_ANY );
1543
1544 if( wxWindow* parent = GetParent() )
1545 wxQueueEvent( parent, evt );
1546}
1547
1548
1550{
1551 std::vector<BOM_PRESET> ret;
1552
1553 for( const std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
1554 {
1555 if( !pair.second.readOnly )
1556 ret.emplace_back( pair.second );
1557 }
1558
1559 return ret;
1560}
1561
1562
1563void DIALOG_SYMBOL_FIELDS_TABLE::SetUserBomPresets( std::vector<BOM_PRESET>& aPresetList )
1564{
1565 // Reset to defaults
1567
1568 for( const BOM_PRESET& preset : aPresetList )
1569 {
1570 if( m_bomPresets.count( preset.name ) )
1571 continue;
1572
1573 m_bomPresets[preset.name] = preset;
1574
1575 m_bomPresetMRU.Add( preset.name );
1576 }
1577
1579}
1580
1581
1582void DIALOG_SYMBOL_FIELDS_TABLE::ApplyBomPreset( const wxString& aPresetName )
1583{
1584 updateBomPresetSelection( aPresetName );
1585
1586 wxCommandEvent dummy;
1588}
1589
1590
1592{
1593 if( m_bomPresets.count( aPreset.name ) )
1595 else
1596 m_currentBomPreset = nullptr;
1597
1600 else
1601 m_lastSelectedBomPreset = nullptr;
1602
1603 updateBomPresetSelection( aPreset.name );
1604 doApplyBomPreset( aPreset );
1605}
1606
1607
1609{
1610 m_bomPresets.clear();
1611 m_bomPresetMRU.clear();
1612
1613 // Load the read-only defaults
1614 for( const BOM_PRESET& preset : BOM_PRESET::BuiltInPresets() )
1615 {
1616 m_bomPresets[preset.name] = preset;
1617 m_bomPresets[preset.name].readOnly = true;
1618
1619 m_bomPresetMRU.Add( preset.name );
1620 }
1621}
1622
1623
1625{
1626 m_cbBomPresets->Clear();
1627
1628 // Build the layers preset list.
1629 // By default, the presetAllLayers will be selected
1630 int idx = 0;
1631 int default_idx = 0;
1632
1633 for( std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
1634 {
1635 m_cbBomPresets->Append( wxGetTranslation( pair.first ),
1636 static_cast<void*>( &pair.second ) );
1637
1638 if( pair.first == BOM_PRESET::DefaultEditing().name )
1639 default_idx = idx;
1640
1641 idx++;
1642 }
1643
1644 m_cbBomPresets->Append( wxT( "---" ) );
1645 m_cbBomPresets->Append( _( "Save preset..." ) );
1646 m_cbBomPresets->Append( _( "Delete preset..." ) );
1647
1648 // At least the built-in presets should always be present
1649 wxASSERT( !m_bomPresets.empty() );
1650
1651 // Default preset: all Boms
1652 m_cbBomPresets->SetSelection( default_idx );
1653 m_currentBomPreset = static_cast<BOM_PRESET*>( m_cbBomPresets->GetClientData( default_idx ) );
1654}
1655
1656
1658{
1660
1661 auto it = std::find_if( m_bomPresets.begin(), m_bomPresets.end(),
1662 [&]( const std::pair<const wxString, BOM_PRESET>& aPair )
1663 {
1664 const BOM_PRESET& preset = aPair.second;
1665
1666 // Check the simple settings first
1667 if( !( preset.sortAsc == current.sortAsc
1668 && preset.filterString == current.filterString
1669 && preset.groupSymbols == current.groupSymbols
1670 && preset.excludeDNP == current.excludeDNP
1671 && preset.includeExcludedFromBOM
1672 == current.includeExcludedFromBOM ) )
1673 {
1674 return false;
1675 }
1676
1677 // We should compare preset.name and current.name.
1678 // unfortunately current.name is empty because
1679 // m_dataModel->GetBomSettings() does not store the .name member
1680 // So use sortField member as a (not very efficient) auxiliary
1681 // filter.
1682 // sortField can be translated in m_bomPresets list,
1683 // so current.sortField needs to be translated
1684 // Probably this not efficient and error prone test should be
1685 // removed (JPC).
1686 if( preset.sortField != wxGetTranslation( current.sortField ) )
1687 return false;
1688
1689 // Only compare shown or grouped fields
1690 std::vector<BOM_FIELD> A, B;
1691
1692 for( const BOM_FIELD& field : preset.fieldsOrdered )
1693 {
1694 if( field.show || field.groupBy )
1695 A.emplace_back( field );
1696 }
1697
1698 for( const BOM_FIELD& field : current.fieldsOrdered )
1699 {
1700 if( field.show || field.groupBy )
1701 B.emplace_back( field );
1702 }
1703
1704 return A == B;
1705 } );
1706
1707 if( it != m_bomPresets.end() )
1708 {
1709 // Select the right m_cbBomPresets item.
1710 // but these items are translated if they are predefined items.
1711 bool do_translate = it->second.readOnly;
1712 wxString text = do_translate ? wxGetTranslation( it->first ) : it->first;
1713 m_cbBomPresets->SetStringSelection( text );
1714 }
1715 else
1716 {
1717 m_cbBomPresets->SetSelection( m_cbBomPresets->GetCount() - 3 ); // separator
1718 }
1719
1720 m_currentBomPreset = static_cast<BOM_PRESET*>(
1721 m_cbBomPresets->GetClientData( m_cbBomPresets->GetSelection() ) );
1722}
1723
1724
1726{
1727 // look at m_userBomPresets to know if aName is a read only preset, or a user preset.
1728 // Read only presets have translated names in UI, so we have to use
1729 // a translated name in UI selection.
1730 // But for a user preset name we should search for aName (not translated)
1731 wxString ui_label = aName;
1732
1733 for( std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
1734 {
1735 if( pair.first != aName )
1736 continue;
1737
1738 if( pair.second.readOnly == true )
1739 ui_label = wxGetTranslation( aName );
1740
1741 break;
1742 }
1743
1744 int idx = m_cbBomPresets->FindString( ui_label );
1745
1746 if( idx >= 0 && m_cbBomPresets->GetSelection() != idx )
1747 {
1748 m_cbBomPresets->SetSelection( idx );
1749 m_currentBomPreset = static_cast<BOM_PRESET*>( m_cbBomPresets->GetClientData( idx ) );
1750 }
1751 else if( idx < 0 )
1752 {
1753 m_cbBomPresets->SetSelection( m_cbBomPresets->GetCount() - 3 ); // separator
1754 }
1755}
1756
1757
1759{
1760 int count = m_cbBomPresets->GetCount();
1761 int index = m_cbBomPresets->GetSelection();
1762
1763 auto resetSelection =
1764 [&]()
1765 {
1766 if( m_currentBomPreset )
1767 m_cbBomPresets->SetStringSelection( m_currentBomPreset->name );
1768 else
1769 m_cbBomPresets->SetSelection( m_cbBomPresets->GetCount() - 3 );
1770 };
1771
1772 if( index == count - 3 )
1773 {
1774 // Separator: reject the selection
1775 resetSelection();
1776 return;
1777 }
1778 else if( index == count - 2 )
1779 {
1780 // Save current state to new preset
1781 wxString name;
1782
1785
1786 wxTextEntryDialog dlg( this, _( "BOM preset name:" ), _( "Save BOM Preset" ), name );
1787
1788 if( dlg.ShowModal() != wxID_OK )
1789 {
1790 resetSelection();
1791 return;
1792 }
1793
1794 name = dlg.GetValue();
1795 bool exists = m_bomPresets.count( name );
1796
1797 if( !exists )
1798 {
1800 m_bomPresets[name].readOnly = false;
1801 m_bomPresets[name].name = name;
1802 }
1803
1804 BOM_PRESET* preset = &m_bomPresets[name];
1805
1806 if( !exists )
1807 {
1808 index = m_cbBomPresets->Insert( name, index - 1, static_cast<void*>( preset ) );
1809 }
1810 else if( preset->readOnly )
1811 {
1812 wxMessageBox( _( "Default presets cannot be modified.\nPlease use a different name." ),
1813 _( "Error" ), wxOK | wxICON_ERROR, this );
1814 resetSelection();
1815 return;
1816 }
1817 else
1818 {
1819 // Ask the user if they want to overwrite the existing preset
1820 if( !IsOK( this, _( "Overwrite existing preset?" ) ) )
1821 {
1822 resetSelection();
1823 return;
1824 }
1825
1826 *preset = m_dataModel->GetBomSettings();
1827 preset->name = name;
1828
1829 index = m_cbBomPresets->FindString( name );
1830 m_bomPresetMRU.Remove( name );
1831 }
1832
1833 m_currentBomPreset = preset;
1834 m_cbBomPresets->SetSelection( index );
1835 m_bomPresetMRU.Insert( name, 0 );
1836
1837 return;
1838 }
1839 else if( index == count - 1 )
1840 {
1841 // Delete a preset
1842 wxArrayString headers;
1843 std::vector<wxArrayString> items;
1844
1845 headers.Add( _( "Presets" ) );
1846
1847 for( std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
1848 {
1849 if( !pair.second.readOnly )
1850 {
1851 wxArrayString item;
1852 item.Add( pair.first );
1853 items.emplace_back( item );
1854 }
1855 }
1856
1857 EDA_LIST_DIALOG dlg( this, _( "Delete Preset" ), headers, items );
1858 dlg.SetListLabel( _( "Select preset:" ) );
1859
1860 if( dlg.ShowModal() == wxID_OK )
1861 {
1862 wxString presetName = dlg.GetTextSelection();
1863 int idx = m_cbBomPresets->FindString( presetName );
1864
1865 if( idx != wxNOT_FOUND )
1866 {
1867 m_bomPresets.erase( presetName );
1868
1869 m_cbBomPresets->Delete( idx );
1870 m_currentBomPreset = nullptr;
1871
1872 m_bomPresetMRU.Remove( presetName );
1873 }
1874 }
1875
1876 resetSelection();
1877 return;
1878 }
1879
1880 BOM_PRESET* preset = static_cast<BOM_PRESET*>( m_cbBomPresets->GetClientData( index ) );
1881 m_currentBomPreset = preset;
1882
1883 m_lastSelectedBomPreset = ( !preset || preset->readOnly ) ? nullptr : preset;
1884
1885 if( preset )
1886 {
1887 doApplyBomPreset( *preset );
1889 m_currentBomPreset = preset;
1890
1891 if( !m_currentBomPreset->name.IsEmpty() )
1892 {
1893 m_bomPresetMRU.Remove( preset->name );
1894 m_bomPresetMRU.Insert( preset->name, 0 );
1895 }
1896 }
1897}
1898
1899
1901{
1902 // Disable rebuilds while we're applying the preset otherwise we'll be
1903 // rebuilding the model constantly while firing off wx events
1905
1906 // Basically, we apply the BOM preset to the data model and then
1907 // update our UI to reflect resulting the data model state, not the preset.
1908 m_dataModel->ApplyBomPreset( aPreset );
1909
1910 // BOM Presets can add, but not remove, columns, so make sure the field control
1911 // grid has all of them before starting
1912 for( int i = 0; i < m_dataModel->GetColsCount(); i++ )
1913 {
1914 const wxString& fieldName( m_dataModel->GetColFieldName( i ) );
1915 bool found = false;
1916
1917 for( int j = 0; j < m_fieldsCtrl->GetItemCount(); j++ )
1918 {
1919 if( m_fieldsCtrl->GetTextValue( j, FIELD_NAME_COLUMN ) == fieldName )
1920 {
1921 found = true;
1922 break;
1923 }
1924 }
1925
1926 // Properties like label, etc. will be added in the next loop
1927 if( !found )
1928 AddField( fieldName, GetTextVars( fieldName ), false, false );
1929 }
1930
1931 // Sync all fields
1932 for( int i = 0; i < m_fieldsCtrl->GetItemCount(); i++ )
1933 {
1934 const wxString& fieldName( m_fieldsCtrl->GetTextValue( i, FIELD_NAME_COLUMN ) );
1935 int col = m_dataModel->GetFieldNameCol( fieldName );
1936
1937 if( col == -1 )
1938 {
1939 wxASSERT_MSG( true, "Fields control has a field not found in the data model." );
1940 continue;
1941 }
1942
1944 std::string fieldNameStr( fieldName.ToUTF8() );
1945
1946 // Set column labels
1947 const wxString& label = m_dataModel->GetColLabelValue( col );
1948 m_fieldsCtrl->SetTextValue( label, i, LABEL_COLUMN );
1949 m_grid->SetColLabelValue( col, label );
1950
1951 if( cfg->m_FieldEditorPanel.field_widths.count( fieldNameStr ) )
1952 m_grid->SetColSize( col, cfg->m_FieldEditorPanel.field_widths.at( fieldNameStr ) );
1953
1954 // Set shown columns
1955 bool show = m_dataModel->GetShowColumn( col );
1956 m_fieldsCtrl->SetToggleValue( show, i, SHOW_FIELD_COLUMN );
1957
1958 if( show )
1959 m_grid->ShowCol( col );
1960 else
1961 m_grid->HideCol( col );
1962
1963 // Set grouped columns
1964 bool groupBy = m_dataModel->GetGroupColumn( col );
1965 m_fieldsCtrl->SetToggleValue( groupBy, i, GROUP_BY_COLUMN );
1966 }
1967
1968 m_grid->SetSortingColumn( m_dataModel->GetSortCol(), m_dataModel->GetSortAsc() );
1970 m_filter->ChangeValue( m_dataModel->GetFilter() );
1973
1975
1976 // This will rebuild all rows and columns in the model such that the order
1977 // and labels are right, then we refresh the shown grid data to match
1980 m_grid->ForceRefresh();
1981}
1982
1983
1984std::vector<BOM_FMT_PRESET> DIALOG_SYMBOL_FIELDS_TABLE::GetUserBomFmtPresets() const
1985{
1986 std::vector<BOM_FMT_PRESET> ret;
1987
1988 for( const std::pair<const wxString, BOM_FMT_PRESET>& pair : m_bomFmtPresets )
1989 {
1990 if( !pair.second.readOnly )
1991 ret.emplace_back( pair.second );
1992 }
1993
1994 return ret;
1995}
1996
1997
1998void DIALOG_SYMBOL_FIELDS_TABLE::SetUserBomFmtPresets( std::vector<BOM_FMT_PRESET>& aPresetList )
1999{
2000 // Reset to defaults
2002
2003 for( const BOM_FMT_PRESET& preset : aPresetList )
2004 {
2005 if( m_bomFmtPresets.count( preset.name ) )
2006 continue;
2007
2008 m_bomFmtPresets[preset.name] = preset;
2009
2010 m_bomFmtPresetMRU.Add( preset.name );
2011 }
2012
2014}
2015
2016
2017void DIALOG_SYMBOL_FIELDS_TABLE::ApplyBomFmtPreset( const wxString& aPresetName )
2018{
2019 updateBomFmtPresetSelection( aPresetName );
2020
2021 wxCommandEvent dummy;
2023}
2024
2025
2027{
2028 if( m_bomFmtPresets.count( aPreset.name ) )
2030 else
2031 m_currentBomFmtPreset = nullptr;
2032
2035 : nullptr;
2036
2038 doApplyBomFmtPreset( aPreset );
2039}
2040
2041
2043{
2044 m_bomFmtPresets.clear();
2045 m_bomFmtPresetMRU.clear();
2046
2047 // Load the read-only defaults
2048 for( const BOM_FMT_PRESET& preset : BOM_FMT_PRESET::BuiltInPresets() )
2049 {
2050 m_bomFmtPresets[preset.name] = preset;
2051 m_bomFmtPresets[preset.name].readOnly = true;
2052
2053 m_bomFmtPresetMRU.Add( preset.name );
2054 }
2055}
2056
2057
2059{
2060 m_cbBomFmtPresets->Clear();
2061
2062 // Build the layers preset list.
2063 // By default, the presetAllLayers will be selected
2064 int idx = 0;
2065 int default_idx = 0;
2066
2067 for( std::pair<const wxString, BOM_FMT_PRESET>& pair : m_bomFmtPresets )
2068 {
2069 m_cbBomFmtPresets->Append( wxGetTranslation( pair.first ),
2070 static_cast<void*>( &pair.second ) );
2071
2072 if( pair.first == BOM_FMT_PRESET::CSV().name )
2073 default_idx = idx;
2074
2075 idx++;
2076 }
2077
2078 m_cbBomFmtPresets->Append( wxT( "---" ) );
2079 m_cbBomFmtPresets->Append( _( "Save preset..." ) );
2080 m_cbBomFmtPresets->Append( _( "Delete preset..." ) );
2081
2082 // At least the built-in presets should always be present
2083 wxASSERT( !m_bomFmtPresets.empty() );
2084
2085 // Default preset: all Boms
2086 m_cbBomFmtPresets->SetSelection( default_idx );
2088 static_cast<BOM_FMT_PRESET*>( m_cbBomFmtPresets->GetClientData( default_idx ) );
2089}
2090
2091
2093{
2095
2096 auto it = std::find_if( m_bomFmtPresets.begin(), m_bomFmtPresets.end(),
2097 [&]( const std::pair<const wxString, BOM_FMT_PRESET>& aPair )
2098 {
2099 return ( aPair.second.fieldDelimiter == current.fieldDelimiter
2100 && aPair.second.stringDelimiter == current.stringDelimiter
2101 && aPair.second.refDelimiter == current.refDelimiter
2102 && aPair.second.refRangeDelimiter == current.refRangeDelimiter
2103 && aPair.second.keepTabs == current.keepTabs
2104 && aPair.second.keepLineBreaks == current.keepLineBreaks );
2105 } );
2106
2107 if( it != m_bomFmtPresets.end() )
2108 {
2109 // Select the right m_cbBomFmtPresets item.
2110 // but these items are translated if they are predefined items.
2111 bool do_translate = it->second.readOnly;
2112 wxString text = do_translate ? wxGetTranslation( it->first ) : it->first;
2113
2114 m_cbBomFmtPresets->SetStringSelection( text );
2115 }
2116 else
2117 {
2118 m_cbBomFmtPresets->SetSelection( m_cbBomFmtPresets->GetCount() - 3 ); // separator
2119 }
2120
2121 m_currentBomFmtPreset = static_cast<BOM_FMT_PRESET*>(
2122 m_cbBomFmtPresets->GetClientData( m_cbBomFmtPresets->GetSelection() ) );
2123}
2124
2125
2127{
2128 // look at m_userBomFmtPresets to know if aName is a read only preset, or a user preset.
2129 // Read only presets have translated names in UI, so we have to use
2130 // a translated name in UI selection.
2131 // But for a user preset name we should search for aName (not translated)
2132 wxString ui_label = aName;
2133
2134 for( std::pair<const wxString, BOM_FMT_PRESET>& pair : m_bomFmtPresets )
2135 {
2136 if( pair.first != aName )
2137 continue;
2138
2139 if( pair.second.readOnly == true )
2140 ui_label = wxGetTranslation( aName );
2141
2142 break;
2143 }
2144
2145 int idx = m_cbBomFmtPresets->FindString( ui_label );
2146
2147 if( idx >= 0 && m_cbBomFmtPresets->GetSelection() != idx )
2148 {
2149 m_cbBomFmtPresets->SetSelection( idx );
2151 static_cast<BOM_FMT_PRESET*>( m_cbBomFmtPresets->GetClientData( idx ) );
2152 }
2153 else if( idx < 0 )
2154 {
2155 m_cbBomFmtPresets->SetSelection( m_cbBomFmtPresets->GetCount() - 3 ); // separator
2156 }
2157}
2158
2159
2161{
2162 int count = m_cbBomFmtPresets->GetCount();
2163 int index = m_cbBomFmtPresets->GetSelection();
2164
2165 auto resetSelection =
2166 [&]()
2167 {
2169 m_cbBomFmtPresets->SetStringSelection( m_currentBomFmtPreset->name );
2170 else
2171 m_cbBomFmtPresets->SetSelection( m_cbBomFmtPresets->GetCount() - 3 );
2172 };
2173
2174 if( index == count - 3 )
2175 {
2176 // Separator: reject the selection
2177 resetSelection();
2178 return;
2179 }
2180 else if( index == count - 2 )
2181 {
2182 // Save current state to new preset
2183 wxString name;
2184
2187
2188 wxTextEntryDialog dlg( this, _( "BOM preset name:" ), _( "Save BOM Preset" ), name );
2189
2190 if( dlg.ShowModal() != wxID_OK )
2191 {
2192 resetSelection();
2193 return;
2194 }
2195
2196 name = dlg.GetValue();
2197 bool exists = m_bomFmtPresets.count( name );
2198
2199 if( !exists )
2200 {
2202 m_bomFmtPresets[name].readOnly = false;
2203 m_bomFmtPresets[name].name = name;
2204 }
2205
2207
2208 if( !exists )
2209 {
2210 index = m_cbBomFmtPresets->Insert( name, index - 1, static_cast<void*>( preset ) );
2211 }
2212 else if( preset->readOnly )
2213 {
2214 wxMessageBox( _( "Default presets cannot be modified.\nPlease use a different name." ),
2215 _( "Error" ), wxOK | wxICON_ERROR, this );
2216 resetSelection();
2217 return;
2218 }
2219 else
2220 {
2221 // Ask the user if they want to overwrite the existing preset
2222 if( !IsOK( this, _( "Overwrite existing preset?" ) ) )
2223 {
2224 resetSelection();
2225 return;
2226 }
2227
2228 *preset = GetCurrentBomFmtSettings();
2229 preset->name = name;
2230
2231 index = m_cbBomFmtPresets->FindString( name );
2232 m_bomFmtPresetMRU.Remove( name );
2233 }
2234
2235 m_currentBomFmtPreset = preset;
2236 m_cbBomFmtPresets->SetSelection( index );
2237 m_bomFmtPresetMRU.Insert( name, 0 );
2238
2239 return;
2240 }
2241 else if( index == count - 1 )
2242 {
2243 // Delete a preset
2244 wxArrayString headers;
2245 std::vector<wxArrayString> items;
2246
2247 headers.Add( _( "Presets" ) );
2248
2249 for( std::pair<const wxString, BOM_FMT_PRESET>& pair : m_bomFmtPresets )
2250 {
2251 if( !pair.second.readOnly )
2252 {
2253 wxArrayString item;
2254 item.Add( pair.first );
2255 items.emplace_back( item );
2256 }
2257 }
2258
2259 EDA_LIST_DIALOG dlg( this, _( "Delete Preset" ), headers, items );
2260 dlg.SetListLabel( _( "Select preset:" ) );
2261
2262 if( dlg.ShowModal() == wxID_OK )
2263 {
2264 wxString presetName = dlg.GetTextSelection();
2265 int idx = m_cbBomFmtPresets->FindString( presetName );
2266
2267 if( idx != wxNOT_FOUND )
2268 {
2269 m_bomFmtPresets.erase( presetName );
2270
2271 m_cbBomFmtPresets->Delete( idx );
2272 m_currentBomFmtPreset = nullptr;
2273
2274 m_bomFmtPresetMRU.Remove( presetName );
2275 }
2276 }
2277
2278 resetSelection();
2279 return;
2280 }
2281
2282 auto* preset = static_cast<BOM_FMT_PRESET*>( m_cbBomFmtPresets->GetClientData( index ) );
2283 m_currentBomFmtPreset = preset;
2284
2285 m_lastSelectedBomFmtPreset = ( !preset || preset->readOnly ) ? nullptr : preset;
2286
2287 if( preset )
2288 {
2289 doApplyBomFmtPreset( *preset );
2291 m_currentBomFmtPreset = preset;
2292
2293 if( !m_currentBomFmtPreset->name.IsEmpty() )
2294 {
2295 m_bomFmtPresetMRU.Remove( preset->name );
2296 m_bomFmtPresetMRU.Insert( preset->name, 0 );
2297 }
2298 }
2299}
2300
2301
2303{
2304 m_textFieldDelimiter->ChangeValue( aPreset.fieldDelimiter );
2305 m_textStringDelimiter->ChangeValue( aPreset.stringDelimiter );
2306 m_textRefDelimiter->ChangeValue( aPreset.refDelimiter );
2307 m_textRefRangeDelimiter->ChangeValue( aPreset.refRangeDelimiter );
2308 m_checkKeepTabs->SetValue( aPreset.keepTabs );
2309 m_checkKeepLineBreaks->SetValue( aPreset.keepLineBreaks );
2310
2311
2312 // Refresh the preview if that's the current page
2313 if( m_nbPages->GetSelection() == 1 )
2315}
2316
2317
2319{
2320 bool modified = false;
2321
2322 // Save our BOM presets
2323 std::vector<BOM_PRESET> presets;
2324
2325 for( const std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
2326 {
2327 if( !pair.second.readOnly )
2328 presets.emplace_back( pair.second );
2329 }
2330
2331 if( m_schSettings.m_BomPresets != presets )
2332 {
2333 modified = true;
2334 m_schSettings.m_BomPresets = presets;
2335 }
2336
2338 {
2339 modified = true;
2341 }
2342
2343 // Save our BOM Format presets
2344 std::vector<BOM_FMT_PRESET> fmts;
2345
2346 for( const std::pair<const wxString, BOM_FMT_PRESET>& pair : m_bomFmtPresets )
2347 {
2348 if( !pair.second.readOnly )
2349 fmts.emplace_back( pair.second );
2350 }
2351
2352 if( m_schSettings.m_BomFmtPresets != fmts )
2353 {
2354 modified = true;
2356 }
2357
2359 {
2360 modified = true;
2362 }
2363
2364 if( modified )
2365 m_parent->OnModify();
2366}
2367
2368
2370 std::vector<SCH_ITEM*>& aSchItem )
2371{
2372 SCH_REFERENCE_LIST allRefs;
2373 m_parent->Schematic().Hierarchy().GetSymbols( allRefs );
2374
2375 for( SCH_ITEM* item : aSchItem )
2376 {
2377 if( item->Type() == SCH_SYMBOL_T )
2378 {
2379 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2380
2381 // Don't add power symbols
2382 if( !symbol->IsMissingLibSymbol() && symbol->IsPower() )
2383 continue;
2384
2385 // Add all fields again in case this symbol has a new one
2386 for( SCH_FIELD& field : symbol->GetFields() )
2387 AddField( field.GetCanonicalName(), field.GetName(), true, false, true );
2388
2389 m_dataModel->AddReferences( getSymbolReferences( symbol, allRefs ) );
2390 }
2391 else if( item->Type() == SCH_SHEET_T )
2392 {
2393 std::set<SCH_SYMBOL*> symbols;
2394 SCH_REFERENCE_LIST refs = getSheetSymbolReferences( *static_cast<SCH_SHEET*>( item ) );
2395
2396 for( SCH_REFERENCE& ref : refs )
2397 symbols.insert( ref.GetSymbol() );
2398
2399 for( SCH_SYMBOL* symbol : symbols )
2400 {
2401 // Add all fields again in case this symbol has a new one
2402 for( SCH_FIELD& field : symbol->GetFields() )
2403 AddField( field.GetCanonicalName(), field.GetName(), true, false, true );
2404 }
2405
2406 m_dataModel->AddReferences( refs );
2407 }
2408 }
2409
2413}
2414
2415
2417 std::vector<SCH_ITEM*>& aSchItem )
2418{
2419 for( SCH_ITEM* item : aSchItem )
2420 {
2421 if( item->Type() == SCH_SYMBOL_T )
2422 {
2423 m_dataModel->RemoveSymbol( *static_cast<SCH_SYMBOL*>( item ) );
2424 }
2425 else if( item->Type() == SCH_SHEET_T )
2426 {
2428 getSheetSymbolReferences( *static_cast<SCH_SHEET*>( item ) ) );
2429 }
2430 }
2431
2435}
2436
2437
2439 std::vector<SCH_ITEM*>& aSchItem )
2440{
2441 SCH_REFERENCE_LIST allRefs;
2442 m_parent->Schematic().Hierarchy().GetSymbols( allRefs );
2443
2444 for( SCH_ITEM* item : aSchItem )
2445 {
2446 if( item->Type() == SCH_SYMBOL_T )
2447 {
2448 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2449
2450 // Don't add power symbols
2451 if( !symbol->IsMissingLibSymbol() && symbol->IsPower() )
2452 continue;
2453
2454 // Add all fields again in case this symbol has a new one
2455 for( SCH_FIELD& field : symbol->GetFields() )
2456 AddField( field.GetCanonicalName(), field.GetName(), true, false, true );
2457
2458 m_dataModel->UpdateReferences( getSymbolReferences( symbol, allRefs ) );
2459 }
2460 else if( item->Type() == SCH_SHEET_T )
2461 {
2462 std::set<SCH_SYMBOL*> symbols;
2463 SCH_REFERENCE_LIST refs = getSheetSymbolReferences( *static_cast<SCH_SHEET*>( item ) );
2464
2465 for( SCH_REFERENCE& ref : refs )
2466 symbols.insert( ref.GetSymbol() );
2467
2468 for( SCH_SYMBOL* symbol : symbols )
2469 {
2470 // Add all fields again in case this symbol has a new one
2471 for( SCH_FIELD& field : symbol->GetFields() )
2472 AddField( field.GetCanonicalName(), field.GetName(), true, false, true );
2473 }
2474
2476 }
2477 }
2478
2482}
2483
2484
2486{
2487 m_dataModel->SetPath( aSch.CurrentSheet() );
2488
2489 if( m_dataModel->GetScope() != FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE::SCOPE_ALL )
2490 {
2494 }
2495}
2496
2497
2499{
2500 m_grid->Connect(
2501 wxEVT_GRID_RANGE_SELECTED,
2502 wxGridRangeSelectEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnTableRangeSelected ),
2503 nullptr, this );
2504}
2505
2506
2508{
2509 m_grid->Disconnect(
2510 wxEVT_GRID_RANGE_SELECTED,
2511 wxGridRangeSelectEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnTableRangeSelected ),
2512 nullptr, this );
2513}
2514
2515
2518 SCH_REFERENCE_LIST& aCachedRefs )
2519{
2520 SCH_REFERENCE_LIST symbolRefs;
2521
2522 for( size_t i = 0; i < aCachedRefs.GetCount(); i++ )
2523 {
2524 SCH_REFERENCE& ref = aCachedRefs[i];
2525
2526 if( ref.GetSymbol() == aSymbol )
2527 {
2528 ref.Split(); // Figures out if we are annotated or not
2529 symbolRefs.AddItem( ref );
2530 }
2531 }
2532
2533 return symbolRefs;
2534}
2535
2536
2538{
2539 SCH_SHEET_LIST allSheets = m_parent->Schematic().Hierarchy();
2540 SCH_REFERENCE_LIST sheetRefs;
2541
2542 // We need to operate on all instances of the sheet
2543 for( const SCH_SHEET_INSTANCE& instance : aSheet.GetInstances() )
2544 {
2545 // For every sheet instance we need to get the current schematic sheet
2546 // instance that matches that particular sheet path from the root
2547 for( SCH_SHEET_PATH& basePath : allSheets )
2548 {
2549 if( basePath.Path() == instance.m_Path )
2550 {
2551 SCH_SHEET_PATH sheetPath = basePath;
2552 sheetPath.push_back( &aSheet );
2553
2554 // Create a list of all sheets in this path, starting with the path
2555 // of the sheet that we just deleted, then all of its subsheets
2556 SCH_SHEET_LIST subSheets;
2557 subSheets.push_back( sheetPath );
2558 allSheets.GetSheetsWithinPath( subSheets, sheetPath );
2559
2560 subSheets.GetSymbolsWithinPath( sheetRefs, sheetPath, false, false );
2561 break;
2562 }
2563 }
2564 }
2565
2566 for( SCH_REFERENCE& ref : sheetRefs )
2567 ref.Split();
2568
2569 return sheetRefs;
2570}
const char * name
Definition: DXF_plotter.cpp:59
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition: bitmap.cpp:110
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:52
int vertPixelsFromDU(int y) const
Convert an integer number of dialog units to pixels, vertically.
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:66
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
Definition: dialog_shim.h:194
int horizPixelsFromDU(int x) const
Convert an integer number of dialog units to pixels, horizontally.
void ClearModify()
void OnModify()
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
int ShowModal() override
Class DIALOG_SYMBOL_FIELDS_TABLE_BASE.
void OnTableColSize(wxGridSizeEvent &event) override
void OnSaveAndContinue(wxCommandEvent &aEvent) override
void OnSchItemsRemoved(SCHEMATIC &aSch, std::vector< SCH_ITEM * > &aSchItem) override
void OnPreviewRefresh(wxCommandEvent &event) override
void OnAddField(wxCommandEvent &event) override
SCH_REFERENCE_LIST getSheetSymbolReferences(SCH_SHEET &aSheet)
void SetUserBomPresets(std::vector< BOM_PRESET > &aPresetList)
void OnOk(wxCommandEvent &aEvent) override
void OnGroupSymbolsToggled(wxCommandEvent &event) override
void OnColumnItemToggled(wxDataViewEvent &event) override
void OnSchItemsAdded(SCHEMATIC &aSch, std::vector< SCH_ITEM * > &aSchItem) override
std::map< wxString, BOM_PRESET > m_bomPresets
void OnSchItemsChanged(SCHEMATIC &aSch, std::vector< SCH_ITEM * > &aSchItem) override
void ApplyBomFmtPreset(const wxString &aPresetName)
FIELDS_EDITOR_GRID_DATA_MODEL * m_dataModel
void updateBomPresetSelection(const wxString &aName)
void OnTableItemContextMenu(wxGridEvent &event) override
void updateBomFmtPresetSelection(const wxString &aName)
void OnFilterText(wxCommandEvent &aEvent) override
void OnScopeChanged(wxCommandEvent &aEvent) override
std::map< FIELD_T, int > m_mandatoryFieldListIndexes
void OnRemoveField(wxCommandEvent &event) override
void OnTableCellClick(wxGridEvent &event) override
void OnShowExcludedToggled(wxCommandEvent &event) override
void OnColLabelChange(wxDataViewEvent &aEvent)
void doApplyBomFmtPreset(const BOM_FMT_PRESET &aPreset)
void onBomPresetChanged(wxCommandEvent &aEvent)
void OnTableValueChanged(wxGridEvent &event) override
void OnExport(wxCommandEvent &aEvent) override
void OnClose(wxCloseEvent &aEvent) override
void OnSchSheetChanged(SCHEMATIC &aSch) override
void OnTableRangeSelected(wxGridRangeSelectEvent &aEvent)
std::vector< BOM_FMT_PRESET > GetUserBomFmtPresets() const
void OnCancel(wxCommandEvent &aEvent) override
void OnFilterMouseMoved(wxMouseEvent &event) override
std::map< wxString, BOM_FMT_PRESET > m_bomFmtPresets
DIALOG_SYMBOL_FIELDS_TABLE(SCH_EDIT_FRAME *parent, JOB_EXPORT_SCH_BOM *aJob=nullptr)
BOM_FMT_PRESET GetCurrentBomFmtSettings()
Returns a formatting configuration corresponding to the values in the UI controls of the dialog.
void AddField(const wxString &displayName, const wxString &aCanonicalName, bool show, bool groupBy, bool addedByUser=false)
SCH_REFERENCE_LIST getSymbolReferences(SCH_SYMBOL *aSymbol, SCH_REFERENCE_LIST &aCachedRefs)
void OnSizeFieldList(wxSizeEvent &event) override
void doApplyBomPreset(const BOM_PRESET &aPreset)
void OnPageChanged(wxNotebookEvent &event) override
void SetUserBomFmtPresets(std::vector< BOM_FMT_PRESET > &aPresetList)
void OnRegroupSymbols(wxCommandEvent &aEvent) override
std::vector< BOM_PRESET > GetUserBomPresets() const
void OnOutputFileBrowseClicked(wxCommandEvent &event) override
void LoadFieldNames()
Construct the rows of m_fieldsCtrl and the columns of m_dataModel from a union of all field names in ...
void onBomFmtPresetChanged(wxCommandEvent &aEvent)
void ApplyBomPreset(const wxString &aPresetName)
void OnExcludeDNPToggled(wxCommandEvent &event) override
void OnRenameField(wxCommandEvent &event) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
EDA_ITEM * GetParent() const
Definition: eda_item.h:103
A dialog which shows:
wxString GetTextSelection(int aColumn=0)
Return the selected text from aColumn in the wxListCtrl in the dialog.
void SetListLabel(const wxString &aLabel)
PANEL_FIELD_EDITOR m_FieldEditorPanel
int GetFieldNameCol(const wxString &aFieldName) const
wxString GetColFieldName(int aCol)
void ApplyBomPreset(const BOM_PRESET &preset)
std::vector< SCH_REFERENCE > GetRowReferences(int aRow) const
wxString GetColLabelValue(int aCol) override
void SetPath(const SCH_SHEET_PATH &aPath)
void RenameColumn(int aCol, const wxString &newName)
wxString Export(const BOM_FMT_PRESET &settings)
void AddColumn(const wxString &aFieldName, const wxString &aLabel, bool aAddedByUser)
void SetSorting(int aCol, bool ascending)
void SetFilter(const wxString &aFilter)
void SetColAttr(wxGridCellAttr *aAttr, int aCol) override
static const wxString ITEM_NUMBER_VARIABLE
void SetIncludeExcludedFromBOM(bool include)
void UpdateReferences(const SCH_REFERENCE_LIST &aRefs)
void ApplyData(SCH_COMMIT &aCommit)
static const wxString QUANTITY_VARIABLE
void SetGroupColumn(int aCol, bool group)
void RemoveSymbol(const SCH_SYMBOL &aSymbol)
std::vector< BOM_FIELD > GetFieldsOrdered()
void SetColLabelValue(int aCol, const wxString &aLabel) override
void MoveColumn(int aCol, int aNewPos)
void RemoveReferences(const SCH_REFERENCE_LIST &aRefs)
void SetShowColumn(int aCol, bool show)
void AddReferences(const SCH_REFERENCE_LIST &aRefs)
void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent) override
FIELDS_EDITOR_GRID_TRICKS(DIALOG_SHIM *aParent, WX_GRID *aGrid, wxDataViewListCtrl *aFieldsCtrl, FIELDS_EDITOR_GRID_DATA_MODEL *aDataModel)
void doPopupSelection(wxCommandEvent &event) override
FIELDS_EDITOR_GRID_DATA_MODEL * m_dataModel
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition: grid_tricks.h:61
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.
Definition: grid_tricks.h:125
std::vector< wxString > m_fieldsLabels
std::vector< wxString > m_fieldsOrdered
wxString GetSettingsDialogTitle() const override
std::vector< wxString > m_fieldsGroupBy
void SetConfiguredOutputPath(const wxString &aPath)
Sets the configured output path for the job, this path is always saved to file.
Definition: job.cpp:153
wxString GetConfiguredOutputPath() const
Returns the configured output path for the job.
Definition: job.h:226
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:55
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:65
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:406
static REPORTER & GetInstance()
Definition: reporter.cpp:118
static SEARCH_STACK * SchSearchS(PROJECT *aProject)
Accessor for Eeschema search stack.
Definition: project_sch.cpp:41
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition: project.cpp:370
BOM_FMT_PRESET m_BomFmtSettings
List of stored BOM format presets.
std::vector< BOM_PRESET > m_BomPresets
std::vector< BOM_FMT_PRESET > m_BomFmtPresets
BOM_PRESET m_BomSettings
List of stored BOM presets.
Holds all the data relating to one schematic.
Definition: schematic.h:69
void RemoveListener(SCHEMATIC_LISTENER *aListener)
Remove the specified listener.
Definition: schematic.cpp:810
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
Definition: schematic.cpp:300
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
Definition: schematic.cpp:208
void AddListener(SCHEMATIC_LISTENER *aListener)
Add a listener to the schematic to receive calls whenever something on the schematic has been modifie...
Definition: schematic.cpp:803
bool ResolveTextVar(const SCH_SHEET_PATH *aSheetPath, wxString *token, int aDepth) const
Definition: schematic.cpp:247
SCH_SHEET_PATH & CurrentSheet() const
Definition: schematic.h:148
void SyncView()
Mark all items for refresh.
EESCHEMA_SETTINGS * eeconfig() const
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
Definition: sch_commit.cpp:433
Handle actions specific to the schematic editor.
Schematic editor (Eeschema) main window.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void SetCurrentSheet(const SCH_SHEET_PATH &aSheet)
bool SaveProject(bool aSaveAs=false)
Save the currently-open schematic (including its hierarchy) and associated project.
void FocusOnItem(SCH_ITEM *aItem)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:167
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
size_t GetCount() const
void AddItem(const SCH_REFERENCE &aItem)
A helper to define a symbol's reference designator in a schematic.
void Split()
Attempt to split the reference designator into a name (U) and number (1).
SCH_SYMBOL * GetSymbol() const
void SyncSelection(const std::optional< SCH_SHEET_PATH > &targetSheetPath, SCH_ITEM *focusItem, const std::vector< SCH_ITEM * > &items)
int ClearSelection(const TOOL_EVENT &aEvent)
Select all visible items in sheet.
SCH_SELECTION & GetSelection()
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets.
void GetSheetsWithinPath(std::vector< SCH_SHEET_PATH > &aSheets, const SCH_SHEET_PATH &aSheetPath) const
Add a SCH_SHEET_PATH object to aSheets for each sheet in the list that are contained within aSheetPat...
void GetSymbolsWithinPath(SCH_REFERENCE_LIST &aReferences, const SCH_SHEET_PATH &aSheetPath, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets that are contained wi...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:47
const std::vector< SCH_SHEET_INSTANCE > & GetInstances() const
Definition: sch_sheet.h:429
Schematic symbol object.
Definition: sch_symbol.h:75
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
Definition: sch_symbol.cpp:841
bool IsMissingLibSymbol() const
Check to see if the library symbol is set to the dummy library symbol.
Definition: sch_symbol.cpp:209
bool IsPower() const override
void SetBitmap(const wxBitmapBundle &aBmp)
const TEMPLATE_FIELDNAMES & GetTemplateFieldNames()
Return a template field name list for read only access.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
Master controller class:
Definition: tool_manager.h:62
void SetTable(wxGridTableBase *table, bool aTakeOwnership=false)
Hide wxGrid's SetTable() method with one which doesn't mess up the grid column widths when setting th...
Definition: wx_grid.cpp:275
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:644
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:351
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition: common.cpp:59
bool EnsureFileDirectoryExists(wxFileName *aTargetFullFileName, const wxString &aBaseFilename, REPORTER *aReporter)
Make aTargetFullFileName absolute and create the path of this file if it doesn't yet exist.
Definition: common.cpp:372
bool IsTextVar(const wxString &aSource)
Returns true if the string is a text var, e.g starts with ${.
Definition: common.cpp:133
wxString GetTextVars(const wxString &aSource)
Returns any variables unexpanded, e.g.
Definition: common.cpp:121
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:143
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:249
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:221
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:130
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
This file is part of the common library.
wxDEFINE_EVENT(EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, wxCommandEvent)
#define COLUMN_MARGIN
#define _(s)
bool GetAssociatedDocument(wxWindow *aParent, const wxString &aDocName, PROJECT *aProject, SEARCH_STACK *aPaths, EMBEDDED_FILES *aFiles)
Open a document (file) with the suitable browser.
Definition: eda_doc.cpp:62
This file is part of the common library.
#define LABEL_COLUMN
#define DISPLAY_NAME_COLUMN
#define FIELD_NAME_COLUMN
#define GROUP_BY_COLUMN
#define SHOW_FIELD_COLUMN
@ FRAME_FOOTPRINT_CHOOSER
Definition: frame_type.h:44
@ GRIDTRICKS_FIRST_SHOWHIDE
Definition: grid_tricks.h:51
@ GRIDTRICKS_FIRST_CLIENT_ID
Definition: grid_tricks.h:48
static const std::string CsvFileExtension
static wxString CsvFileWildcard()
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition: wxgtk/ui.cpp:252
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:156
KICOMMON_API wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
Definition: ui_common.cpp:78
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:100
@ HIGHLIGHT_SYMBOL
std::vector< FAB_LAYER_COLOR > dummy
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:403
wxString label
Definition: bom_settings.h:33
bool groupBy
Definition: bom_settings.h:35
wxString name
Definition: bom_settings.h:32
wxString fieldDelimiter
Definition: bom_settings.h:83
wxString name
Definition: bom_settings.h:81
static BOM_FMT_PRESET CSV()
static std::vector< BOM_FMT_PRESET > BuiltInPresets()
wxString stringDelimiter
Definition: bom_settings.h:84
wxString refRangeDelimiter
Definition: bom_settings.h:86
wxString refDelimiter
Definition: bom_settings.h:85
wxString name
Definition: bom_settings.h:51
static BOM_PRESET DefaultEditing()
wxString sortField
Definition: bom_settings.h:54
bool groupSymbols
Definition: bom_settings.h:57
std::vector< BOM_FIELD > fieldsOrdered
Definition: bom_settings.h:53
bool includeExcludedFromBOM
Definition: bom_settings.h:59
bool readOnly
Definition: bom_settings.h:52
static std::vector< BOM_PRESET > BuiltInPresets()
bool excludeDNP
Definition: bom_settings.h:58
bool sortAsc
Definition: bom_settings.h:55
wxString filterString
Definition: bom_settings.h:56
std::map< std::string, int > field_widths
A simple container for sheet instance information.
Hold a name of a symbol's field, field value, and default visibility.
Definition for symbol library class.
wxString GetDefaultFieldName(FIELD_T aFieldId, bool aTranslateForHI)
Return a default symbol field name for a mandatory field type.
#define DO_TRANSLATE
#define MANDATORY_FIELDS
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
wxString GetCanonicalFieldName(FIELD_T aFieldType)
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
@ SCH_SHEET_T
Definition: typeinfo.h:174
Definition of file extensions used in Kicad.