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