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{
112};
113
114
116{
117public:
119 VIEW_CONTROLS_GRID_DATA_MODEL* aViewFieldsData,
121 FIELDS_TABLE_GRID_TRICKS( aParent, aGrid, aDataModel ),
122 m_dlg( aParent ),
123 m_viewControlsDataModel( aViewFieldsData ),
124 m_dataModel( aDataModel )
125 {}
126
127protected:
128 bool toggleCell( int aRow, int aCol, bool aPreserveSelection = false ) override
129 {
130 if( !m_grid->IsEditable() || m_dataModel->IsCellReadOnly( aRow, aCol ) )
131 return false;
132
133 return GRID_TRICKS::toggleCell( aRow, aCol, aPreserveSelection );
134 }
135
136 void showFieldsTablePopupMenu( wxMenu& aMenu, wxGridEvent& aEvent ) override
137 {
138 int row = m_grid->GetGridCursorRow();
139 int col = m_grid->GetGridCursorCol();
140
141 wxMenuItem* useParentMenu = aMenu.Append( MYID_USE_PARENT_VALUE, _( "Use Parent Value" ),
142 _( "Remove the local override and inherit the parent's value" ) );
143 useParentMenu->Enable( row >= 0 && col >= 0 && m_grid->IsEditable()
144 && m_dataModel->CanUseParentValue( row, col ) );
145
146 wxMenuItem* deriveMenu = aMenu.Append( MYID_CREATE_DERIVED_SYMBOL, _( "Create Derived Symbol" ),
147 _( "Create a new symbol derived from the selected one" ) );
148
149 if( row >= 0 && col >= 0 )
150 {
151 deriveMenu->Enable( m_grid->IsEditable() && m_dataModel->IsRowSingleSymbol( row ) );
152
153 if( m_dataModel->GetColFieldName( col ) == GetDefaultFieldName( FIELD_T::FOOTPRINT, UNTRANSLATED ) )
154 {
155 wxMenuItem* selectFootprint =
156 aMenu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ), _( "Browse for footprint" ) );
157 selectFootprint->Enable( m_grid->IsEditable() );
158 aMenu.AppendSeparator();
159 }
160 else if( m_dataModel->GetColFieldName( col ) == GetDefaultFieldName( FIELD_T::DATASHEET, UNTRANSLATED ) )
161 {
162 aMenu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ), _( "Show datasheet in browser" ) );
163 aMenu.AppendSeparator();
164 }
165 }
166 else
167 {
168 deriveMenu->Enable( false );
169 }
170
171 GRID_TRICKS::showPopupMenu( aMenu, aEvent );
172 }
173
174 void doFieldsTablePopupSelection( wxCommandEvent& aEvent ) override
175 {
176 int row = m_grid->GetGridCursorRow();
177 int col = m_grid->GetGridCursorCol();
178
179 if( aEvent.GetId() == MYID_USE_PARENT_VALUE )
180 {
181 if( !m_grid->IsEditable() || !m_grid->CommitPendingChanges( false )
182 || !m_dataModel->CanUseParentValue( row, col ) )
183 {
184 return;
185 }
186
187 m_dataModel->UseParentValue( row, col );
188 m_dlg->OnModify();
189 m_grid->ForceRefresh();
190 }
191 else if( aEvent.GetId() == MYID_SELECT_FOOTPRINT )
192 {
193 if( !m_grid->IsEditable() )
194 return;
195
196 // pick a footprint using the footprint picker.
197 wxString fpid = m_grid->GetCellValue( row, col );
198
199 wxString symbolNetlist =
200 BuildFootprintChooserSymbolNetlist( m_dataModel->GetRowReferences( row ) );
201
202 if( SelectFootprintFromChooser( m_dlg, fpid, symbolNetlist ) )
203 {
204 m_grid->SetCellValue( row, col, fpid );
205
206 wxGridEvent evt( m_grid->GetId(), wxEVT_GRID_CELL_CHANGED, m_grid, row, col );
207 m_grid->GetEventHandler()->ProcessEvent( evt );
208 m_dlg->OnModify();
209 }
210 }
211 else if( aEvent.GetId() == MYID_SHOW_DATASHEET )
212 {
213 wxString datasheetUri = m_grid->GetCellValue( row, col );
214 GRID_CELL_URL_EDITOR_CONTEXT context = getDatasheetContext( m_dataModel->GetRowReferences( row ) );
215
216 GetAssociatedDocument( m_dlg, datasheetUri, &m_dlg->Prj(), PROJECT_SCH::SchSearchS( &m_dlg->Prj() ),
217 context.m_filesStack );
218 }
219 else if( aEvent.GetId() == MYID_CREATE_DERIVED_SYMBOL )
220 {
221 if( !m_grid->IsEditable() )
222 return;
223
224 EDA_DRAW_FRAME* frame = dynamic_cast<EDA_DRAW_FRAME*>( m_dlg->GetParent() );
225 wxCHECK( frame, /* void */ );
226
227 const LIB_SYMBOL* parentSymbol = m_dataModel->GetSymbolForRow( row );
228
229 wxArrayString symbolNames;
230 wxArrayString derivedSymbols;
231 m_dataModel->GetSymbolNames( symbolNames, SYMBOL_NAME_FILTER::ALL );
232 m_dataModel->GetSymbolNames( derivedSymbols, SYMBOL_NAME_FILTER::DERIVED_ONLY );
233
234 auto validator =
235 [&]( const wxString& aNewName ) -> bool
236 {
237 if( aNewName.IsEmpty() )
238 {
239 wxMessageBox( _( "Symbol must have a name." ) );
240 return false;
241 }
242
243 return symbolNames.Index( UnescapeString( aNewName ), false ) == wxNOT_FOUND;
244 };
245
246 const auto styler =
247 [&]( const wxString& aItem ) -> int
248 {
249 for( wxString& candidate : derivedSymbols )
250 {
251 if( candidate.CmpNoCase( aItem ) == 0 )
252 return ITALIC;
253 }
254
255 return 0;
256 };
257
258 DIALOG_NEW_SYMBOL dlg( frame, symbolNames, styler, parentSymbol->GetName(), validator );
259
260 if( dlg.ShowModal() != wxID_OK )
261 return;
262
263 wxString derivedName = dlg.GetName();
264 m_dataModel->CreateDerivedSymbolImmediate( row, col, derivedName );
265
266 if( m_dataModel->IsEdited() )
267 m_dlg->OnModify();
268
269 m_grid->ForceRefresh();
270 }
271 else if( aEvent.GetId() >= GRIDTRICKS_FIRST_SHOWHIDE )
272 {
273 if( !m_grid->CommitPendingChanges( false ) )
274 return;
275
276 // Pop-up column order is the order of the shown fields, not the viewControls order
277 col = aEvent.GetId() - GRIDTRICKS_FIRST_SHOWHIDE;
278
279 bool show = !m_dataModel->GetShowColumn( col );
280
281 m_dlg->ShowHideColumn( col, show );
282
283 wxString fieldName = m_dataModel->GetColFieldName( col );
284
285 for( row = 0; row < m_viewControlsDataModel->GetNumberRows(); row++ )
286 {
287 if( m_viewControlsDataModel->GetUntranslatedFieldName( row ) == fieldName )
288 m_viewControlsDataModel->SetValueAsBool( row, SHOW_FIELD_COLUMN, show );
289 }
290
291 if( m_viewControlsDataModel->GetView() )
292 m_viewControlsDataModel->GetView()->ForceRefresh();
293 }
294 else
295 {
297 }
298 }
299
300private:
304};
305
306
308 DIALOG_FIELDS_TABLE( aParent, aParent->libeditconfig()->m_LibFieldEditor,
309 aParent->libeditconfig()->m_LibFieldEditorBom, nullptr ),
310 m_parent( aParent )
311{
312 loadSymbols();
313
314 const wxString& libName = m_parent->GetTargetLibId().GetLibNickname();
315 const bool readOnly = m_parent->GetLibManager().IsLibraryReadOnly( libName );
316
318 m_dataModel->SetScope( aScope );
319
320 const wxString& targetSymbolName = m_parent->GetTargetLibId().GetLibItemName();
321
322 for( LIB_SYMBOL* symbol : m_symbolsList )
323 {
324 if( symbol->GetName() == targetSymbolName )
325 {
326 if( std::shared_ptr<LIB_SYMBOL> root = symbol->GetRootSymbol() )
327 m_dataModel->SetRelatedSymbolRoot( root->GetName() );
328
329 break;
330 }
331 }
332
333 m_grid->UseNativeColHeader( true );
334 m_grid->SetTable( m_dataModel, true );
335
336 // The field-list grid regroups its rows, so the dialog's position-based Ctrl+Z would shift
337 // values onto the wrong field.
339
340 // must be done after SetTable(), which appears to re-set it
341 m_grid->SetSelectionMode( wxGrid::wxGridSelectCells );
342
343 // add Cut, Copy, and Paste to wxGrid
345 m_dataModel ) );
346
348 m_variantsPanel->Hide();
349
350 m_scope->Clear();
351 m_scope->Append( _( "Whole Library" ) );
352 m_scope->Append( _( "Related Symbols Only" ) );
353 m_scope->SetSelection( static_cast<int>( m_dataModel->GetScope() ) );
354 m_filterScope->SetString( static_cast<int>( BOM_FILTER_SCOPE::REFERENCE ), _( "Symbol Names" ) );
355
356 wxString title = wxString::Format( _( "Symbol Fields Table ('%s' Library)" ), libName );
357
358 if( readOnly )
359 title += wxS( " " ) + _( "[Read Only]" );
360
361 SetTitle( title );
362 m_buttonApply->SetLabel( _( "Apply" ) );
363
365 m_grid->ClearSelection();
366
368 SetReadOnly( readOnly );
369
371
372 SetSize( GetDefaultDialogSize() );
373
375
377
378 m_outputFileName->SetValue( m_cfgBomSettings.m_BomExportFileName );
379
380 Center();
381
382 // Connect Events
383 m_grid->Bind( wxEVT_GRID_COL_SORT, &DIALOG_LIB_FIELDS_TABLE::OnColSort, this );
384 m_grid->Bind( wxEVT_GRID_COL_MOVE, &DIALOG_LIB_FIELDS_TABLE::OnColMove, this );
385 m_grid->GetGridWindow()->Bind( wxEVT_MOTION, &DIALOG_LIB_FIELDS_TABLE::OnGridMouseMove, this );
388}
389
390
392{
393 m_symbolsList.clear();
394
395 LIB_SYMBOL_LIBRARY_MANAGER& libMgr = m_parent->GetLibManager();
396 wxString libName = m_parent->GetTargetLibId().GetLibNickname();
397 wxArrayString symbolNames;
398
399 libMgr.GetSymbolNames( libName, symbolNames );
400
401 if( symbolNames.IsEmpty() )
402 {
403 wxMessageBox( wxString::Format( _( "No symbols found in library '%s'." ), libName ) );
404 return;
405 }
406
407 for( const wxString& symbolName : symbolNames )
408 {
409 LIB_SYMBOL* canvasSymbol = m_parent->GetCurSymbol();
410
411 if( canvasSymbol && canvasSymbol->GetLibraryName() == libName
412 && UnescapeString( canvasSymbol->GetName() ) == symbolName )
413 {
414 m_symbolsList.push_back( canvasSymbol );
415 }
416 else
417 {
418 try
419 {
420 if( LIB_SYMBOL* symbol = m_parent->GetLibManager().GetSymbol( symbolName, libName ) )
421 m_symbolsList.push_back( symbol );
422 }
423 catch( const IO_ERROR& ioe )
424 {
425 wxLogWarning( wxString::Format( _( "Error loading symbol '%s': %s" ), symbolName, ioe.What() ) );
426 }
427 }
428 }
429
430 if( m_symbolsList.empty() )
431 wxMessageBox( _( "No symbols could be loaded from the library." ) );
432}
433
434
436{
437 savePresets( true );
440
441 // Disconnect Events
442 m_grid->GetGridWindow()->Unbind( wxEVT_MOTION, &DIALOG_LIB_FIELDS_TABLE::OnGridMouseMove, this );
443 m_grid->Unbind( wxEVT_GRID_COL_SORT, &DIALOG_LIB_FIELDS_TABLE::OnColSort, this );
444 m_grid->Unbind( wxEVT_GRID_COL_MOVE, &DIALOG_LIB_FIELDS_TABLE::OnColMove, this );
445 m_cbBomPresets->Unbind( wxEVT_CHOICE, &DIALOG_LIB_FIELDS_TABLE::onBomPresetChanged, this );
447
448 // Delete the GRID_TRICKS.
449 m_grid->PopEventHandler( true );
450
451 // we gave ownership of m_viewControlsDataModel & m_dataModel to the wxGrids...
452}
453
454
460{
461 auto rowAllowsEmptyReference =
462 [this]()
463 {
464 int row = m_grid->GetGridCursorRow();
465
466 if( row < 0 || row >= m_dataModel->GetNumberRows() )
467 return false;
468
469 std::vector<LIB_SYMBOL*> symbols = m_dataModel->GetRowReferences( row );
470
471 if( symbols.empty() )
472 return false;
473
474 // Can't have any parent symbols with empty references
475 for( LIB_SYMBOL* symbol : symbols )
476 {
477 if( symbol->IsRoot() )
478 return false;
479 }
480
481 return true;
482 };
483
485 editor->SetValidator( LIB_SYMBOL_REFERENCE_VALIDATOR( rowAllowsEmptyReference ) );
486 return editor;
487}
488
489
491{
492 return new GRID_CELL_URL_EDITOR(
493 this, PROJECT_SCH::SchSearchS( &Prj() ),
494 [this]( int aRow )
495 {
496 return getDatasheetContext( m_dataModel->GetRowReferences( aRow ) );
497 } );
498}
499
500
502{
503 return new GRID_CELL_FPID_EDITOR(
504 this,
505 [this]( int aRow )
506 {
507 return BuildFootprintChooserSymbolNetlist( m_dataModel->GetRowReferences( aRow ) );
508 } );
509}
510
511
513{
514 if( !wxDialog::TransferDataToWindow() )
515 return false;
516
517 LoadFieldNames(); // loads rows into m_viewControlsDataModel and columns into m_dataModel
518
519 m_scope->SetSelection( static_cast<int>( m_dataModel->GetScope() ) );
520
521 // Load our BOM view presets
522 SetUserBomPresets( m_cfgBomSettings.m_BomPresets );
523
524 BOM_PRESET preset = m_cfgBomSettings.m_BomSettings;
525
526 ApplyBomPreset( preset );
528
529 // Load BOM export format presets
530 SetUserBomFmtPresets( m_cfgBomSettings.m_BomFmtPresets );
531 ApplyBomFmtPreset( m_cfgBomSettings.m_BomFmtSettings );
533
534 m_outputFileName->SetValue( m_cfgBomSettings.m_BomExportFileName );
535
536 m_dataModel->SetGroupingEnabled( m_groupSymbolsBox->GetValue() );
537
538 setScope( static_cast<SCOPE>( m_scope->GetSelection() ) );
539
540 return true;
541}
542
543
545{
546 if( !m_grid->CommitPendingChanges() )
547 return false;
548
549 wxString symbolName;
550 wxString errorMessage;
551
552 if( !m_dataModel->ValidateReferences( symbolName, errorMessage ) )
553 {
554 DisplayErrorMessage( this, wxString::Format( _( "Invalid reference for symbol '%s'." ), symbolName ),
555 errorMessage );
556 return false;
557 }
558
559 if( !wxDialog::TransferDataFromWindow() )
560 return false;
561
562 std::set<KIID_PATH> savedSelection = SaveGridSelection();
563 bool updateCanvas = false;
564
565 m_dataModel->ApplyData(
566 [&]( LIB_SYMBOL* aSymbol )
567 {
568 m_parent->GetLibManager().UpdateSymbol( aSymbol, aSymbol->GetLibNickname() );
569
570 if( m_parent->GetCurSymbol() == aSymbol )
571 updateCanvas = true;
572 },
573 [&]()
574 {
575 auto createdSymbols = m_dataModel->GetAndClearCreatedDerivedSymbols();
576
577 wxLogTrace( traceLibFieldTable, "Post-apply handler: found %zu created derived symbols",
578 createdSymbols.size() );
579
580 for( const auto& [symbol, libraryName] : createdSymbols )
581 {
582 if( !libraryName.IsEmpty() )
583 {
584 wxLogTrace( traceLibFieldTable, "Updating symbol '%s' (UUID: %s) in library '%s'",
585 symbol->GetName(), symbol->m_Uuid.AsString(), libraryName );
586 m_parent->GetLibManager().UpdateSymbol( symbol, libraryName );
587 }
588 }
589
590 if( !createdSymbols.empty() )
591 {
592 wxLogTrace( traceLibFieldTable, "Syncing libraries due to %zu new symbols",
593 createdSymbols.size() );
594
595 std::vector<LIB_SYMBOL*> symbolsToPreserve;
596
597 for( const auto& [symbol, libraryName] : createdSymbols )
598 symbolsToPreserve.push_back( symbol );
599
600 m_parent->SyncLibraries( false );
601
602 for( LIB_SYMBOL* symbol : symbolsToPreserve )
603 {
604 bool found = std::any_of( m_symbolsList.begin(), m_symbolsList.end(),
605 [&]( LIB_SYMBOL* aExistingSymbol )
606 {
607 return aExistingSymbol->m_Uuid == symbol->m_Uuid;
608 } );
609
610 if( !found )
611 {
612 wxLogTrace( traceLibFieldTable, "Re-adding symbol '%s' to list after sync",
613 symbol->GetName() );
614 m_symbolsList.push_back( symbol );
615 }
616 }
617 }
618
619 wxLogTrace( traceLibFieldTable, "Dialog symbol list size after processing: %zu",
620 m_symbolsList.size() );
621 } );
622
623 ClearModify();
624 m_dataModel->RebuildRows();
625 RestoreGridSelection( savedSelection );
626 m_parent->RefreshLibraryTree();
627
628 if( updateCanvas )
629 {
630 m_parent->OnModify();
631 m_parent->HardRedraw();
632 }
633
634 return true;
635}
636
637
639{
640 auto addMandatoryField =
641 [&]( FIELD_T aFieldId, bool aShow, bool aGroupBy )
642 {
643 m_mandatoryFieldListIndexes[aFieldId] = m_viewControlsDataModel->GetNumberRows();
644
646 aShow, aGroupBy );
647 };
648
649 AddField( LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_NAME, _( "Symbol Name" ), true, false );
650 AddField( LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_PARENT, _( "Parent Symbol" ), false, false );
651 AddField( LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_ROOT, _( "Root Symbol" ), false, false );
652
653 // Add mandatory fields first show groupBy
654 addMandatoryField( FIELD_T::REFERENCE, false, false );
655 addMandatoryField( FIELD_T::VALUE, true, false );
656 addMandatoryField( FIELD_T::FOOTPRINT, true, false );
657 addMandatoryField( FIELD_T::DATASHEET, true, false );
658 addMandatoryField( FIELD_T::DESCRIPTION, false, false );
659
660 // Generated fields present only in the fields table
662 AddField( wxS( "${EXCLUDE_FROM_BOM}" ), _( "Exclude From BOM" ), true, false );
663 AddField( wxS( "${EXCLUDE_FROM_SIM}" ), _( "Exclude From Simulation" ), true, false );
664 AddField( wxS( "${EXCLUDE_FROM_BOARD}" ), _( "Exclude From Board" ), true, false );
665 AddField( wxS( "${EXCLUDE_FROM_POS_FILES}" ), _( "Exclude From Position Files" ), true, false );
666 AddField( LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_IS_POWER, _( "Power Symbol" ), true, false );
667 AddField( LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_IS_LOCAL_POWER, _( "Local Power Symbol" ), true, false );
668
669 // User field names are stored and matched case-sensitively (see issue #24021), so each
670 // distinct name gets its own column rather than collapsing case variants together.
671 std::set<wxString> userFieldNames;
672
673 for( LIB_SYMBOL* symbol : m_symbolsList )
674 {
675 std::vector<SCH_FIELD*> fields;
676 symbol->GetFields( fields );
677
678 for( SCH_FIELD* field : fields )
679 {
680 if( !field->IsMandatory() && !field->IsPrivate() )
681 userFieldNames.insert( field->GetName() );
682 }
683 }
684
685 for( const wxString& fieldName : userFieldNames )
686 AddField( fieldName, GetGeneratedFieldDisplayName( fieldName ), true, false );
687
688 // Add any global template field names which aren't already present.
689 for( const TEMPLATE_FIELDNAME& templateField :
690 Pgm().GetCommonSettings()->m_FieldNameTemplates.GetTemplateFieldNames(
691 TEMPLATES::SCOPE::GLOBAL ) )
692 {
693 if( userFieldNames.count( templateField.m_Name ) == 0 )
694 AddField( templateField.m_Name, GetGeneratedFieldDisplayName( templateField.m_Name ), false, false );
695 }
696}
697
698
700{
701 m_dataModel->SetScope( aScope );
702 m_dataModel->RebuildRows();
703}
704
705
706void DIALOG_LIB_FIELDS_TABLE::OnScope( wxCommandEvent& aEvent )
707{
708 switch( aEvent.GetSelection() )
709 {
710 case 0: setScope( SCOPE::SCOPE_LIBRARY ); break;
711 case 1: setScope( SCOPE::SCOPE_RELATED_SYMBOLS ); break;
712 }
713}
714
715
716void DIALOG_LIB_FIELDS_TABLE::OnMenu( wxCommandEvent& aEvent )
717{
718 // Build a pop menu:
719 wxMenu menu;
720
721 menu.Append( MYID_INCLUDE_DNP, _( "Include 'DNP' Symbols" ),
722 _( "Show symbols marked 'DNP' in the table. This setting also controls whether or not 'DNP' "
723 "symbols are included on export." ),
724 wxITEM_CHECK );
725 menu.Check( MYID_INCLUDE_DNP, !m_dataModel->GetExcludeDNP() );
726
727 menu.Append( MYID_INCLUDE_EXCLUDED_FROM_BOM, _( "Include 'Exclude from BOM' Symbols" ),
728 _( "Show symbols marked 'Exclude from BOM' in the table. Symbols marked 'Exclude from BOM' "
729 "are never included on export." ),
730 wxITEM_CHECK );
731 menu.Check( MYID_INCLUDE_EXCLUDED_FROM_BOM, m_dataModel->GetIncludeExcludedFromBOM() );
732
733 // menuId is the selected submenu id from the popup menu or wxID_NONE
734 int menuId = m_bMenu->GetPopupMenuSelectionFromUser( menu );
735
736 if( menuId == 0 || menuId == MYID_INCLUDE_DNP )
737 {
738 m_dataModel->SetExcludeDNP( !m_dataModel->GetExcludeDNP() );
739 m_dataModel->RebuildRows();
740 m_grid->ForceRefresh();
741
743 }
744 else if( menuId == 1 || menuId == MYID_INCLUDE_EXCLUDED_FROM_BOM )
745 {
746 m_dataModel->SetIncludeExcludedFromBOM( !m_dataModel->GetIncludeExcludedFromBOM() );
747 m_dataModel->RebuildRows();
748 m_grid->ForceRefresh();
749
751 }
752}
753
754
755void DIALOG_LIB_FIELDS_TABLE::OnSaveAndContinue( wxCommandEvent& aEvent )
756{
758 {
759 m_cfgBomSettings.m_BomExportFileName = m_outputFileName->GetValue();
760 ClearModify();
761 }
762}
763
764
765void DIALOG_LIB_FIELDS_TABLE::OnCancel( wxCommandEvent& aEvent )
766{
767 m_grid->CommitPendingChanges( true );
768
769 if( m_dataModel->IsEdited() )
770 {
771 if( !HandleUnsavedChanges( this, _( "Save changes?" ),
772 [&]() -> bool
773 {
774 return TransferDataFromWindow();
775 } ) )
776 {
777 return;
778 }
779 }
780
781 EndModal( wxID_CANCEL );
782}
783
784
785void DIALOG_LIB_FIELDS_TABLE::OnOk( wxCommandEvent& aEvent )
786{
788 return;
789
790 m_cfgBomSettings.m_BomExportFileName = m_outputFileName->GetValue();
791 EndModal( wxID_OK );
792}
793
794
795void DIALOG_LIB_FIELDS_TABLE::OnClose( wxCloseEvent& aEvent )
796{
797 m_grid->CommitPendingChanges( true );
798
799 if( m_dataModel->IsEdited() && aEvent.CanVeto() )
800 {
801 if( !HandleUnsavedChanges( this, _( "Save changes?" ),
802 [&]() -> bool
803 {
804 return TransferDataFromWindow();
805 } ) )
806 {
807 aEvent.Veto();
808 return;
809 }
810 }
811
812 aEvent.Skip();
813}
814
815
817{
818 std::vector<BOM_PRESET> presets = BOM_PRESET::BuiltInPresets();
819
820 for( BOM_PRESET& preset : presets )
821 {
822 if( preset.sortField == GetDefaultFieldName( FIELD_T::REFERENCE, TRANSLATED ) )
824
825 for( BOM_FIELD& field : preset.fieldsOrdered )
826 {
828 {
830 field.label = wxS( "Symbol Name" );
831 field.groupBy = false;
832 }
833 }
834
835 if( preset.name == BOM_PRESET::DefaultEditing().name )
836 {
837 preset.groupSymbols = false;
838 preset.fieldsOrdered = {
839 { LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_NAME, wxS( "Symbol Name" ), true, false },
840 { LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_PARENT, wxS( "Parent Symbol" ), false, false },
841 { LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_ROOT, wxS( "Root Symbol" ), false, false },
842 { GetDefaultFieldName( FIELD_T::REFERENCE, UNTRANSLATED ), wxS( "Reference" ), false, false },
843 { GetDefaultFieldName( FIELD_T::VALUE, UNTRANSLATED ), wxS( "Value" ), true, false },
844 { GetDefaultFieldName( FIELD_T::FOOTPRINT, UNTRANSLATED ), wxS( "Footprint" ), true, false },
845 { GetDefaultFieldName( FIELD_T::DATASHEET, UNTRANSLATED ), wxS( "Datasheet" ), true, false },
846 { GetDefaultFieldName( FIELD_T::DESCRIPTION, UNTRANSLATED ), wxS( "Description" ), false, false },
847 { LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_KEYWORDS, wxS( "Keywords" ), true, false },
848 { wxS( "${EXCLUDE_FROM_BOM}" ), wxS( "Exclude From BOM" ), true, false },
849 { wxS( "${EXCLUDE_FROM_SIM}" ), wxS( "Exclude From Simulation" ), true, false },
850 { wxS( "${EXCLUDE_FROM_BOARD}" ), wxS( "Exclude From Board" ), true, false },
851 { wxS( "${EXCLUDE_FROM_POS_FILES}" ), wxS( "Exclude From Position Files" ), true, false },
852 { LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_IS_POWER, wxS( "Power Symbol" ), true, false },
853 { LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_IS_LOCAL_POWER, wxS( "Local Power Symbol" ), true, false },
854 };
855 }
856 }
857
858 return presets;
859}
860
861
863{
864 return wxEmptyString;
865}
866
867
868bool DIALOG_LIB_FIELDS_TABLE::resolveTextVar( wxString* aToken ) const
869{
870 return Prj().TextVarResolver( aToken );
871}
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:114
const wxString GetLibraryName() const
wxString GetName() const override
Definition lib_symbol.h:183
wxString GetLibNickname() const override
Definition lib_symbol.h:196
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.