KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_lib_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) 2025 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <algorithm>
23#include <functional>
24#include <set>
25
26#include <confirm.h>
28#include <eda_doc.h>
29#include <fields_grid_table.h>
31#include <grid_tricks.h>
32#include <kiface_base.h>
33#include <pgm_base.h>
34#include <project.h>
35#include <project_sch.h>
37#include <symbol_edit_frame.h>
40#include <template_fieldnames.h>
41#include <trace_helpers.h>
42#include <validators.h>
46#include <wx/arrstr.h>
47#include <wx/menu.h>
48#include <wx/msgdlg.h>
49
52
53
55{
56public:
57 LIB_SYMBOL_REFERENCE_VALIDATOR( std::function<bool()> aAllowEmpty ) :
59 m_allowEmpty( aAllowEmpty )
60 {
61 }
62
68
69 wxObject* Clone() const override { return new LIB_SYMBOL_REFERENCE_VALIDATOR( *this ); }
70
71 bool Validate( wxWindow* aParent ) override
72 {
73 wxTextEntry* const text = GetTextEntry();
74
75 if( text && text->GetValue().IsEmpty() && m_allowEmpty() )
76 return true;
77
78 return FIELD_VALIDATOR::Validate( aParent );
79 }
80
81private:
82 std::function<bool()> m_allowEmpty;
83};
84
85
86static GRID_CELL_URL_EDITOR_CONTEXT getDatasheetContext( const std::vector<LIB_SYMBOL*>& aSymbols )
87{
88 std::vector<EMBEDDED_FILES*> embedTargets;
89 std::vector<EMBEDDED_FILES*> inheritedFiles;
90
91 for( LIB_SYMBOL* symbol : aSymbols )
92 {
93 if( !symbol )
94 continue;
95
96 embedTargets.push_back( symbol->GetEmbeddedFiles() );
97 symbol->AppendParentEmbeddedFiles( inheritedFiles );
98 }
99
100 return MakeGridCellUrlEditorContext( embedTargets, inheritedFiles );
101}
102
103
104enum
105{
111};
112
113
115{
116public:
118 VIEW_CONTROLS_GRID_DATA_MODEL* aViewFieldsData,
120 FIELDS_TABLE_GRID_TRICKS( aParent, aGrid, aDataModel ),
121 m_dlg( aParent ),
122 m_viewControlsDataModel( aViewFieldsData ),
123 m_dataModel( aDataModel )
124 {}
125
126protected:
127 bool toggleCell( int aRow, int aCol, bool aPreserveSelection = false ) override
128 {
129 if( !m_grid->IsEditable() || m_dataModel->IsCellReadOnly( aRow, aCol ) )
130 return false;
131
132 return GRID_TRICKS::toggleCell( aRow, aCol, aPreserveSelection );
133 }
134
135 void showFieldsTablePopupMenu( wxMenu& aMenu, wxGridEvent& aEvent ) override
136 {
137 int row = m_grid->GetGridCursorRow();
138 int col = m_grid->GetGridCursorCol();
139
140 wxMenuItem* deriveMenu = aMenu.Append( MYID_CREATE_DERIVED_SYMBOL, _( "Create Derived Symbol" ),
141 _( "Create a new symbol derived from the selected one" ) );
142
143 if( row >= 0 && col >= 0 )
144 {
145 deriveMenu->Enable( m_grid->IsEditable() && m_dataModel->IsRowSingleSymbol( row ) );
146
147 if( m_dataModel->GetColFieldName( col ) == GetDefaultFieldName( FIELD_T::FOOTPRINT, UNTRANSLATED ) )
148 {
149 wxMenuItem* selectFootprint =
150 aMenu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ), _( "Browse for footprint" ) );
151 selectFootprint->Enable( m_grid->IsEditable() );
152 aMenu.AppendSeparator();
153 }
154 else if( m_dataModel->GetColFieldName( col ) == GetDefaultFieldName( FIELD_T::DATASHEET, UNTRANSLATED ) )
155 {
156 aMenu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ), _( "Show datasheet in browser" ) );
157 aMenu.AppendSeparator();
158 }
159 }
160 else
161 {
162 deriveMenu->Enable( false );
163 }
164
165 GRID_TRICKS::showPopupMenu( aMenu, aEvent );
166 }
167
168 void doFieldsTablePopupSelection( wxCommandEvent& aEvent ) override
169 {
170 int row = m_grid->GetGridCursorRow();
171 int col = m_grid->GetGridCursorCol();
172
173 if( aEvent.GetId() == MYID_SELECT_FOOTPRINT )
174 {
175 if( !m_grid->IsEditable() )
176 return;
177
178 // pick a footprint using the footprint picker.
179 wxString fpid = m_grid->GetCellValue( row, col );
180
181 wxString symbolNetlist =
182 BuildFootprintChooserSymbolNetlist( m_dataModel->GetRowReferences( row ) );
183
184 if( SelectFootprintFromChooser( m_dlg, fpid, symbolNetlist ) )
185 m_grid->SetCellValue( row, col, fpid );
186 }
187 else if( aEvent.GetId() == MYID_SHOW_DATASHEET )
188 {
189 wxString datasheetUri = m_grid->GetCellValue( row, col );
190 GRID_CELL_URL_EDITOR_CONTEXT context = getDatasheetContext( m_dataModel->GetRowReferences( row ) );
191
192 GetAssociatedDocument( m_dlg, datasheetUri, &m_dlg->Prj(), PROJECT_SCH::SchSearchS( &m_dlg->Prj() ),
193 context.m_filesStack );
194 }
195 else if( aEvent.GetId() == MYID_CREATE_DERIVED_SYMBOL )
196 {
197 if( !m_grid->IsEditable() )
198 return;
199
200 EDA_DRAW_FRAME* frame = dynamic_cast<EDA_DRAW_FRAME*>( m_dlg->GetParent() );
201 wxCHECK( frame, /* void */ );
202
203 const LIB_SYMBOL* parentSymbol = m_dataModel->GetSymbolForRow( row );
204
205 wxArrayString symbolNames;
206 wxArrayString derivedSymbols;
207 m_dataModel->GetSymbolNames( symbolNames, SYMBOL_NAME_FILTER::ALL );
208 m_dataModel->GetSymbolNames( derivedSymbols, SYMBOL_NAME_FILTER::DERIVED_ONLY );
209
210 auto validator =
211 [&]( const wxString& aNewName ) -> bool
212 {
213 return symbolNames.Index( UnescapeString( aNewName ) ) == wxNOT_FOUND;
214 };
215
216 const auto styler =
217 [&]( const wxString& aItem ) -> int
218 {
219 for( wxString& candidate : derivedSymbols )
220 {
221 if( candidate.CmpNoCase( aItem ) == 0 )
222 return ITALIC;
223 }
224
225 return 0;
226 };
227
228 DIALOG_NEW_SYMBOL dlg( frame, symbolNames, styler, parentSymbol->GetName(), validator );
229
230 if( dlg.ShowModal() != wxID_OK )
231 return;
232
233 wxString derivedName = dlg.GetName();
234 m_dataModel->CreateDerivedSymbolImmediate( row, col, derivedName );
235
236 if( m_dataModel->IsEdited() )
237 m_dlg->OnModify();
238
239 m_grid->ForceRefresh();
240 }
241 else if( aEvent.GetId() >= GRIDTRICKS_FIRST_SHOWHIDE )
242 {
243 if( !m_grid->CommitPendingChanges( false ) )
244 return;
245
246 // Pop-up column order is the order of the shown fields, not the viewControls order
247 col = aEvent.GetId() - GRIDTRICKS_FIRST_SHOWHIDE;
248
249 bool show = !m_dataModel->GetShowColumn( col );
250
251 m_dlg->ShowHideColumn( col, show );
252
253 wxString fieldName = m_dataModel->GetColFieldName( col );
254
255 for( row = 0; row < m_viewControlsDataModel->GetNumberRows(); row++ )
256 {
257 if( m_viewControlsDataModel->GetUntranslatedFieldName( row ) == fieldName )
258 m_viewControlsDataModel->SetValueAsBool( row, SHOW_FIELD_COLUMN, show );
259 }
260
261 if( m_viewControlsDataModel->GetView() )
262 m_viewControlsDataModel->GetView()->ForceRefresh();
263 }
264 else
265 {
267 }
268 }
269
270private:
274};
275
276
278 DIALOG_FIELDS_TABLE( aParent, aParent->libeditconfig()->m_LibFieldEditor,
279 aParent->libeditconfig()->m_LibFieldEditorBom, nullptr ),
280 m_parent( aParent )
281{
282 loadSymbols();
283
284 const wxString& libName = m_parent->GetTargetLibId().GetLibNickname();
285 const bool readOnly = m_parent->GetLibManager().IsLibraryReadOnly( libName );
286
288 m_dataModel->SetScope( aScope );
289
290 const wxString& targetSymbolName = m_parent->GetTargetLibId().GetLibItemName();
291
292 for( LIB_SYMBOL* symbol : m_symbolsList )
293 {
294 if( symbol->GetName() == targetSymbolName )
295 {
296 if( std::shared_ptr<LIB_SYMBOL> root = symbol->GetRootSymbol() )
297 m_dataModel->SetRelatedSymbolRoot( root->GetName() );
298
299 break;
300 }
301 }
302
303 m_grid->UseNativeColHeader( true );
304 m_grid->SetTable( m_dataModel, true );
305
306 // The field-list grid regroups its rows, so the dialog's position-based Ctrl+Z would shift
307 // values onto the wrong field.
309
310 // must be done after SetTable(), which appears to re-set it
311 m_grid->SetSelectionMode( wxGrid::wxGridSelectCells );
312
313 // add Cut, Copy, and Paste to wxGrid
315 m_dataModel ) );
316
318 m_variantsPanel->Hide();
319
320 m_scope->Clear();
321 m_scope->Append( _( "Whole Library" ) );
322 m_scope->Append( _( "Related Symbols Only" ) );
323 m_scope->SetSelection( static_cast<int>( m_dataModel->GetScope() ) );
324 m_filterScope->SetString( static_cast<int>( BOM_FILTER_SCOPE::REFERENCE ), _( "Symbol Names" ) );
325
326 wxString title = wxString::Format( _( "Symbol Fields Table ('%s' Library)" ), libName );
327
328 if( readOnly )
329 title += wxS( " " ) + _( "[Read Only]" );
330
331 SetTitle( title );
332 m_buttonApply->SetLabel( _( "Apply" ) );
333
335 m_grid->ClearSelection();
336
338 SetReadOnly( readOnly );
339
341
342 SetSize( GetDefaultDialogSize() );
343
345
347
348 m_outputFileName->SetValue( m_cfgBomSettings.m_BomExportFileName );
349
350 Center();
351
352 // Connect Events
353 m_grid->Bind( wxEVT_GRID_COL_SORT, &DIALOG_LIB_FIELDS_TABLE::OnColSort, this );
354 m_grid->Bind( wxEVT_GRID_COL_MOVE, &DIALOG_LIB_FIELDS_TABLE::OnColMove, this );
355 m_grid->GetGridWindow()->Bind( wxEVT_MOTION, &DIALOG_LIB_FIELDS_TABLE::OnGridMouseMove, this );
358}
359
360
362{
363 m_symbolsList.clear();
364
365 LIB_SYMBOL_LIBRARY_MANAGER& libMgr = m_parent->GetLibManager();
366 wxString libName = m_parent->GetTargetLibId().GetLibNickname();
367 wxArrayString symbolNames;
368
369 libMgr.GetSymbolNames( libName, symbolNames );
370
371 if( symbolNames.IsEmpty() )
372 {
373 wxMessageBox( wxString::Format( _( "No symbols found in library '%s'." ), libName ) );
374 return;
375 }
376
377 for( const wxString& symbolName : symbolNames )
378 {
379 LIB_SYMBOL* canvasSymbol = m_parent->GetCurSymbol();
380
381 if( canvasSymbol && canvasSymbol->GetLibraryName() == libName && canvasSymbol->GetName() == symbolName )
382 {
383 m_symbolsList.push_back( canvasSymbol );
384 }
385 else
386 {
387 try
388 {
389 if( LIB_SYMBOL* symbol = m_parent->GetLibManager().GetSymbol( symbolName, libName ) )
390 m_symbolsList.push_back( symbol );
391 }
392 catch( const IO_ERROR& ioe )
393 {
394 wxLogWarning( wxString::Format( _( "Error loading symbol '%s': %s" ), symbolName, ioe.What() ) );
395 }
396 }
397 }
398
399 if( m_symbolsList.empty() )
400 wxMessageBox( _( "No symbols could be loaded from the library." ) );
401}
402
403
405{
406 savePresets( true );
409
410 // Disconnect Events
411 m_grid->GetGridWindow()->Unbind( wxEVT_MOTION, &DIALOG_LIB_FIELDS_TABLE::OnGridMouseMove, this );
412 m_grid->Unbind( wxEVT_GRID_COL_SORT, &DIALOG_LIB_FIELDS_TABLE::OnColSort, this );
413 m_grid->Unbind( wxEVT_GRID_COL_MOVE, &DIALOG_LIB_FIELDS_TABLE::OnColMove, this );
414 m_cbBomPresets->Unbind( wxEVT_CHOICE, &DIALOG_LIB_FIELDS_TABLE::onBomPresetChanged, this );
416
417 // Delete the GRID_TRICKS.
418 m_grid->PopEventHandler( true );
419
420 // we gave ownership of m_viewControlsDataModel & m_dataModel to the wxGrids...
421}
422
423
429{
430 auto rowAllowsEmptyReference =
431 [this]()
432 {
433 int row = m_grid->GetGridCursorRow();
434
435 if( row < 0 || row >= m_dataModel->GetNumberRows() )
436 return false;
437
438 std::vector<LIB_SYMBOL*> symbols = m_dataModel->GetRowReferences( row );
439
440 if( symbols.empty() )
441 return false;
442
443 // Can't have any parent symbols with empty references
444 for( LIB_SYMBOL* symbol : symbols )
445 {
446 if( symbol->IsRoot() )
447 return false;
448 }
449
450 return true;
451 };
452
454 editor->SetValidator( LIB_SYMBOL_REFERENCE_VALIDATOR( rowAllowsEmptyReference ) );
455 return editor;
456}
457
458
460{
461 return new GRID_CELL_URL_EDITOR(
462 this, PROJECT_SCH::SchSearchS( &Prj() ),
463 [this]( int aRow )
464 {
465 return getDatasheetContext( m_dataModel->GetRowReferences( aRow ) );
466 } );
467}
468
469
471{
472 return new GRID_CELL_FPID_EDITOR(
473 this,
474 [this]( int aRow )
475 {
476 return BuildFootprintChooserSymbolNetlist( m_dataModel->GetRowReferences( aRow ) );
477 } );
478}
479
480
482{
483 if( !wxDialog::TransferDataToWindow() )
484 return false;
485
486 LoadFieldNames(); // loads rows into m_viewControlsDataModel and columns into m_dataModel
487
488 m_scope->SetSelection( static_cast<int>( m_dataModel->GetScope() ) );
489
490 // Load our BOM view presets
491 SetUserBomPresets( m_cfgBomSettings.m_BomPresets );
492
493 BOM_PRESET preset = m_cfgBomSettings.m_BomSettings;
494
495 ApplyBomPreset( preset );
497
498 // Load BOM export format presets
499 SetUserBomFmtPresets( m_cfgBomSettings.m_BomFmtPresets );
500 ApplyBomFmtPreset( m_cfgBomSettings.m_BomFmtSettings );
502
503 m_outputFileName->SetValue( m_cfgBomSettings.m_BomExportFileName );
504
505 m_dataModel->SetGroupingEnabled( m_groupSymbolsBox->GetValue() );
506
507 setScope( static_cast<SCOPE>( m_scope->GetSelection() ) );
508
509 return true;
510}
511
512
514{
515 if( !m_grid->CommitPendingChanges() )
516 return false;
517
518 wxString symbolName;
519 wxString errorMessage;
520
521 if( !m_dataModel->ValidateReferences( symbolName, errorMessage ) )
522 {
523 DisplayErrorMessage( this, wxString::Format( _( "Invalid reference for symbol '%s'." ), symbolName ),
524 errorMessage );
525 return false;
526 }
527
528 if( !wxDialog::TransferDataFromWindow() )
529 return false;
530
531 std::set<KIID_PATH> savedSelection = SaveGridSelection();
532 bool updateCanvas = false;
533
534 m_dataModel->ApplyData(
535 [&]( LIB_SYMBOL* aSymbol )
536 {
537 m_parent->GetLibManager().UpdateSymbol( aSymbol, aSymbol->GetLibNickname() );
538
539 if( m_parent->GetCurSymbol() == aSymbol )
540 updateCanvas = true;
541 },
542 [&]()
543 {
544 auto createdSymbols = m_dataModel->GetAndClearCreatedDerivedSymbols();
545
546 wxLogTrace( traceLibFieldTable, "Post-apply handler: found %zu created derived symbols",
547 createdSymbols.size() );
548
549 for( const auto& [symbol, libraryName] : createdSymbols )
550 {
551 if( !libraryName.IsEmpty() )
552 {
553 wxLogTrace( traceLibFieldTable, "Updating symbol '%s' (UUID: %s) in library '%s'",
554 symbol->GetName(), symbol->m_Uuid.AsString(), libraryName );
555 m_parent->GetLibManager().UpdateSymbol( symbol, libraryName );
556 }
557 }
558
559 if( !createdSymbols.empty() )
560 {
561 wxLogTrace( traceLibFieldTable, "Syncing libraries due to %zu new symbols",
562 createdSymbols.size() );
563
564 std::vector<LIB_SYMBOL*> symbolsToPreserve;
565
566 for( const auto& [symbol, libraryName] : createdSymbols )
567 symbolsToPreserve.push_back( symbol );
568
569 m_parent->SyncLibraries( false );
570
571 for( LIB_SYMBOL* symbol : symbolsToPreserve )
572 {
573 bool found = std::any_of( m_symbolsList.begin(), m_symbolsList.end(),
574 [&]( LIB_SYMBOL* aExistingSymbol )
575 {
576 return aExistingSymbol->m_Uuid == symbol->m_Uuid;
577 } );
578
579 if( !found )
580 {
581 wxLogTrace( traceLibFieldTable, "Re-adding symbol '%s' to list after sync",
582 symbol->GetName() );
583 m_symbolsList.push_back( symbol );
584 }
585 }
586 }
587
588 wxLogTrace( traceLibFieldTable, "Dialog symbol list size after processing: %zu",
589 m_symbolsList.size() );
590 } );
591
592 ClearModify();
593 m_dataModel->RebuildRows();
594 RestoreGridSelection( savedSelection );
595 m_parent->RefreshLibraryTree();
596
597 if( updateCanvas )
598 {
599 m_parent->OnModify();
600 m_parent->HardRedraw();
601 }
602
603 return true;
604}
605
606
608{
609 auto addMandatoryField =
610 [&]( FIELD_T aFieldId, bool aShow, bool aGroupBy )
611 {
612 m_mandatoryFieldListIndexes[aFieldId] = m_viewControlsDataModel->GetNumberRows();
613
615 aShow, aGroupBy );
616 };
617
618 AddField( LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_NAME, _( "Symbol Name" ), true, false );
619
620 // Add mandatory fields first show groupBy
621 addMandatoryField( FIELD_T::REFERENCE, false, false );
622 addMandatoryField( FIELD_T::VALUE, true, false );
623 addMandatoryField( FIELD_T::FOOTPRINT, true, false );
624 addMandatoryField( FIELD_T::DATASHEET, true, false );
625 addMandatoryField( FIELD_T::DESCRIPTION, false, false );
626
627 // Generated fields present only in the fields table
629 AddField( wxS( "${EXCLUDE_FROM_BOM}" ), _( "Exclude From BOM" ), true, false );
630 AddField( wxS( "${EXCLUDE_FROM_SIM}" ), _( "Exclude From Simulation" ), true, false );
631 AddField( wxS( "${EXCLUDE_FROM_BOARD}" ), _( "Exclude From Board" ), true, false );
632 AddField( wxS( "${EXCLUDE_FROM_POS_FILES}" ), _( "Exclude From Position Files" ), true, false );
633 AddField( LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_IS_POWER, _( "Power Symbol" ), true, false );
634 AddField( LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_IS_LOCAL_POWER, _( "Local Power Symbol" ), true, false );
635
636 // User field names are stored and matched case-sensitively (see issue #24021), so each
637 // distinct name gets its own column rather than collapsing case variants together.
638 std::set<wxString> userFieldNames;
639
640 for( LIB_SYMBOL* symbol : m_symbolsList )
641 {
642 std::vector<SCH_FIELD*> fields;
643 symbol->GetFields( fields );
644
645 for( SCH_FIELD* field : fields )
646 {
647 if( !field->IsMandatory() && !field->IsPrivate() )
648 userFieldNames.insert( field->GetName() );
649 }
650 }
651
652 for( const wxString& fieldName : userFieldNames )
653 AddField( fieldName, GetGeneratedFieldDisplayName( fieldName ), true, false );
654
655 // Add any global template field names which aren't already present.
656 for( const TEMPLATE_FIELDNAME& templateField :
657 Pgm().GetCommonSettings()->m_FieldNameTemplates.GetTemplateFieldNames(
658 TEMPLATES::SCOPE::GLOBAL ) )
659 {
660 if( userFieldNames.count( templateField.m_Name ) == 0 )
661 AddField( templateField.m_Name, GetGeneratedFieldDisplayName( templateField.m_Name ), false, false );
662 }
663}
664
665
667{
668 m_dataModel->SetScope( aScope );
669 m_dataModel->RebuildRows();
670}
671
672
673void DIALOG_LIB_FIELDS_TABLE::OnScope( wxCommandEvent& aEvent )
674{
675 switch( aEvent.GetSelection() )
676 {
677 case 0: setScope( SCOPE::SCOPE_LIBRARY ); break;
678 case 1: setScope( SCOPE::SCOPE_RELATED_SYMBOLS ); break;
679 }
680}
681
682
683void DIALOG_LIB_FIELDS_TABLE::OnMenu( wxCommandEvent& aEvent )
684{
685 // Build a pop menu:
686 wxMenu menu;
687
688 menu.Append( MYID_INCLUDE_DNP, _( "Include 'DNP' Symbols" ),
689 _( "Show symbols marked 'DNP' in the table. This setting also controls whether or not 'DNP' "
690 "symbols are included on export." ),
691 wxITEM_CHECK );
692 menu.Check( MYID_INCLUDE_DNP, !m_dataModel->GetExcludeDNP() );
693
694 menu.Append( MYID_INCLUDE_EXCLUDED_FROM_BOM, _( "Include 'Exclude from BOM' Symbols" ),
695 _( "Show symbols marked 'Exclude from BOM' in the table. Symbols marked 'Exclude from BOM' "
696 "are never included on export." ),
697 wxITEM_CHECK );
698 menu.Check( MYID_INCLUDE_EXCLUDED_FROM_BOM, m_dataModel->GetIncludeExcludedFromBOM() );
699
700 // menuId is the selected submenu id from the popup menu or wxID_NONE
701 int menuId = m_bMenu->GetPopupMenuSelectionFromUser( menu );
702
703 if( menuId == 0 || menuId == MYID_INCLUDE_DNP )
704 {
705 m_dataModel->SetExcludeDNP( !m_dataModel->GetExcludeDNP() );
706 m_dataModel->RebuildRows();
707 m_grid->ForceRefresh();
708
710 }
711 else if( menuId == 1 || menuId == MYID_INCLUDE_EXCLUDED_FROM_BOM )
712 {
713 m_dataModel->SetIncludeExcludedFromBOM( !m_dataModel->GetIncludeExcludedFromBOM() );
714 m_dataModel->RebuildRows();
715 m_grid->ForceRefresh();
716
718 }
719}
720
721
722void DIALOG_LIB_FIELDS_TABLE::OnSaveAndContinue( wxCommandEvent& aEvent )
723{
725 {
726 m_cfgBomSettings.m_BomExportFileName = m_outputFileName->GetValue();
727 ClearModify();
728 }
729}
730
731
732void DIALOG_LIB_FIELDS_TABLE::OnCancel( wxCommandEvent& aEvent )
733{
734 m_grid->CommitPendingChanges( true );
735
736 if( m_dataModel->IsEdited() )
737 {
738 if( !HandleUnsavedChanges( this, _( "Save changes?" ),
739 [&]() -> bool
740 {
741 return TransferDataFromWindow();
742 } ) )
743 {
744 return;
745 }
746 }
747
748 EndModal( wxID_CANCEL );
749}
750
751
752void DIALOG_LIB_FIELDS_TABLE::OnOk( wxCommandEvent& aEvent )
753{
755 return;
756
757 m_cfgBomSettings.m_BomExportFileName = m_outputFileName->GetValue();
758 EndModal( wxID_OK );
759}
760
761
762void DIALOG_LIB_FIELDS_TABLE::OnClose( wxCloseEvent& aEvent )
763{
764 m_grid->CommitPendingChanges( true );
765
766 if( m_dataModel->IsEdited() && aEvent.CanVeto() )
767 {
768 if( !HandleUnsavedChanges( this, _( "Save changes?" ),
769 [&]() -> bool
770 {
771 return TransferDataFromWindow();
772 } ) )
773 {
774 aEvent.Veto();
775 return;
776 }
777 }
778
779 aEvent.Skip();
780}
781
782
784{
785 std::vector<BOM_PRESET> presets = BOM_PRESET::BuiltInPresets();
786
787 for( BOM_PRESET& preset : presets )
788 {
789 if( preset.sortField == GetDefaultFieldName( FIELD_T::REFERENCE, TRANSLATED ) )
791
792 for( BOM_FIELD& field : preset.fieldsOrdered )
793 {
795 {
797 field.label = wxS( "Symbol Name" );
798 field.groupBy = false;
799 }
800 }
801
802 if( preset.name == BOM_PRESET::DefaultEditing().name )
803 {
804 preset.groupSymbols = false;
805 preset.fieldsOrdered = {
806 { LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_NAME, wxS( "Symbol Name" ), true, false },
807 { GetDefaultFieldName( FIELD_T::REFERENCE, UNTRANSLATED ), wxS( "Reference" ), false, false },
808 { GetDefaultFieldName( FIELD_T::VALUE, UNTRANSLATED ), wxS( "Value" ), true, false },
809 { GetDefaultFieldName( FIELD_T::FOOTPRINT, UNTRANSLATED ), wxS( "Footprint" ), true, false },
810 { GetDefaultFieldName( FIELD_T::DATASHEET, UNTRANSLATED ), wxS( "Datasheet" ), true, false },
811 { GetDefaultFieldName( FIELD_T::DESCRIPTION, UNTRANSLATED ), wxS( "Description" ), false, false },
812 { LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_KEYWORDS, wxS( "Keywords" ), true, false },
813 { wxS( "${EXCLUDE_FROM_BOM}" ), wxS( "Exclude From BOM" ), true, false },
814 { wxS( "${EXCLUDE_FROM_SIM}" ), wxS( "Exclude From Simulation" ), true, false },
815 { wxS( "${EXCLUDE_FROM_BOARD}" ), wxS( "Exclude From Board" ), true, false },
816 { wxS( "${EXCLUDE_FROM_POS_FILES}" ), wxS( "Exclude From Position Files" ), true, false },
817 { LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_IS_POWER, wxS( "Power Symbol" ), true, false },
818 { LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_IS_LOCAL_POWER, wxS( "Local Power Symbol" ), true, false },
819 };
820 }
821 }
822
823 return presets;
824}
825
826
828{
829 return wxEmptyString;
830}
831
832
833bool DIALOG_LIB_FIELDS_TABLE::resolveTextVar( wxString* aToken ) const
834{
835 return Prj().TextVarResolver( aToken );
836}
void SetUserBomFmtPresets(std::vector< BOM_FMT_PRESET > &aPresetList)
wxSize GetDefaultDialogSize() const
void OnColMove(wxGridEvent &aEvent)
void OnColSort(wxGridEvent &aEvent)
void OnGridMouseMove(wxMouseEvent &aEvent)
bool savePresets(bool aSaveCurrentSettings)
void RestoreGridSelection(const std::set< KIID_PATH > &aItemKeys)
Restore a selection previously returned by SaveGridSelection().
std::map< FIELD_T, int > m_mandatoryFieldListIndexes
void onBomFmtPresetChanged(wxCommandEvent &aEvent)
void SetUserBomPresets(std::vector< BOM_PRESET > &aPresetList)
void ApplyBomFmtPreset(const wxString &aPresetName)
DIALOG_FIELDS_TABLE(wxWindow *aParent, FIELDS_TABLE_SETTINGS &aPanelSettings, FIELDS_TABLE_BOM_SETTINGS &aBomSettings, JOB_EXPORT_BOM *aJob)
FIELDS_TABLE_BOM_SETTINGS & m_cfgBomSettings
void onBomPresetChanged(wxCommandEvent &aEvent)
void SetReadOnly(bool aReadOnly)
std::set< KIID_PATH > SaveGridSelection()
Save the grid selection by stable item identity so it can survive a row rebuild.
void ApplyBomPreset(const wxString &aPresetName)
VIEW_CONTROLS_GRID_DATA_MODEL * m_viewControlsDataModel
void AddField(const wxString &aFieldName, const wxString &aLabelValue, bool aShow, bool aGroupBy, bool aAddedByUser=false)
wxGridCellEditor * createFootprintEditor() override
void OnOk(wxCommandEvent &aEvent) override
void OnSaveAndContinue(wxCommandEvent &aEvent) override
LIB_FIELDS_EDITOR_GRID_DATA_MODEL * m_dataModel
std::vector< BOM_PRESET > getBuiltInBomPresets() const override
void OnCancel(wxCommandEvent &aEvent) override
void OnMenu(wxCommandEvent &aEvent) override
void LoadFieldNames()
Construct the rows of m_fieldsCtrl and the columns of m_dataModel from a union of all field names in ...
wxGridCellEditor * createReferenceEditor() override
Lib symbols have different rules for references.
void setScope(LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE aScope)
std::vector< LIB_SYMBOL * > m_symbolsList
void OnClose(wxCloseEvent &aEvent) override
wxString resolveVariant() const override
wxGridCellEditor * createDatasheetEditor() override
DIALOG_LIB_FIELDS_TABLE(SYMBOL_EDIT_FRAME *aParent, LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE aScope)
bool resolveTextVar(wxString *aToken) const override
void OnScope(wxCommandEvent &aEvent) override
wxString GetName() const override
void ExcludeFromControlUndoRedo(wxWindow *aWindow)
Opt a control out of the dialog's generic Ctrl+Z/Ctrl+Y undo/redo.
void OptOut(wxWindow *aWindow)
Opt out of control state saving.
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:94
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
int ShowModal() override
The base class for create windows for drawing purpose.
FIELDS_TABLE_GRID_TRICKS(DIALOG_FIELDS_TABLE *aDialog, WX_GRID *aGrid, FIELDS_TABLE_DATA_MODEL_BASE *aDataModel)
static constexpr int FIRST_CLIENT_ID
virtual bool Validate(wxWindow *aParent) override
Override the default Validate() function provided by wxTextValidator to provide better error messages...
FIELD_VALIDATOR(FIELD_T aFieldId, wxString *aValue=nullptr)
This class works around a bug in wxGrid where the first keystroke doesn't get sent through the valida...
virtual void doPopupSelection(wxCommandEvent &event)
virtual void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent)
WX_GRID * m_grid
I don't own the grid, but he owns me.
virtual bool toggleCell(int aRow, int aCol, bool aPreserveSelection=false)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
bool toggleCell(int aRow, int aCol, bool aPreserveSelection=false) override
LIB_FIELDS_EDITOR_GRID_DATA_MODEL * m_dataModel
LIB_FIELDS_EDITOR_GRID_TRICKS(DIALOG_LIB_FIELDS_TABLE *aParent, WX_GRID *aGrid, VIEW_CONTROLS_GRID_DATA_MODEL *aViewFieldsData, LIB_FIELDS_EDITOR_GRID_DATA_MODEL *aDataModel)
VIEW_CONTROLS_GRID_DATA_MODEL * m_viewControlsDataModel
void doFieldsTablePopupSelection(wxCommandEvent &aEvent) override
void showFieldsTablePopupMenu(wxMenu &aMenu, wxGridEvent &aEvent) override
Symbol library management helper that is specific to the symbol library editor frame.
LIB_SYMBOL_REFERENCE_VALIDATOR(std::function< bool()> aAllowEmpty)
bool Validate(wxWindow *aParent) override
Override the default Validate() function provided by wxTextValidator to provide better error messages...
LIB_SYMBOL_REFERENCE_VALIDATOR(const LIB_SYMBOL_REFERENCE_VALIDATOR &aOther)
Define a library symbol object.
Definition lib_symbol.h:119
const wxString GetLibraryName() const
wxString GetName() const override
Definition lib_symbol.h:181
wxString GetLibNickname() const override
Sets the Description field text value.
Definition lib_symbol.h:194
static SEARCH_STACK * SchSearchS(PROJECT *aProject)
Accessor for Eeschema search stack.
virtual bool TextVarResolver(wxString *aToken) const
Definition project.cpp:81
The symbol library editor main window.
void GetSymbolNames(const wxString &aLibName, wxArrayString &aSymbolNames, SYMBOL_NAME_FILTER aFilter=SYMBOL_NAME_FILTER::ALL)
wxString GetGeneratedFieldDisplayName(const wxString &aSource)
Returns any variables unexpanded, e.g.
Definition common.cpp:481
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition confirm.cpp:146
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
This file is part of the common library.
DIALOG_LIB_NEW_SYMBOL DIALOG_NEW_SYMBOL
static GRID_CELL_URL_EDITOR_CONTEXT getDatasheetContext(const std::vector< LIB_SYMBOL * > &aSymbols)
LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SCOPE SCOPE
@ MYID_INCLUDE_EXCLUDED_FROM_BOM
@ MYID_CREATE_DERIVED_SYMBOL
#define _(s)
bool GetAssociatedDocument(wxWindow *aParent, const wxString &aDocName, PROJECT *aProject, SEARCH_STACK *aPaths, std::vector< EMBEDDED_FILES * > aFilesStack)
Open a document (file) with the suitable browser.
Definition eda_doc.cpp:59
This file is part of the common library.
wxString BuildFootprintChooserSymbolNetlist(const LIB_SYMBOL *aSymbol)
@ ITALIC
Definition font.h:44
bool SelectFootprintFromChooser(DIALOG_SHIM *aDialog, wxString &aFootprint, const wxString &aSymbolNetlist)
GRID_CELL_URL_EDITOR_CONTEXT MakeGridCellUrlEditorContext(const std::vector< EMBEDDED_FILES * > &aEmbedTargets, const std::vector< EMBEDDED_FILES * > &aAdditionalLookupFiles)
@ GRIDTRICKS_FIRST_SHOWHIDE
Definition grid_tricks.h:47
const wxChar *const traceLibFieldTable
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
wxString UnescapeString(const wxString &aSource)
wxString label
wxString name
std::vector< EMBEDDED_FILES * > m_filesStack
Hold a name of a symbol's field, field value, and default visibility.
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
@ UNTRANSLATED
@ TRANSLATED
JSON_SCHEMA_VALIDATOR validator(schema)
wxLogTrace helper definitions.
Custom text control validator definitions.