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>
41#include <schematic.h>
43#include <kiplatform/ui.h>
47#include <widgets/wx_grid.h>
48#include <wx/debug.h>
49#include <wx/ffile.h>
50#include <wx/grid.h>
51#include <wx/textdlg.h>
52#include <wx/filedlg.h>
53#include <wx/msgdlg.h>
56#include <fields_data_model.h>
57#include <eda_list_dialog.h>
58#include <project_sch.h>
60
61wxDEFINE_EVENT( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, wxCommandEvent );
62
63#ifdef __WXMAC__
64#define COLUMN_MARGIN 3
65#else
66#define COLUMN_MARGIN 15
67#endif
68
70
71
72enum
73{
76};
77
79{
80public:
82 wxDataViewListCtrl* aFieldsCtrl,
83 FIELDS_EDITOR_GRID_DATA_MODEL* aDataModel ) :
84 GRID_TRICKS( aGrid ),
85 m_dlg( aParent ),
86 m_fieldsCtrl( aFieldsCtrl ),
87 m_dataModel( aDataModel )
88 {}
89
90protected:
91 void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) override
92 {
93 if( m_grid->GetGridCursorCol() == FOOTPRINT_FIELD )
94 {
95 menu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ),
96 _( "Browse for footprint" ) );
97 menu.AppendSeparator();
98 }
99 else if( m_grid->GetGridCursorCol() == DATASHEET_FIELD )
100 {
101 menu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ),
102 _( "Show datasheet in browser" ) );
103 menu.AppendSeparator();
104 }
105
106 GRID_TRICKS::showPopupMenu( menu, aEvent );
107 }
108
109 void doPopupSelection( wxCommandEvent& event ) override
110 {
111 if( event.GetId() == MYID_SELECT_FOOTPRINT )
112 {
113 // pick a footprint using the footprint picker.
114 wxString fpid = m_grid->GetCellValue( m_grid->GetGridCursorRow(), FOOTPRINT_FIELD );
115
117 m_dlg ) )
118 {
119 if( frame->ShowModal( &fpid, m_dlg ) )
120 m_grid->SetCellValue( m_grid->GetGridCursorRow(), FOOTPRINT_FIELD, fpid );
121
122 frame->Destroy();
123 }
124 }
125 else if (event.GetId() == MYID_SHOW_DATASHEET )
126 {
127 wxString datasheet_uri = m_grid->GetCellValue( m_grid->GetGridCursorRow(),
129 GetAssociatedDocument( m_dlg, datasheet_uri, &m_dlg->Prj(),
131 }
132 else
133 {
134 // We have grid tricks events to show/hide the columns from the popup menu
135 // and we need to make sure the data model is updated to match the grid,
136 // so do it through our code instead
137 if( event.GetId() >= GRIDTRICKS_FIRST_SHOWHIDE )
138 {
139 // Pop-up column order is the order of the shown fields, not the
140 // fieldsCtrl order
141 int col = event.GetId() - GRIDTRICKS_FIRST_SHOWHIDE;
142
143 bool show = !m_dataModel->GetShowColumn( col );
144
145 // Convert data model column to by iterating over m_fieldsCtrl rows
146 // and finding the matching field name
147 wxString fieldName = m_dataModel->GetColFieldName( col );
148
149 for( int row = 0; row < m_fieldsCtrl->GetItemCount(); row++ )
150 {
151 if( m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN ) == fieldName )
152 {
153 if( m_grid->CommitPendingChanges( false ) )
154 m_fieldsCtrl->SetToggleValue( show, row, SHOW_FIELD_COLUMN );
155
156 break;
157 }
158 }
159 }
160 else
161 {
163 }
164 }
165 }
166
168 wxDataViewListCtrl* m_fieldsCtrl;
170};
171
172
174 JOB_EXPORT_SCH_BOM* aJob ) :
176 m_currentBomPreset( nullptr ),
177 m_lastSelectedBomPreset( nullptr ),
178 m_parent( parent ),
179 m_schSettings( parent->Schematic().Settings() ),
180 m_job( aJob )
181{
182 // Get all symbols from the list of schematic sheets
184
185 m_bRefresh->SetBitmap( KiBitmapBundle( BITMAPS::small_refresh ) );
186 m_bRefreshPreview->SetBitmap( KiBitmapBundle( BITMAPS::small_refresh ) );
187 m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
188
189 m_addFieldButton->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
190 m_removeFieldButton->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
191 m_renameFieldButton->SetBitmap( KiBitmapBundle( BITMAPS::small_edit ) );
192
193 m_removeFieldButton->Enable( false );
194 m_renameFieldButton->Enable( false );
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" ) );
226
227 LoadFieldNames(); // loads rows into m_fieldsCtrl and columns into m_dataModel
228
229 // Now that the fields are loaded we can set the initial location of the splitter
230 // based on the list width. Again, SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails us on GTK.
232 m_labelColWidth = 0;
233
234 int colWidth = 0;
235
236 for( int row = 0; row < m_fieldsCtrl->GetItemCount(); ++row )
237 {
238 const wxString& displayName = m_fieldsCtrl->GetTextValue( row, DISPLAY_NAME_COLUMN );
239 colWidth = std::max( colWidth, KIUI::GetTextSize( displayName, m_fieldsCtrl ).x );
240
241 const wxString& label = m_fieldsCtrl->GetTextValue( row, LABEL_COLUMN );
242 colWidth = std::max( colWidth, KIUI::GetTextSize( label, m_fieldsCtrl ).x );
243 }
244
245 m_fieldNameColWidth = colWidth + 20;
246 m_labelColWidth = colWidth + 20;
247
249
250 m_fieldsCtrl->GetColumn( DISPLAY_NAME_COLUMN )->SetWidth( m_fieldNameColWidth );
251 m_fieldsCtrl->GetColumn( LABEL_COLUMN )->SetWidth( m_labelColWidth );
252
253 // This is used for data only. Don't show it to the user.
254 m_fieldsCtrl->GetColumn( FIELD_NAME_COLUMN )->SetHidden( true );
255
256 m_splitterMainWindow->SetMinimumPaneSize( fieldsMinWidth );
257 m_splitterMainWindow->SetSashPosition( fieldsMinWidth + 40 );
258
259 m_grid->UseNativeColHeader( true );
260 m_grid->SetTable( m_dataModel, true );
261
262 // must be done after SetTable(), which appears to re-set it
263 m_grid->SetSelectionMode( wxGrid::wxGridSelectCells );
264
265 // add Cut, Copy, and Paste to wxGrid
266 m_grid->PushEventHandler( new FIELDS_EDITOR_GRID_TRICKS( this, m_grid, m_fieldsCtrl,
267 m_dataModel ) );
268
269 // give a bit more room for comboboxes
270 m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
271
272 // Load our BOM view presets
274
276
277 if( m_job )
278 {
279 SetTitle( m_job->GetSettingsDialogTitle() );
280
281 preset.name = m_job->m_bomPresetName;
282 preset.excludeDNP = m_job->m_excludeDNP;
285 preset.sortAsc = m_job->m_sortAsc;
286 preset.sortField = m_job->m_sortField;
287 preset.groupSymbols = ( m_job->m_fieldsGroupBy.size() > 0 );
288
289 preset.fieldsOrdered.clear();
290
291 size_t i = 0;
292
293 for( const wxString& fieldName : m_job->m_fieldsOrdered )
294 {
295 BOM_FIELD field;
296 field.name = fieldName;
297 field.show = !fieldName.StartsWith( wxT( "__" ), &field.name );
298 field.groupBy = std::find( m_job->m_fieldsGroupBy.begin(), m_job->m_fieldsGroupBy.end(),
299 field.name )
300 != m_job->m_fieldsGroupBy.end();
301
302 if( ( m_job->m_fieldsLabels.size() > i ) && !m_job->m_fieldsLabels[i].IsEmpty() )
303 field.label = m_job->m_fieldsLabels[i];
304 else if( IsTextVar( field.name ) )
305 field.label = GetTextVars( field.name );
306 else
307 field.label = field.name;
308
309 preset.fieldsOrdered.emplace_back( field );
310 i++;
311 }
312 }
313
314 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
315 // non-job versions (which have different sizes).
316 m_hash_key = TO_UTF8( GetTitle() );
317
318 ApplyBomPreset( preset );
320
321 // Load BOM export format presets
324
325 if( m_job )
326 {
327 fmtPreset.name = m_job->m_bomFmtPresetName;
330 fmtPreset.keepTabs = m_job->m_keepTabs;
331 fmtPreset.refDelimiter = m_job->m_refDelimiter;
334 }
335
336 ApplyBomFmtPreset( fmtPreset );
338
340 m_grid->ClearSelection();
341
343
345
348
349 wxSize dlgSize( panelCfg.width > 0 ? panelCfg.width : horizPixelsFromDU( 600 ),
350 panelCfg.height > 0 ? panelCfg.height : vertPixelsFromDU( 300 ) );
351 SetSize( dlgSize );
352
353 m_nbPages->SetSelection( cfg->m_FieldEditorPanel.page );
354
356 {
357 case 0: m_radioHighlight->SetValue( true ); break;
358 case 1: m_radioSelect->SetValue( true ); break;
359 case 2: m_radioOff->SetValue( true ); break;
360 }
361
362 switch( cfg->m_FieldEditorPanel.scope )
363 {
364 case SCOPE::SCOPE_ALL: m_radioProject->SetValue( true ); break;
365 case SCOPE::SCOPE_SHEET: m_radioCurrentSheet->SetValue( true ); break;
366 case SCOPE::SCOPE_SHEET_RECURSIVE: m_radioRecursive->SetValue( true ); break;
367 }
368
369 if( m_job )
370 {
372 }
373 else
374 {
376 }
377
378 Center();
379
380 // Connect Events
381 m_grid->Connect( wxEVT_GRID_COL_SORT,
382 wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColSort ), nullptr, this );
383 m_grid->Connect( wxEVT_GRID_COL_MOVE,
384 wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColMove ), nullptr, this );
387 this );
388 m_fieldsCtrl->Bind( wxEVT_DATAVIEW_ITEM_VALUE_CHANGED,
390
391 if( !m_job )
392 {
393 // Start listening for schematic changes
394 m_parent->Schematic().AddListener( this );
395 }
396 else
397 {
398 // Don't allow editing
399 m_grid->EnableEditing( false );
400 m_buttonApply->Hide();
401 m_buttonExport->Hide();
402
404 }
405}
406
407
409{
410 wxGridCellAttr* attr = new wxGridCellAttr;
411 attr->SetReadOnly( false );
412
413 // Set some column types to specific editors
414 if( m_dataModel->ColIsReference( aCol ) )
415 {
416 attr->SetReadOnly();
417 m_grid->SetColAttr( aCol, attr );
418 }
420 {
421 attr->SetEditor( new GRID_CELL_FPID_EDITOR( this, wxEmptyString ) );
422 m_grid->SetColAttr( aCol, attr );
423 }
425 {
426 // set datasheet column viewer button
427 attr->SetEditor( new GRID_CELL_URL_EDITOR( this, PROJECT_SCH::SchSearchS( &Prj() ),
428 &m_parent->Schematic() ) );
429 m_grid->SetColAttr( aCol, attr );
430 }
431 else if( m_dataModel->ColIsQuantity( aCol ) || m_dataModel->ColIsItemNumber( aCol ) )
432 {
433 attr->SetReadOnly();
434 m_grid->SetColAttr( aCol, attr );
435 m_grid->SetColFormatNumber( aCol );
436 }
437 else if( m_dataModel->ColIsAttribute( aCol ) )
438 {
439 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
440 m_grid->SetColAttr( aCol, attr );
441 m_grid->SetColFormatBool( aCol );
442 }
443 else if( IsTextVar( m_dataModel->GetColFieldName( aCol ) ) )
444 {
445 attr->SetReadOnly();
446 m_grid->SetColAttr( aCol, attr );
447 }
448 else
449 {
450 attr->SetEditor( m_grid->GetDefaultEditor() );
451 m_grid->SetColAttr( aCol, attr );
452 m_grid->SetColFormatCustom( aCol, wxGRID_VALUE_STRING );
453 }
454}
455
456
458{
460 wxSize defaultDlgSize = ConvertDialogToPixels( wxSize( 600, 300 ) );
461
462 // Restore column sorting order and widths
463 m_grid->AutoSizeColumns( false );
464 int sortCol = 0;
465 bool sortAscending = true;
466
467 for( int col = 0; col < m_grid->GetNumberCols(); ++col )
468 {
470
471 if( col == m_dataModel->GetSortCol() )
472 {
473 sortCol = col;
474 sortAscending = m_dataModel->GetSortAsc();
475 }
476 }
477
478 // sync m_grid's column visibilities to Show checkboxes in m_fieldsCtrl
479 for( int i = 0; i < m_fieldsCtrl->GetItemCount(); ++i )
480 {
481 int col = m_dataModel->GetFieldNameCol( m_fieldsCtrl->GetTextValue( i,
483
484 if( col == -1 )
485 continue;
486
487 bool show = m_fieldsCtrl->GetToggleValue( i, SHOW_FIELD_COLUMN );
488 m_dataModel->SetShowColumn( col, show );
489
490 if( show )
491 {
492 m_grid->ShowCol( col );
493
494 std::string key( m_dataModel->GetColFieldName( col ).ToUTF8() );
495
496 if( cfg->m_FieldEditorPanel.field_widths.count( key )
497 && ( cfg->m_FieldEditorPanel.field_widths.at( key ) > 0 ) )
498 {
499 m_grid->SetColSize( col, cfg->m_FieldEditorPanel.field_widths.at( key ) );
500 }
501 else
502 {
503 int textWidth = m_dataModel->GetDataWidth( col ) + COLUMN_MARGIN;
504 int maxWidth = defaultDlgSize.x / 3;
505
506 m_grid->SetColSize( col, std::clamp( textWidth, 100, maxWidth ) );
507 }
508 }
509 else
510 {
511 m_grid->HideCol( col );
512 }
513 }
514
515 m_dataModel->SetSorting( sortCol, sortAscending );
516 m_grid->SetSortingColumn( sortCol, sortAscending );
517}
518
519
521{
522 // Disconnect Events
523 m_grid->Disconnect( wxEVT_GRID_COL_SORT,
524 wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColSort ), nullptr,
525 this );
526 m_grid->Disconnect( wxEVT_GRID_COL_SORT,
527 wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColMove ), nullptr,
528 this );
529
530 // Delete the GRID_TRICKS.
531 m_grid->PopEventHandler( true );
532
533 // we gave ownership of m_dataModel to the wxGrid...
534}
535
536
538{
539 if( !wxDialog::TransferDataFromWindow() )
540 return false;
541
543 EE_SELECTION_TOOL* selectionTool = toolMgr->GetTool<EE_SELECTION_TOOL>();
544 EE_SELECTION& selection = selectionTool->GetSelection();
545 SCH_SYMBOL* symbol = nullptr;
546
547 UpdateScope();
548
549 if( selection.GetSize() == 1 )
550 {
551 EDA_ITEM* item = selection.Front();
552
553 if( item->Type() == SCH_SYMBOL_T )
554 symbol = (SCH_SYMBOL*) item;
555 else if( item->GetParent() && item->GetParent()->Type() == SCH_SYMBOL_T )
556 symbol = (SCH_SYMBOL*) item->GetParent();
557 }
558
559 if( symbol )
560 {
561 for( int row = 0; row < m_dataModel->GetNumberRows(); ++row )
562 {
563 std::vector<SCH_REFERENCE> references = m_dataModel->GetRowReferences( row );
564 bool found = false;
565
566 for( const SCH_REFERENCE& ref : references )
567 {
568 if( ref.GetSymbol() == symbol )
569 {
570 found = true;
571 break;
572 }
573 }
574
575 if( found )
576 {
577 // Find the value column and the reference column if they're shown
578 int valueCol = -1;
579 int refCol = -1;
580 int anyCol = -1;
581
582 for( int col = 0; col < m_dataModel->GetNumberCols(); col++ )
583 {
584 if( m_dataModel->ColIsValue( col ) )
585 valueCol = col;
586 else if( m_dataModel->ColIsReference( col ) )
587 refCol = col;
588 else if( anyCol == -1 && m_dataModel->GetShowColumn( col ) )
589 anyCol = col;
590 }
591
592 if( valueCol != -1 && m_dataModel->GetShowColumn( valueCol ) )
593 m_grid->GoToCell( row, valueCol );
594 else if( refCol != -1 && m_dataModel->GetShowColumn( refCol ) )
595 m_grid->GoToCell( row, refCol );
596 else if( anyCol != -1 )
597 m_grid->GoToCell( row, anyCol );
598
599 break;
600 }
601 }
602 }
603
604 // We don't want table range selection events to happen until we've loaded the data or we
605 // we'll clear our selection as the grid is built before the code above can get the
606 // user's current selection.
608
609 return true;
610}
611
612
614{
616 return false;
617
618 if( !wxDialog::TransferDataFromWindow() )
619 return false;
620
621 if( m_job )
622 {
623 // and exit, don't even dream of saving changes from the data model
624 return true;
625 }
626
627 SCH_COMMIT commit( m_parent );
628 SCH_SHEET_PATH currentSheet = m_parent->GetCurrentSheet();
629
630 std::function<void( SCH_SYMBOL&, SCH_SHEET_PATH & aPath )> changeHandler =
631 [&commit]( SCH_SYMBOL& aSymbol, SCH_SHEET_PATH& aPath ) -> void
632 {
633 commit.Modify( &aSymbol, aPath.LastScreen() );
634 };
635
636 m_dataModel->ApplyData( changeHandler );
637
638 commit.Push( wxS( "Symbol Fields Table Edit" ) );
639
640 // Reset the view to where we left the user
641 m_parent->SetCurrentSheet( currentSheet );
643 m_parent->Refresh();
644
646
647 return true;
648}
649
650
651void DIALOG_SYMBOL_FIELDS_TABLE::AddField( const wxString& aFieldName, const wxString& aLabelValue,
652 bool show, bool groupBy, bool addedByUser )
653{
654 // Users can add fields with variable names that match the special names in the grid,
655 // e.g. ${QUANTITY} so make sure we don't add them twice
656 for( int i = 0; i < m_fieldsCtrl->GetItemCount(); i++ )
657 {
658 if( m_fieldsCtrl->GetTextValue( i, FIELD_NAME_COLUMN ) == aFieldName )
659 return;
660 }
661
662 m_dataModel->AddColumn( aFieldName, aLabelValue, addedByUser );
663
664 wxVector<wxVariant> fieldsCtrlRow;
665 std::string key( aFieldName.ToUTF8() );
666
667 // Don't change these to emplace_back: some versions of wxWidgets don't support it
668 fieldsCtrlRow.push_back( wxVariant( aFieldName ) );
669 fieldsCtrlRow.push_back( wxVariant( aLabelValue ) );
670 fieldsCtrlRow.push_back( wxVariant( show ) );
671 fieldsCtrlRow.push_back( wxVariant( groupBy ) );
672 fieldsCtrlRow.push_back( wxVariant( aFieldName ) );
673
674 m_fieldsCtrl->AppendItem( fieldsCtrlRow );
675
676 wxGridTableMessage msg( m_dataModel, wxGRIDTABLE_NOTIFY_COLS_APPENDED, 1 );
677 m_grid->ProcessTableMessage( msg );
678}
679
680
682{
683 // Add mandatory fields first
684 for( int i = 0; i < MANDATORY_FIELDS; ++i )
685 {
686 bool show = false;
687 bool groupBy = false;
688
689 switch( i )
690 {
691 case REFERENCE_FIELD:
692 case VALUE_FIELD:
693 case FOOTPRINT_FIELD:
694 show = true;
695 groupBy = true;
696 break;
697 case DATASHEET_FIELD:
698 show = true;
699 groupBy = false;
700 break;
701 }
702
704 groupBy );
705 }
706
707 // Generated fields present only in the fields table
710
711 // User fields next
712 std::set<wxString> userFieldNames;
713
714 for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
715 {
716 SCH_SYMBOL* symbol = m_symbolsList[ i ].GetSymbol();
717
718 for( int j = MANDATORY_FIELDS; j < symbol->GetFieldCount(); ++j )
719 {
720 if( !symbol->GetFields()[j].IsPrivate() )
721 userFieldNames.insert( symbol->GetFields()[j].GetName() );
722 }
723 }
724
725 for( const wxString& fieldName : userFieldNames )
726 AddField( fieldName, GetTextVars( fieldName ), true, false );
727
728 // Add any templateFieldNames which aren't already present in the userFieldNames
729 for( const TEMPLATE_FIELDNAME& templateFieldname :
731 {
732 if( userFieldNames.count( templateFieldname.m_Name ) == 0 )
733 {
734 AddField( templateFieldname.m_Name, GetTextVars( templateFieldname.m_Name ), false,
735 false );
736 }
737 }
738}
739
740
741void DIALOG_SYMBOL_FIELDS_TABLE::OnAddField( wxCommandEvent& event )
742{
743 wxTextEntryDialog dlg( this, _( "New field name:" ), _( "Add Field" ) );
744
745 if( dlg.ShowModal() != wxID_OK )
746 return;
747
748 wxString fieldName = dlg.GetValue();
749
750 if( fieldName.IsEmpty() )
751 {
752 DisplayError( this, _( "Field must have a name." ) );
753 return;
754 }
755
756 for( int i = 0; i < m_dataModel->GetNumberCols(); ++i )
757 {
758 if( fieldName == m_dataModel->GetColFieldName( i ) )
759 {
760 DisplayError( this, wxString::Format( _( "Field name '%s' already in use." ),
761 fieldName ) );
762 return;
763 }
764 }
765
766 AddField( fieldName, GetTextVars( fieldName ), true, false, true );
767
768 SetupColumnProperties( m_dataModel->GetColsCount() - 1 );
769
771 OnModify();
772}
773
774
775void DIALOG_SYMBOL_FIELDS_TABLE::OnRemoveField( wxCommandEvent& event )
776{
777 int col = -1;
778 int row = m_fieldsCtrl->GetSelectedRow();
779
780 // Should never occur: "Remove Field..." button should be disabled if invalid selection
781 // via OnFieldsCtrlSelectionChanged()
782 wxCHECK_RET( row != -1, wxS( "Some user defined field must be selected first" ) );
783 wxCHECK_RET( row >= MANDATORY_FIELDS, wxS( "Mandatory fields cannot be removed" ) );
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 if( row < MANDATORY_FIELDS )
809 {
810 m_removeFieldButton->Enable( false );
811 m_renameFieldButton->Enable( false );
812 }
813
814 wxGridTableMessage msg( m_dataModel, wxGRIDTABLE_NOTIFY_COLS_DELETED, col, 1 );
815
816 m_grid->ProcessTableMessage( msg );
817
819 OnModify();
820}
821
822
823void DIALOG_SYMBOL_FIELDS_TABLE::OnRenameField( wxCommandEvent& event )
824{
825 int row = m_fieldsCtrl->GetSelectedRow();
826 wxString fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
827
828 // Should never occur: "Rename Field..." button should be disabled if invalid selection
829 // via OnFieldsCtrlSelectionChanged()
830 wxCHECK_RET( row != -1, wxS( "Some user defined field must be selected first" ) );
831 wxCHECK_RET( row >= MANDATORY_FIELDS, wxS( "Mandatory fields cannot be renamed" ) );
832 wxCHECK_RET( !fieldName.IsEmpty(), wxS( "Field must have a name" ) );
833
834 int col = m_dataModel->GetFieldNameCol( fieldName );
835 wxCHECK_RET( col != -1, wxS( "Existing field name missing from data model" ) );
836
837 wxTextEntryDialog dlg( this, _( "New field name:" ), _( "Rename Field" ) );
838
839 if( dlg.ShowModal() != wxID_OK )
840 return;
841
842 wxString newFieldName = dlg.GetValue();
843
844 // No change, no-op
845 if( newFieldName == fieldName )
846 return;
847
848 // New field name already exists
849 if( m_dataModel->GetFieldNameCol( newFieldName ) != -1 )
850 {
851 wxString confirm_msg = wxString::Format( _( "Field name %s already exists." ),
852 newFieldName );
853 DisplayError( this, confirm_msg );
854 return;
855 }
856
857 m_dataModel->RenameColumn( col, newFieldName );
858 m_fieldsCtrl->SetTextValue( newFieldName, row, DISPLAY_NAME_COLUMN );
859 m_fieldsCtrl->SetTextValue( newFieldName, row, FIELD_NAME_COLUMN );
860 m_fieldsCtrl->SetTextValue( newFieldName, row, LABEL_COLUMN );
861
863 OnModify();
864}
865
866
867void DIALOG_SYMBOL_FIELDS_TABLE::OnFilterText( wxCommandEvent& aEvent )
868{
869 m_dataModel->SetFilter( m_filter->GetValue() );
871 m_grid->ForceRefresh();
872
874}
875
876
878{
879 wxPoint pos = aEvent.GetPosition();
880 wxRect ctrlRect = m_filter->GetScreenRect();
881 int buttonWidth = ctrlRect.GetHeight(); // Presume buttons are square
882
883 // TODO: restore cursor when mouse leaves the filter field (or is it a MSW bug?)
884 if( m_filter->IsSearchButtonVisible() && pos.x < buttonWidth )
885 SetCursor( wxCURSOR_ARROW );
886 else if( m_filter->IsCancelButtonVisible() && pos.x > ctrlRect.GetWidth() - buttonWidth )
887 SetCursor( wxCURSOR_ARROW );
888 else
889 SetCursor( wxCURSOR_IBEAM );
890}
891
892
894{
895 int row = m_fieldsCtrl->GetSelectedRow();
896
897 if( row >= MANDATORY_FIELDS )
898 {
901 }
902 else
903 {
904 m_removeFieldButton->Enable( false );
905 m_renameFieldButton->Enable( false );
906 }
907}
908
909
911{
912 wxDataViewItem item = event.GetItem();
913 int row = m_fieldsCtrl->ItemToRow( item );
914 int col = event.GetColumn();
915
916 switch ( col )
917 {
919 {
920 wxString name = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
921 bool value = m_fieldsCtrl->GetToggleValue( row, col );
922 int dataCol = m_dataModel->GetFieldNameCol( name );
923
924 m_dataModel->SetShowColumn( dataCol, value );
925
926 if( dataCol != -1 )
927 {
928 if( value )
929 m_grid->ShowCol( dataCol );
930 else
931 m_grid->HideCol( dataCol );
932 }
933
934 break;
935 }
936
937 case GROUP_BY_COLUMN:
938 {
939 wxString name = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
940 bool value = m_fieldsCtrl->GetToggleValue( row, col );
941 int dataCol = m_dataModel->GetFieldNameCol( name );
942
943 if( m_dataModel->ColIsQuantity( dataCol ) && value )
944 {
945 DisplayError( this, _( "The Quantity column cannot be grouped by." ) );
946
947 value = false;
948 m_fieldsCtrl->SetToggleValue( value, row, col );
949 }
950
951 if( m_dataModel->ColIsItemNumber( dataCol ) && value )
952 {
953 DisplayError( this, _( "The Item Number column cannot be grouped by." ) );
954
955 value = false;
956 m_fieldsCtrl->SetToggleValue( value, row, col );
957 }
958
959 wxString fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
960
961 m_dataModel->SetGroupColumn( m_dataModel->GetFieldNameCol( fieldName ), value );
963 m_grid->ForceRefresh();
964 break;
965 }
966
967 default:
968 break;
969 }
970
972}
973
974
976{
979 m_grid->ForceRefresh();
980
982}
983
984
986{
989 m_grid->ForceRefresh();
990
992}
993
994
996{
999 m_grid->ForceRefresh();
1000
1002}
1003
1004
1005void DIALOG_SYMBOL_FIELDS_TABLE::OnColSort( wxGridEvent& aEvent )
1006{
1007 int sortCol = aEvent.GetCol();
1008 std::string key( m_dataModel->GetColFieldName( sortCol ).ToUTF8() );
1009 bool ascending;
1010
1011 // Don't sort by item number, it is generated by the sort
1012 if( m_dataModel->ColIsItemNumber( sortCol ) )
1013 {
1014 aEvent.Veto();
1015 return;
1016 }
1017
1018 // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the event, and
1019 // if we ask it will give us pre-event info.
1020 if( m_grid->IsSortingBy( sortCol ) )
1021 {
1022 // same column; invert ascending
1023 ascending = !m_grid->IsSortOrderAscending();
1024 }
1025 else
1026 {
1027 // different column; start with ascending
1028 ascending = true;
1029 }
1030
1031 m_dataModel->SetSorting( sortCol, ascending );
1033 m_grid->ForceRefresh();
1034
1036}
1037
1038
1039void DIALOG_SYMBOL_FIELDS_TABLE::OnColMove( wxGridEvent& aEvent )
1040{
1041 int origPos = aEvent.GetCol();
1042
1043 // Save column widths since the setup function uses the saved config values
1045
1046 for( int i = 0; i < m_grid->GetNumberCols(); i++ )
1047 {
1048 if( m_grid->IsColShown( i ) )
1049 {
1050 std::string fieldName( m_dataModel->GetColFieldName( i ).ToUTF8() );
1051 cfg->m_FieldEditorPanel.field_widths[fieldName] = m_grid->GetColSize( i );
1052 }
1053 }
1054
1055 CallAfter(
1056 [origPos, this]()
1057 {
1058 int newPos = m_grid->GetColPos( origPos );
1059
1060 m_dataModel->MoveColumn( origPos, newPos );
1061
1062 // "Unmove" the column since we've moved the column internally
1063 m_grid->ResetColPos();
1064
1065 // We need to reset all the column attr's to the correct column order
1067
1068 m_grid->ForceRefresh();
1069 } );
1070
1072}
1073
1074
1076{
1077 wxDataViewItem item = aEvent.GetItem();
1078 int row = m_fieldsCtrl->ItemToRow( item );
1079 wxString label = m_fieldsCtrl->GetTextValue( row, LABEL_COLUMN );
1080 wxString fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
1081 int col = m_dataModel->GetFieldNameCol( fieldName );
1082
1083 if( col != -1 )
1084 m_dataModel->SetColLabelValue( col, label );
1085
1087
1088 aEvent.Skip();
1089
1090 m_grid->ForceRefresh();
1091}
1092
1093
1095{
1096 m_grid->ForceRefresh();
1097 OnModify();
1098}
1099
1100
1101void DIALOG_SYMBOL_FIELDS_TABLE::OnTableColSize( wxGridSizeEvent& aEvent )
1102{
1103 int col = aEvent.GetRowOrCol();
1104 std::string key( m_dataModel->GetColFieldName( col ).ToUTF8() );
1105
1106 aEvent.Skip();
1107
1108 m_grid->ForceRefresh();
1109}
1110
1111
1113{
1115 m_grid->ForceRefresh();
1116}
1117
1118
1120{
1121 UpdateScope();
1122}
1123
1124
1126{
1128
1129 if( m_radioProject->GetValue() )
1130 m_dataModel->SetScope( FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE::SCOPE_ALL );
1131 else if( m_radioCurrentSheet->GetValue() )
1132 m_dataModel->SetScope( FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE::SCOPE_SHEET );
1133 else if( m_radioRecursive->GetValue() )
1134 m_dataModel->SetScope( FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE::SCOPE_SHEET_RECURSIVE );
1135
1137}
1138
1139
1141{
1142 if( m_dataModel->ColIsReference( event.GetCol() ) )
1143 {
1144 m_grid->ClearSelection();
1145
1146 m_dataModel->ExpandCollapseRow( event.GetRow() );
1147 m_grid->SetGridCursor( event.GetRow(), event.GetCol() );
1148 }
1149 else
1150 {
1151 event.Skip();
1152 }
1153}
1154
1155
1156void DIALOG_SYMBOL_FIELDS_TABLE::OnTableRangeSelected( wxGridRangeSelectEvent& aEvent )
1157{
1158 // Cross-probing should only work in Edit page
1159 if( m_nbPages->GetSelection() != 0 )
1160 return;
1161
1162 // Multi-select can grab the rows that are expanded child refs, and also the row
1163 // containing the list of all child refs. Make sure we add refs/symbols uniquely
1164 std::set<SCH_REFERENCE> refs;
1165 std::set<SCH_ITEM*> symbols;
1166
1167 // This handler handles selecting and deselecting
1168 if( aEvent.Selecting() )
1169 {
1170 for( int i = aEvent.GetTopRow(); i <= aEvent.GetBottomRow(); i++ )
1171 {
1172 for( const SCH_REFERENCE& ref : m_dataModel->GetRowReferences( i ) )
1173 refs.insert( ref );
1174 }
1175
1176 for( const SCH_REFERENCE& ref : refs )
1177 symbols.insert( ref.GetSymbol() );
1178 }
1179
1180 if( m_radioHighlight->GetValue() )
1181 {
1183
1184 if( refs.size() > 0 )
1185 {
1186 // Use of full path based on UUID allows select of not yet annotated or duplicated
1187 // symbols
1188 wxString symbol_path = refs.begin()->GetFullPath();
1189
1190 // Focus only handles one item at this time
1191 editor->FindSymbolAndItem( &symbol_path, nullptr, true, HIGHLIGHT_SYMBOL,
1192 wxEmptyString );
1193 }
1194 else
1195 {
1196 m_parent->FocusOnItem( nullptr );
1197 }
1198 }
1199 else if( m_radioSelect->GetValue() )
1200 {
1202
1203 std::vector<SCH_ITEM*> items( symbols.begin(), symbols.end() );
1204
1205 if( refs.size() > 0 )
1206 selTool->SyncSelection( refs.begin()->GetSheetPath(), nullptr, items );
1207 else
1208 selTool->ClearSelection();
1209 }
1210}
1211
1212
1214{
1215 // TODO: Option to select footprint if FOOTPRINT column selected
1216
1217 event.Skip();
1218}
1219
1220
1222{
1226#ifdef __WXMAC__
1227 // TODO: something in wxWidgets 3.1.x pads checkbox columns with extra space. (It used to
1228 // also be that the width of the column would get set too wide (to 30), but that's patched in
1229 // our local wxWidgets fork.)
1230 width -= 50;
1231#endif
1232
1233 m_fieldNameColWidth = width / 2;
1235
1236 // GTK loses its head and messes these up when resizing the splitter bar:
1237 m_fieldsCtrl->GetColumn( SHOW_FIELD_COLUMN )->SetWidth( m_showColWidth );
1238 m_fieldsCtrl->GetColumn( GROUP_BY_COLUMN )->SetWidth( m_groupByColWidth );
1239
1240 m_fieldsCtrl->GetColumn( FIELD_NAME_COLUMN )->SetHidden( true );
1241 m_fieldsCtrl->GetColumn( DISPLAY_NAME_COLUMN )->SetWidth( m_fieldNameColWidth );
1242 m_fieldsCtrl->GetColumn( LABEL_COLUMN )->SetWidth( m_labelColWidth );
1243
1244 m_fieldsCtrl->Refresh(); // To refresh checkboxes on Windows.
1245
1246 event.Skip();
1247}
1248
1249
1251{
1253 {
1255 ClearModify();
1256 }
1257}
1258
1259
1260void DIALOG_SYMBOL_FIELDS_TABLE::OnPageChanged( wxNotebookEvent& event )
1261{
1263}
1264
1265
1267{
1270}
1271
1272
1274{
1277}
1278
1279
1281{
1282 BOM_FMT_PRESET current;
1283
1284 current.name = m_cbBomFmtPresets->GetStringSelection();
1285 current.fieldDelimiter = m_textFieldDelimiter->GetValue();
1286 current.stringDelimiter = m_textStringDelimiter->GetValue();
1287 current.refDelimiter = m_textRefDelimiter->GetValue();
1288 current.refRangeDelimiter = m_textRefRangeDelimiter->GetValue();
1289 current.keepTabs = m_checkKeepTabs->GetValue();
1290 current.keepLineBreaks = m_checkKeepLineBreaks->GetValue();
1291
1292 return current;
1293}
1294
1295
1297{
1298 m_nbPages->SetSelection( 0 );
1299}
1300
1301
1303{
1304 m_nbPages->SetSelection( 1 );
1305}
1306
1307
1309{
1310 // Build the absolute path of current output directory to preselect it in the file browser.
1311 wxString path = ExpandEnvVarSubstitutions( m_outputFileName->GetValue(), &Prj() );
1312 path = Prj().AbsolutePath( path );
1313
1314
1315 // Calculate the export filename
1316 wxFileName fn( Prj().AbsolutePath( m_parent->Schematic().GetFileName() ) );
1317 fn.SetExt( FILEEXT::CsvFileExtension );
1318
1319 wxFileDialog saveDlg( this, _( "Bill of Materials Output File" ), path, fn.GetFullName(),
1320 FILEEXT::CsvFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1321
1322 if( saveDlg.ShowModal() == wxID_CANCEL )
1323 return;
1324
1325
1326 wxFileName file = wxFileName( saveDlg.GetPath() );
1327 wxString defaultPath = fn.GetPathWithSep();
1328 wxString msg;
1329 msg.Printf( _( "Do you want to use a path relative to\n'%s'?" ), defaultPath );
1330
1331 wxMessageDialog dialog( this, msg, _( "BOM Output File" ),
1332 wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
1333
1334 if( dialog.ShowModal() == wxID_YES )
1335 {
1336 if( !file.MakeRelativeTo( defaultPath ) )
1337 {
1338 wxMessageBox( _( "Cannot make path relative (target volume different from schematic "
1339 "file volume)!" ),
1340 _( "BOM Output File" ), wxOK | wxICON_ERROR );
1341 }
1342 }
1343
1344 m_outputFileName->SetValue( file.GetFullPath() );
1345}
1346
1347
1348void DIALOG_SYMBOL_FIELDS_TABLE::OnExport( wxCommandEvent& aEvent )
1349{
1350 if( m_dataModel->IsEdited() )
1351 {
1352 if( OKOrCancelDialog( nullptr, _( "Unsaved data" ),
1353 _( "Changes have not yet been saved. Export unsaved data?" ), "",
1354 _( "OK" ), _( "Cancel" ) )
1355 == wxID_CANCEL )
1356 {
1357 return;
1358 }
1359 }
1360
1361 // Create output directory if it does not exist (also transform it in absolute form).
1362 // Bail if it fails.
1363
1364 std::function<bool( wxString* )> textResolver =
1365 [&]( wxString* token ) -> bool
1366 {
1367 SCHEMATIC& schematic = m_parent->Schematic();
1368
1369 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
1370 return schematic.ResolveTextVar( &schematic.CurrentSheet(), token, 0 );
1371 };
1372
1373 wxString path = m_outputFileName->GetValue();
1374
1375 if( path.IsEmpty() )
1376 {
1377 DisplayError( this, _( "No output file specified in Export tab." ) );
1378 return;
1379 }
1380
1381 path = ExpandTextVars( path, &textResolver );
1382 path = ExpandEnvVarSubstitutions( path, nullptr );
1383
1384 wxFileName outputFile = wxFileName::FileName( path );
1385 wxString msg;
1386
1387 if( !EnsureFileDirectoryExists( &outputFile,
1388 Prj().AbsolutePath( m_parent->Schematic().GetFileName() ),
1390 {
1391 msg.Printf( _( "Could not open/create path '%s'." ), outputFile.GetPath() );
1392 DisplayError( this, msg );
1393 return;
1394 }
1395
1396 wxFFile out( outputFile.GetFullPath(), "wb" );
1397
1398 if( !out.IsOpened() )
1399 {
1400 msg.Printf( _( "Could not create BOM output '%s'." ), outputFile.GetFullPath() );
1401 DisplayError( this, msg );
1402 return;
1403 }
1404
1406
1407 if( !out.Write( m_textOutput->GetValue() ) )
1408 {
1409 msg.Printf( _( "Could not write BOM output '%s'." ), outputFile.GetFullPath() );
1410 DisplayError( this, msg );
1411 return;
1412 }
1413
1414 // close the file before we tell the user it's done with the info modal :workflow meme:
1415 out.Close();
1416 msg.Printf( _( "Wrote BOM output to '%s'" ), outputFile.GetFullPath() );
1417 DisplayInfoMessage( this, msg );
1418}
1419
1420
1421void DIALOG_SYMBOL_FIELDS_TABLE::OnCancel( wxCommandEvent& aEvent )
1422{
1423 if( m_job )
1424 EndModal( wxID_CANCEL );
1425 else
1426 Close();
1427}
1428
1429
1430void DIALOG_SYMBOL_FIELDS_TABLE::OnOk( wxCommandEvent& aEvent )
1431{
1433
1434 if( m_job )
1435 {
1437
1440 else
1441 m_job->m_bomFmtPresetName = wxEmptyString;
1442
1443 if( m_currentBomPreset )
1445 else
1446 m_job->m_bomPresetName = wxEmptyString;
1447
1449 m_job->m_fieldDelimiter = fmtSettings.fieldDelimiter;
1451 m_job->m_refDelimiter = fmtSettings.refDelimiter;
1453 m_job->m_keepTabs = fmtSettings.keepTabs;
1454 m_job->m_keepLineBreaks = fmtSettings.keepLineBreaks;
1455
1456 BOM_PRESET presetFields = m_dataModel->GetBomSettings();
1457 m_job->m_sortAsc = presetFields.sortAsc;
1458 m_job->m_excludeDNP = presetFields.excludeDNP;
1460 m_job->m_filterString = presetFields.filterString;
1461 m_job->m_sortField = presetFields.sortField;
1462
1463 m_job->m_fieldsOrdered.clear();
1464 m_job->m_fieldsLabels.clear();
1465 m_job->m_fieldsGroupBy.clear();
1466
1467 for( const BOM_FIELD& modelField : m_dataModel->GetFieldsOrdered() )
1468 {
1469 if( modelField.show )
1470 m_job->m_fieldsOrdered.emplace_back( modelField.name );
1471 else
1472 m_job->m_fieldsOrdered.emplace_back( wxT( "__" ) + modelField.name );
1473
1474 m_job->m_fieldsLabels.emplace_back( modelField.label );
1475
1476 if( modelField.groupBy )
1477 m_job->m_fieldsGroupBy.emplace_back( modelField.name );
1478 }
1479
1480 EndModal( wxID_OK );
1481 }
1482 else
1483 {
1484 Close();
1485 }
1486}
1487
1488
1489void DIALOG_SYMBOL_FIELDS_TABLE::OnClose( wxCloseEvent& aEvent )
1490{
1491 if( m_job )
1492 {
1493 aEvent.Skip();
1494 return;
1495 }
1496
1497 // This is a cancel, so commit quietly as we're going to throw the results away anyway.
1499
1500 if( m_dataModel->IsEdited() )
1501 {
1502 if( !HandleUnsavedChanges( this, _( "Save changes?" ),
1503 [&]() -> bool
1504 {
1505 return TransferDataFromWindow();
1506 } ) )
1507 {
1508 aEvent.Veto();
1509 return;
1510 }
1511 }
1512
1513 // Stop listening to schematic events
1515
1516 // Save all our settings since we're really closing
1519
1521
1522 cfg->m_FieldEditorPanel.width = GetSize().x;
1523 cfg->m_FieldEditorPanel.height = GetSize().y;
1524 cfg->m_FieldEditorPanel.page = m_nbPages->GetSelection();
1525
1526 if( m_radioHighlight->GetValue() )
1528 else if( m_radioSelect->GetValue() )
1530 else if( m_radioOff->GetValue() )
1532
1533 if( m_radioProject->GetValue() )
1534 cfg->m_FieldEditorPanel.scope = SCOPE::SCOPE_ALL;
1535 else if( m_radioCurrentSheet->GetValue() )
1536 cfg->m_FieldEditorPanel.scope = SCOPE::SCOPE_SHEET;
1537 else if( m_radioRecursive->GetValue() )
1538 cfg->m_FieldEditorPanel.scope = SCOPE::SCOPE_SHEET_RECURSIVE;
1539
1540 for( int i = 0; i < m_grid->GetNumberCols(); i++ )
1541 {
1542 if( m_grid->IsColShown( i ) )
1543 {
1544 std::string fieldName( m_dataModel->GetColFieldName( i ).ToUTF8() );
1545 cfg->m_FieldEditorPanel.field_widths[fieldName] = m_grid->GetColSize( i );
1546 }
1547 }
1548
1549 m_parent->FocusOnItem( nullptr );
1550
1551 wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, wxID_ANY );
1552
1553 if( wxWindow* parent = GetParent() )
1554 wxQueueEvent( parent, evt );
1555}
1556
1557
1559{
1560 std::vector<BOM_PRESET> ret;
1561
1562 for( const std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
1563 {
1564 if( !pair.second.readOnly )
1565 ret.emplace_back( pair.second );
1566 }
1567
1568 return ret;
1569}
1570
1571
1572void DIALOG_SYMBOL_FIELDS_TABLE::SetUserBomPresets( std::vector<BOM_PRESET>& aPresetList )
1573{
1574 // Reset to defaults
1576
1577 for( const BOM_PRESET& preset : aPresetList )
1578 {
1579 if( m_bomPresets.count( preset.name ) )
1580 continue;
1581
1582 m_bomPresets[preset.name] = preset;
1583
1584 m_bomPresetMRU.Add( preset.name );
1585 }
1586
1588}
1589
1590
1591void DIALOG_SYMBOL_FIELDS_TABLE::ApplyBomPreset( const wxString& aPresetName )
1592{
1593 updateBomPresetSelection( aPresetName );
1594
1595 wxCommandEvent dummy;
1597}
1598
1599
1601{
1602 if( m_bomPresets.count( aPreset.name ) )
1604 else
1605 m_currentBomPreset = nullptr;
1606
1609 else
1610 m_lastSelectedBomPreset = nullptr;
1611
1612 updateBomPresetSelection( aPreset.name );
1613 doApplyBomPreset( aPreset );
1614}
1615
1616
1618{
1619 m_bomPresets.clear();
1620 m_bomPresetMRU.clear();
1621
1622 // Load the read-only defaults
1623 for( const BOM_PRESET& preset : BOM_PRESET::BuiltInPresets() )
1624 {
1625 m_bomPresets[preset.name] = preset;
1626 m_bomPresets[preset.name].readOnly = true;
1627
1628 m_bomPresetMRU.Add( preset.name );
1629 }
1630}
1631
1632
1634{
1635 m_cbBomPresets->Clear();
1636
1637 // Build the layers preset list.
1638 // By default, the presetAllLayers will be selected
1639 int idx = 0;
1640 int default_idx = 0;
1641
1642 for( std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
1643 {
1644 m_cbBomPresets->Append( wxGetTranslation( pair.first ),
1645 static_cast<void*>( &pair.second ) );
1646
1647 if( pair.first == BOM_PRESET::DefaultEditing().name )
1648 default_idx = idx;
1649
1650 idx++;
1651 }
1652
1653 m_cbBomPresets->Append( wxT( "---" ) );
1654 m_cbBomPresets->Append( _( "Save preset..." ) );
1655 m_cbBomPresets->Append( _( "Delete preset..." ) );
1656
1657 // At least the built-in presets should always be present
1658 wxASSERT( !m_bomPresets.empty() );
1659
1660 // Default preset: all Boms
1661 m_cbBomPresets->SetSelection( default_idx );
1662 m_currentBomPreset = static_cast<BOM_PRESET*>( m_cbBomPresets->GetClientData( default_idx ) );
1663}
1664
1665
1667{
1669
1670 auto it = std::find_if( m_bomPresets.begin(), m_bomPresets.end(),
1671 [&]( const std::pair<const wxString, BOM_PRESET>& aPair )
1672 {
1673 const BOM_PRESET& preset = aPair.second;
1674
1675 // Check the simple settings first
1676 if( !( preset.sortAsc == current.sortAsc
1677 && preset.filterString == current.filterString
1678 && preset.groupSymbols == current.groupSymbols
1679 && preset.excludeDNP == current.excludeDNP
1680 && preset.includeExcludedFromBOM
1681 == current.includeExcludedFromBOM ) )
1682 {
1683 return false;
1684 }
1685
1686 // We should compare preset.name and current.name.
1687 // unfortunately current.name is empty because
1688 // m_dataModel->GetBomSettings() does not store the .name member
1689 // So use sortField member as a (not very efficient) auxiliary
1690 // filter.
1691 // sortField can be translated in m_bomPresets list,
1692 // so current.sortField needs to be translated
1693 // Probably this not efficient and error prone test should be
1694 // removed (JPC).
1695 if( preset.sortField != wxGetTranslation( current.sortField ) )
1696 return false;
1697
1698 // Only compare shown or grouped fields
1699 std::vector<BOM_FIELD> A, B;
1700
1701 for( const BOM_FIELD& field : preset.fieldsOrdered )
1702 {
1703 if( field.show || field.groupBy )
1704 A.emplace_back( field );
1705 }
1706
1707 for( const BOM_FIELD& field : current.fieldsOrdered )
1708 {
1709 if( field.show || field.groupBy )
1710 B.emplace_back( field );
1711 }
1712
1713 return A == B;
1714 } );
1715
1716 if( it != m_bomPresets.end() )
1717 {
1718 // Select the right m_cbBomPresets item.
1719 // but these items are translated if they are predefined items.
1720 bool do_translate = it->second.readOnly;
1721 wxString text = do_translate ? wxGetTranslation( it->first ) : it->first;
1722 m_cbBomPresets->SetStringSelection( text );
1723 }
1724 else
1725 {
1726 m_cbBomPresets->SetSelection( m_cbBomPresets->GetCount() - 3 ); // separator
1727 }
1728
1729 m_currentBomPreset = static_cast<BOM_PRESET*>(
1730 m_cbBomPresets->GetClientData( m_cbBomPresets->GetSelection() ) );
1731}
1732
1733
1735{
1736 // look at m_userBomPresets to know if aName is a read only preset, or a user preset.
1737 // Read only presets have translated names in UI, so we have to use
1738 // a translated name in UI selection.
1739 // But for a user preset name we should search for aName (not translated)
1740 wxString ui_label = aName;
1741
1742 for( std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
1743 {
1744 if( pair.first != aName )
1745 continue;
1746
1747 if( pair.second.readOnly == true )
1748 ui_label = wxGetTranslation( aName );
1749
1750 break;
1751 }
1752
1753 int idx = m_cbBomPresets->FindString( ui_label );
1754
1755 if( idx >= 0 && m_cbBomPresets->GetSelection() != idx )
1756 {
1757 m_cbBomPresets->SetSelection( idx );
1758 m_currentBomPreset = static_cast<BOM_PRESET*>( m_cbBomPresets->GetClientData( idx ) );
1759 }
1760 else if( idx < 0 )
1761 {
1762 m_cbBomPresets->SetSelection( m_cbBomPresets->GetCount() - 3 ); // separator
1763 }
1764}
1765
1766
1768{
1769 int count = m_cbBomPresets->GetCount();
1770 int index = m_cbBomPresets->GetSelection();
1771
1772 auto resetSelection =
1773 [&]()
1774 {
1775 if( m_currentBomPreset )
1776 m_cbBomPresets->SetStringSelection( m_currentBomPreset->name );
1777 else
1778 m_cbBomPresets->SetSelection( m_cbBomPresets->GetCount() - 3 );
1779 };
1780
1781 if( index == count - 3 )
1782 {
1783 // Separator: reject the selection
1784 resetSelection();
1785 return;
1786 }
1787 else if( index == count - 2 )
1788 {
1789 // Save current state to new preset
1790 wxString name;
1791
1794
1795 wxTextEntryDialog dlg( this, _( "BOM preset name:" ), _( "Save BOM Preset" ), name );
1796
1797 if( dlg.ShowModal() != wxID_OK )
1798 {
1799 resetSelection();
1800 return;
1801 }
1802
1803 name = dlg.GetValue();
1804 bool exists = m_bomPresets.count( name );
1805
1806 if( !exists )
1807 {
1809 m_bomPresets[name].readOnly = false;
1810 m_bomPresets[name].name = name;
1811 }
1812
1813 BOM_PRESET* preset = &m_bomPresets[name];
1814
1815 if( !exists )
1816 {
1817 index = m_cbBomPresets->Insert( name, index - 1, static_cast<void*>( preset ) );
1818 }
1819 else if( preset->readOnly )
1820 {
1821 wxMessageBox( _( "Default presets cannot be modified.\nPlease use a different name." ),
1822 _( "Error" ), wxOK | wxICON_ERROR, this );
1823 resetSelection();
1824 return;
1825 }
1826 else
1827 {
1828 // Ask the user if they want to overwrite the existing preset
1829 if( !IsOK( this, _( "Overwrite existing preset?" ) ) )
1830 {
1831 resetSelection();
1832 return;
1833 }
1834
1835 *preset = m_dataModel->GetBomSettings();
1836 preset->name = name;
1837
1838 index = m_cbBomPresets->FindString( name );
1839 m_bomPresetMRU.Remove( name );
1840 }
1841
1842 m_currentBomPreset = preset;
1843 m_cbBomPresets->SetSelection( index );
1844 m_bomPresetMRU.Insert( name, 0 );
1845
1846 return;
1847 }
1848 else if( index == count - 1 )
1849 {
1850 // Delete a preset
1851 wxArrayString headers;
1852 std::vector<wxArrayString> items;
1853
1854 headers.Add( _( "Presets" ) );
1855
1856 for( std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
1857 {
1858 if( !pair.second.readOnly )
1859 {
1860 wxArrayString item;
1861 item.Add( pair.first );
1862 items.emplace_back( item );
1863 }
1864 }
1865
1866 EDA_LIST_DIALOG dlg( this, _( "Delete Preset" ), headers, items );
1867 dlg.SetListLabel( _( "Select preset:" ) );
1868
1869 if( dlg.ShowModal() == wxID_OK )
1870 {
1871 wxString presetName = dlg.GetTextSelection();
1872 int idx = m_cbBomPresets->FindString( presetName );
1873
1874 if( idx != wxNOT_FOUND )
1875 {
1876 m_bomPresets.erase( presetName );
1877
1878 m_cbBomPresets->Delete( idx );
1879 m_currentBomPreset = nullptr;
1880
1881 m_bomPresetMRU.Remove( presetName );
1882 }
1883 }
1884
1885 resetSelection();
1886 return;
1887 }
1888
1889 BOM_PRESET* preset = static_cast<BOM_PRESET*>( m_cbBomPresets->GetClientData( index ) );
1890 m_currentBomPreset = preset;
1891
1892 m_lastSelectedBomPreset = ( !preset || preset->readOnly ) ? nullptr : preset;
1893
1894 if( preset )
1895 {
1896 doApplyBomPreset( *preset );
1898 m_currentBomPreset = preset;
1899
1900 if( !m_currentBomPreset->name.IsEmpty() )
1901 {
1902 m_bomPresetMRU.Remove( preset->name );
1903 m_bomPresetMRU.Insert( preset->name, 0 );
1904 }
1905 }
1906}
1907
1908
1910{
1911 // Disable rebuilds while we're applying the preset otherwise we'll be
1912 // rebuilding the model constantly while firing off wx events
1914
1915 // Basically, we apply the BOM preset to the data model and then
1916 // update our UI to reflect resulting the data model state, not the preset.
1917 m_dataModel->ApplyBomPreset( aPreset );
1918
1919 // BOM Presets can add, but not remove, columns, so make sure the field control
1920 // grid has all of them before starting
1921 for( int i = 0; i < m_dataModel->GetColsCount(); i++ )
1922 {
1923 const wxString& fieldName( m_dataModel->GetColFieldName( i ) );
1924 bool found = false;
1925
1926 for( int j = 0; j < m_fieldsCtrl->GetItemCount(); j++ )
1927 {
1928 if( m_fieldsCtrl->GetTextValue( j, FIELD_NAME_COLUMN ) == fieldName )
1929 {
1930 found = true;
1931 break;
1932 }
1933 }
1934
1935 // Properties like label, etc. will be added in the next loop
1936 if( !found )
1937 AddField( fieldName, GetTextVars( fieldName ), false, false );
1938 }
1939
1940 // Sync all fields
1941 for( int i = 0; i < m_fieldsCtrl->GetItemCount(); i++ )
1942 {
1943 const wxString& fieldName( m_fieldsCtrl->GetTextValue( i, FIELD_NAME_COLUMN ) );
1944 int col = m_dataModel->GetFieldNameCol( fieldName );
1945
1946 if( col == -1 )
1947 {
1948 wxASSERT_MSG( true, "Fields control has a field not found in the data model." );
1949 continue;
1950 }
1951
1953 std::string fieldNameStr( fieldName.ToUTF8() );
1954
1955 // Set column labels
1956 const wxString& label = m_dataModel->GetColLabelValue( col );
1957 m_fieldsCtrl->SetTextValue( label, i, LABEL_COLUMN );
1958 m_grid->SetColLabelValue( col, label );
1959
1960 if( cfg->m_FieldEditorPanel.field_widths.count( fieldNameStr ) )
1961 m_grid->SetColSize( col, cfg->m_FieldEditorPanel.field_widths.at( fieldNameStr ) );
1962
1963 // Set shown columns
1964 bool show = m_dataModel->GetShowColumn( col );
1965 m_fieldsCtrl->SetToggleValue( show, i, SHOW_FIELD_COLUMN );
1966
1967 if( show )
1968 m_grid->ShowCol( col );
1969 else
1970 m_grid->HideCol( col );
1971
1972 // Set grouped columns
1973 bool groupBy = m_dataModel->GetGroupColumn( col );
1974 m_fieldsCtrl->SetToggleValue( groupBy, i, GROUP_BY_COLUMN );
1975 }
1976
1977 m_grid->SetSortingColumn( m_dataModel->GetSortCol(), m_dataModel->GetSortAsc() );
1979 m_filter->ChangeValue( m_dataModel->GetFilter() );
1982
1984
1985 // This will rebuild all rows and columns in the model such that the order
1986 // and labels are right, then we refresh the shown grid data to match
1989 m_grid->ForceRefresh();
1990}
1991
1992
1993std::vector<BOM_FMT_PRESET> DIALOG_SYMBOL_FIELDS_TABLE::GetUserBomFmtPresets() const
1994{
1995 std::vector<BOM_FMT_PRESET> ret;
1996
1997 for( const std::pair<const wxString, BOM_FMT_PRESET>& pair : m_bomFmtPresets )
1998 {
1999 if( !pair.second.readOnly )
2000 ret.emplace_back( pair.second );
2001 }
2002
2003 return ret;
2004}
2005
2006
2007void DIALOG_SYMBOL_FIELDS_TABLE::SetUserBomFmtPresets( std::vector<BOM_FMT_PRESET>& aPresetList )
2008{
2009 // Reset to defaults
2011
2012 for( const BOM_FMT_PRESET& preset : aPresetList )
2013 {
2014 if( m_bomFmtPresets.count( preset.name ) )
2015 continue;
2016
2017 m_bomFmtPresets[preset.name] = preset;
2018
2019 m_bomFmtPresetMRU.Add( preset.name );
2020 }
2021
2023}
2024
2025
2026void DIALOG_SYMBOL_FIELDS_TABLE::ApplyBomFmtPreset( const wxString& aPresetName )
2027{
2028 updateBomFmtPresetSelection( aPresetName );
2029
2030 wxCommandEvent dummy;
2032}
2033
2034
2036{
2037 if( m_bomFmtPresets.count( aPreset.name ) )
2039 else
2040 m_currentBomFmtPreset = nullptr;
2041
2044 : nullptr;
2045
2047 doApplyBomFmtPreset( aPreset );
2048}
2049
2050
2052{
2053 m_bomFmtPresets.clear();
2054 m_bomFmtPresetMRU.clear();
2055
2056 // Load the read-only defaults
2057 for( const BOM_FMT_PRESET& preset : BOM_FMT_PRESET::BuiltInPresets() )
2058 {
2059 m_bomFmtPresets[preset.name] = preset;
2060 m_bomFmtPresets[preset.name].readOnly = true;
2061
2062 m_bomFmtPresetMRU.Add( preset.name );
2063 }
2064}
2065
2066
2068{
2069 m_cbBomFmtPresets->Clear();
2070
2071 // Build the layers preset list.
2072 // By default, the presetAllLayers will be selected
2073 int idx = 0;
2074 int default_idx = 0;
2075
2076 for( std::pair<const wxString, BOM_FMT_PRESET>& pair : m_bomFmtPresets )
2077 {
2078 m_cbBomFmtPresets->Append( wxGetTranslation( pair.first ),
2079 static_cast<void*>( &pair.second ) );
2080
2081 if( pair.first == BOM_FMT_PRESET::CSV().name )
2082 default_idx = idx;
2083
2084 idx++;
2085 }
2086
2087 m_cbBomFmtPresets->Append( wxT( "---" ) );
2088 m_cbBomFmtPresets->Append( _( "Save preset..." ) );
2089 m_cbBomFmtPresets->Append( _( "Delete preset..." ) );
2090
2091 // At least the built-in presets should always be present
2092 wxASSERT( !m_bomFmtPresets.empty() );
2093
2094 // Default preset: all Boms
2095 m_cbBomFmtPresets->SetSelection( default_idx );
2097 static_cast<BOM_FMT_PRESET*>( m_cbBomFmtPresets->GetClientData( default_idx ) );
2098}
2099
2100
2102{
2104
2105 auto it = std::find_if( m_bomFmtPresets.begin(), m_bomFmtPresets.end(),
2106 [&]( const std::pair<const wxString, BOM_FMT_PRESET>& aPair )
2107 {
2108 return ( aPair.second.fieldDelimiter == current.fieldDelimiter
2109 && aPair.second.stringDelimiter == current.stringDelimiter
2110 && aPair.second.refDelimiter == current.refDelimiter
2111 && aPair.second.refRangeDelimiter == current.refRangeDelimiter
2112 && aPair.second.keepTabs == current.keepTabs
2113 && aPair.second.keepLineBreaks == current.keepLineBreaks );
2114 } );
2115
2116 if( it != m_bomFmtPresets.end() )
2117 {
2118 // Select the right m_cbBomFmtPresets item.
2119 // but these items are translated if they are predefined items.
2120 bool do_translate = it->second.readOnly;
2121 wxString text = do_translate ? wxGetTranslation( it->first ) : it->first;
2122
2123 m_cbBomFmtPresets->SetStringSelection( text );
2124 }
2125 else
2126 {
2127 m_cbBomFmtPresets->SetSelection( m_cbBomFmtPresets->GetCount() - 3 ); // separator
2128 }
2129
2130 m_currentBomFmtPreset = static_cast<BOM_FMT_PRESET*>(
2131 m_cbBomFmtPresets->GetClientData( m_cbBomFmtPresets->GetSelection() ) );
2132}
2133
2134
2136{
2137 // look at m_userBomFmtPresets to know if aName is a read only preset, or a user preset.
2138 // Read only presets have translated names in UI, so we have to use
2139 // a translated name in UI selection.
2140 // But for a user preset name we should search for aName (not translated)
2141 wxString ui_label = aName;
2142
2143 for( std::pair<const wxString, BOM_FMT_PRESET>& pair : m_bomFmtPresets )
2144 {
2145 if( pair.first != aName )
2146 continue;
2147
2148 if( pair.second.readOnly == true )
2149 ui_label = wxGetTranslation( aName );
2150
2151 break;
2152 }
2153
2154 int idx = m_cbBomFmtPresets->FindString( ui_label );
2155
2156 if( idx >= 0 && m_cbBomFmtPresets->GetSelection() != idx )
2157 {
2158 m_cbBomFmtPresets->SetSelection( idx );
2160 static_cast<BOM_FMT_PRESET*>( m_cbBomFmtPresets->GetClientData( idx ) );
2161 }
2162 else if( idx < 0 )
2163 {
2164 m_cbBomFmtPresets->SetSelection( m_cbBomFmtPresets->GetCount() - 3 ); // separator
2165 }
2166}
2167
2168
2170{
2171 int count = m_cbBomFmtPresets->GetCount();
2172 int index = m_cbBomFmtPresets->GetSelection();
2173
2174 auto resetSelection =
2175 [&]()
2176 {
2178 m_cbBomFmtPresets->SetStringSelection( m_currentBomFmtPreset->name );
2179 else
2180 m_cbBomFmtPresets->SetSelection( m_cbBomFmtPresets->GetCount() - 3 );
2181 };
2182
2183 if( index == count - 3 )
2184 {
2185 // Separator: reject the selection
2186 resetSelection();
2187 return;
2188 }
2189 else if( index == count - 2 )
2190 {
2191 // Save current state to new preset
2192 wxString name;
2193
2196
2197 wxTextEntryDialog dlg( this, _( "BOM preset name:" ), _( "Save BOM Preset" ), name );
2198
2199 if( dlg.ShowModal() != wxID_OK )
2200 {
2201 resetSelection();
2202 return;
2203 }
2204
2205 name = dlg.GetValue();
2206 bool exists = m_bomFmtPresets.count( name );
2207
2208 if( !exists )
2209 {
2211 m_bomFmtPresets[name].readOnly = false;
2212 m_bomFmtPresets[name].name = name;
2213 }
2214
2216
2217 if( !exists )
2218 {
2219 index = m_cbBomFmtPresets->Insert( name, index - 1, static_cast<void*>( preset ) );
2220 }
2221 else if( preset->readOnly )
2222 {
2223 wxMessageBox( _( "Default presets cannot be modified.\nPlease use a different name." ),
2224 _( "Error" ), wxOK | wxICON_ERROR, this );
2225 resetSelection();
2226 return;
2227 }
2228 else
2229 {
2230 // Ask the user if they want to overwrite the existing preset
2231 if( !IsOK( this, _( "Overwrite existing preset?" ) ) )
2232 {
2233 resetSelection();
2234 return;
2235 }
2236
2237 *preset = GetCurrentBomFmtSettings();
2238 preset->name = name;
2239
2240 index = m_cbBomFmtPresets->FindString( name );
2241 m_bomFmtPresetMRU.Remove( name );
2242 }
2243
2244 m_currentBomFmtPreset = preset;
2245 m_cbBomFmtPresets->SetSelection( index );
2246 m_bomFmtPresetMRU.Insert( name, 0 );
2247
2248 return;
2249 }
2250 else if( index == count - 1 )
2251 {
2252 // Delete a preset
2253 wxArrayString headers;
2254 std::vector<wxArrayString> items;
2255
2256 headers.Add( _( "Presets" ) );
2257
2258 for( std::pair<const wxString, BOM_FMT_PRESET>& pair : m_bomFmtPresets )
2259 {
2260 if( !pair.second.readOnly )
2261 {
2262 wxArrayString item;
2263 item.Add( pair.first );
2264 items.emplace_back( item );
2265 }
2266 }
2267
2268 EDA_LIST_DIALOG dlg( this, _( "Delete Preset" ), headers, items );
2269 dlg.SetListLabel( _( "Select preset:" ) );
2270
2271 if( dlg.ShowModal() == wxID_OK )
2272 {
2273 wxString presetName = dlg.GetTextSelection();
2274 int idx = m_cbBomFmtPresets->FindString( presetName );
2275
2276 if( idx != wxNOT_FOUND )
2277 {
2278 m_bomFmtPresets.erase( presetName );
2279
2280 m_cbBomFmtPresets->Delete( idx );
2281 m_currentBomFmtPreset = nullptr;
2282
2283 m_bomFmtPresetMRU.Remove( presetName );
2284 }
2285 }
2286
2287 resetSelection();
2288 return;
2289 }
2290
2291 auto* preset = static_cast<BOM_FMT_PRESET*>( m_cbBomFmtPresets->GetClientData( index ) );
2292 m_currentBomFmtPreset = preset;
2293
2294 m_lastSelectedBomFmtPreset = ( !preset || preset->readOnly ) ? nullptr : preset;
2295
2296 if( preset )
2297 {
2298 doApplyBomFmtPreset( *preset );
2300 m_currentBomFmtPreset = preset;
2301
2302 if( !m_currentBomFmtPreset->name.IsEmpty() )
2303 {
2304 m_bomFmtPresetMRU.Remove( preset->name );
2305 m_bomFmtPresetMRU.Insert( preset->name, 0 );
2306 }
2307 }
2308}
2309
2310
2312{
2313 m_textFieldDelimiter->ChangeValue( aPreset.fieldDelimiter );
2314 m_textStringDelimiter->ChangeValue( aPreset.stringDelimiter );
2315 m_textRefDelimiter->ChangeValue( aPreset.refDelimiter );
2316 m_textRefRangeDelimiter->ChangeValue( aPreset.refRangeDelimiter );
2317 m_checkKeepTabs->SetValue( aPreset.keepTabs );
2318 m_checkKeepLineBreaks->SetValue( aPreset.keepLineBreaks );
2319
2320
2321 // Refresh the preview if that's the current page
2322 if( m_nbPages->GetSelection() == 1 )
2324}
2325
2326
2328{
2329 bool modified = false;
2330
2331 // Save our BOM presets
2332 std::vector<BOM_PRESET> presets;
2333
2334 for( const std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
2335 {
2336 if( !pair.second.readOnly )
2337 presets.emplace_back( pair.second );
2338 }
2339
2340 if( m_schSettings.m_BomPresets != presets )
2341 {
2342 modified = true;
2343 m_schSettings.m_BomPresets = presets;
2344 }
2345
2347 {
2348 modified = true;
2350 }
2351
2352 // Save our BOM Format presets
2353 std::vector<BOM_FMT_PRESET> fmts;
2354
2355 for( const std::pair<const wxString, BOM_FMT_PRESET>& pair : m_bomFmtPresets )
2356 {
2357 if( !pair.second.readOnly )
2358 fmts.emplace_back( pair.second );
2359 }
2360
2361 if( m_schSettings.m_BomFmtPresets != fmts )
2362 {
2363 modified = true;
2365 }
2366
2368 {
2369 modified = true;
2371 }
2372
2373 if( modified )
2374 m_parent->OnModify();
2375}
2376
2377
2379 std::vector<SCH_ITEM*>& aSchItem )
2380{
2381 SCH_REFERENCE_LIST allRefs;
2382 m_parent->Schematic().Hierarchy().GetSymbols( allRefs );
2383
2384 for( SCH_ITEM* item : aSchItem )
2385 {
2386 if( item->Type() == SCH_SYMBOL_T )
2387 {
2388 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2389
2390 // Don't add power symbols
2391 if( !symbol->IsMissingLibSymbol() && symbol->IsPower() )
2392 continue;
2393
2394 // Add all fields again in case this symbol has a new one
2395 for( SCH_FIELD& field : symbol->GetFields() )
2396 AddField( field.GetCanonicalName(), field.GetName(), true, false, true );
2397
2398 m_dataModel->AddReferences( getSymbolReferences( symbol, allRefs ) );
2399 }
2400 else if( item->Type() == SCH_SHEET_T )
2401 {
2402 std::set<SCH_SYMBOL*> symbols;
2403 SCH_REFERENCE_LIST refs = getSheetSymbolReferences( *static_cast<SCH_SHEET*>( item ) );
2404
2405 for( SCH_REFERENCE& ref : refs )
2406 symbols.insert( ref.GetSymbol() );
2407
2408 for( SCH_SYMBOL* symbol : symbols )
2409 {
2410 // Add all fields again in case this symbol has a new one
2411 for( SCH_FIELD& field : symbol->GetFields() )
2412 AddField( field.GetCanonicalName(), field.GetName(), true, false, true );
2413 }
2414
2415 m_dataModel->AddReferences( refs );
2416 }
2417 }
2418
2422}
2423
2424
2426 std::vector<SCH_ITEM*>& aSchItem )
2427{
2428 for( SCH_ITEM* item : aSchItem )
2429 {
2430 if( item->Type() == SCH_SYMBOL_T )
2431 {
2432 m_dataModel->RemoveSymbol( *static_cast<SCH_SYMBOL*>( item ) );
2433 }
2434 else if( item->Type() == SCH_SHEET_T )
2435 {
2437 getSheetSymbolReferences( *static_cast<SCH_SHEET*>( item ) ) );
2438 }
2439 }
2440
2444}
2445
2446
2448 std::vector<SCH_ITEM*>& aSchItem )
2449{
2450 SCH_REFERENCE_LIST allRefs;
2451 m_parent->Schematic().Hierarchy().GetSymbols( allRefs );
2452
2453 for( SCH_ITEM* item : aSchItem )
2454 {
2455 if( item->Type() == SCH_SYMBOL_T )
2456 {
2457 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2458
2459 // Don't add power symbols
2460 if( !symbol->IsMissingLibSymbol() && symbol->IsPower() )
2461 continue;
2462
2463 // Add all fields again in case this symbol has a new one
2464 for( SCH_FIELD& field : symbol->GetFields() )
2465 AddField( field.GetCanonicalName(), field.GetName(), true, false, true );
2466
2467 m_dataModel->UpdateReferences( getSymbolReferences( symbol, allRefs ) );
2468 }
2469 else if( item->Type() == SCH_SHEET_T )
2470 {
2471 std::set<SCH_SYMBOL*> symbols;
2472 SCH_REFERENCE_LIST refs = getSheetSymbolReferences( *static_cast<SCH_SHEET*>( item ) );
2473
2474 for( SCH_REFERENCE& ref : refs )
2475 symbols.insert( ref.GetSymbol() );
2476
2477 for( SCH_SYMBOL* symbol : symbols )
2478 {
2479 // Add all fields again in case this symbol has a new one
2480 for( SCH_FIELD& field : symbol->GetFields() )
2481 AddField( field.GetCanonicalName(), field.GetName(), true, false, true );
2482 }
2483
2485 }
2486 }
2487
2491}
2492
2493
2495{
2496 m_dataModel->SetPath( aSch.CurrentSheet() );
2497
2498 if( m_dataModel->GetScope() != FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE::SCOPE_ALL )
2499 {
2503 }
2504}
2505
2506
2508{
2509 m_grid->Connect(
2510 wxEVT_GRID_RANGE_SELECTED,
2511 wxGridRangeSelectEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnTableRangeSelected ),
2512 nullptr, this );
2513}
2514
2515
2517{
2518 m_grid->Disconnect(
2519 wxEVT_GRID_RANGE_SELECTED,
2520 wxGridRangeSelectEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnTableRangeSelected ),
2521 nullptr, this );
2522}
2523
2524
2527 SCH_REFERENCE_LIST& aCachedRefs )
2528{
2529 SCH_REFERENCE_LIST symbolRefs;
2530
2531 for( size_t i = 0; i < aCachedRefs.GetCount(); i++ )
2532 {
2533 SCH_REFERENCE& ref = aCachedRefs[i];
2534
2535 if( ref.GetSymbol() == aSymbol )
2536 {
2537 ref.Split(); // Figures out if we are annotated or not
2538 symbolRefs.AddItem( ref );
2539 }
2540 }
2541
2542 return symbolRefs;
2543}
2544
2545
2547{
2548 SCH_SHEET_LIST allSheets = m_parent->Schematic().Hierarchy();
2549 SCH_REFERENCE_LIST sheetRefs;
2550
2551 // We need to operate on all instances of the sheet
2552 for( const SCH_SHEET_INSTANCE& instance : aSheet.GetInstances() )
2553 {
2554 // For every sheet instance we need to get the current schematic sheet
2555 // instance that matches that particular sheet path from the root
2556 for( SCH_SHEET_PATH& basePath : allSheets )
2557 {
2558 if( basePath.Path() == instance.m_Path )
2559 {
2560 SCH_SHEET_PATH sheetPath = basePath;
2561 sheetPath.push_back( &aSheet );
2562
2563 // Create a list of all sheets in this path, starting with the path
2564 // of the sheet that we just deleted, then all of its subsheets
2565 SCH_SHEET_LIST subSheets;
2566 subSheets.push_back( sheetPath );
2567 allSheets.GetSheetsWithinPath( subSheets, sheetPath );
2568
2569 subSheets.GetSymbolsWithinPath( sheetRefs, sheetPath, false, false );
2570 break;
2571 }
2572 }
2573 }
2574
2575 for( SCH_REFERENCE& ref : sheetRefs )
2576 ref.Split();
2577
2578 return sheetRefs;
2579}
const char * name
Definition: DXF_plotter.cpp:59
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Modify a given item in the model.
Definition: commit.h:108
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:88
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:102
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
Definition: dialog_shim.h:230
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
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 OnFieldsCtrlSelectionChanged(wxDataViewEvent &event) 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
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.
EE_SELECTION & GetSelection()
wxString GetColFieldName(int aCol)
int GetFieldNameCol(wxString aFieldName)
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)
static const wxString ITEM_NUMBER_VARIABLE
void SetIncludeExcludedFromBOM(bool include)
void UpdateReferences(const SCH_REFERENCE_LIST &aRefs)
void ApplyData(std::function< void(SCH_SYMBOL &, SCH_SHEET_PATH &)> symbolChangeHandler)
static const wxString QUANTITY_VARIABLE
void SetGroupColumn(int aCol, bool group)
void RemoveSymbol(const SCH_SYMBOL &aSymbol)
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)
const std::vector< BOM_FIELD > GetFieldsOrdered()
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:115
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:82
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:161
void RemoveListener(SCHEMATIC_LISTENER *aListener)
Remove the specified listener.
Definition: schematic.cpp:815
wxString GetFileName() const override
Helper to retrieve the filename from the root sheet screen.
Definition: schematic.cpp:306
SCH_SHEET_LIST Hierarchy() const override
Return the full schematic flattened hierarchical sheet list.
Definition: schematic.cpp:214
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:808
bool ResolveTextVar(const SCH_SHEET_PATH *aSheetPath, wxString *token, int aDepth) const
Definition: schematic.cpp:253
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:432
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)
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
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
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...
SCH_SCREEN * LastScreen()
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:57
const std::vector< SCH_SHEET_INSTANCE > & GetInstances() const
Definition: sch_sheet.h:419
Schematic symbol object.
Definition: sch_symbol.h:77
int GetFieldCount() const
Return the number of fields in this symbol.
Definition: sch_symbol.h:574
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) override
Populate a std::vector with SCH_FIELDs.
Definition: sch_symbol.cpp:954
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
bool Enable(bool aEnable=true) 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:277
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:646
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:250
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:222
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
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:155
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:77
@ 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:398
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(int aFieldNdx, bool aTranslateForHI)
Return a default symbol field name for field aFieldNdx for all components.
#define DO_TRANSLATE
wxString GetCanonicalFieldName(int idx)
@ DATASHEET_FIELD
name of datasheet
@ FOOTPRINT_FIELD
Field Name Module PCB, i.e. "16DIP300".
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ MANDATORY_FIELDS
The first 5 are mandatory, and must be instantiated in SCH_COMPONENT, LIB_PART, and FOOTPRINT constru...
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
@ SCH_SHEET_T
Definition: typeinfo.h:174
Definition of file extensions used in Kicad.