From dc103b88d14cea1c49a1c265a03ea3c5d3eb6f00 Mon Sep 17 00:00:00 2001 From: Mike Williams Date: Mon, 14 Aug 2023 10:41:28 -0400 Subject: [PATCH] Symbol Fields Table: make non-modal Fixes: https://gitlab.com/kicad/code/kicad/-/issues/2141 --- .../dialogs/dialog_symbol_fields_table.cpp | 133 +++++++++++++++--- eeschema/dialogs/dialog_symbol_fields_table.h | 10 +- eeschema/fields_data_model.cpp | 48 +++++++ eeschema/fields_data_model.h | 7 + eeschema/sch_edit_frame.cpp | 37 +++++ eeschema/sch_edit_frame.h | 7 + eeschema/tools/sch_editor_control.cpp | 12 +- 7 files changed, 230 insertions(+), 24 deletions(-) diff --git a/eeschema/dialogs/dialog_symbol_fields_table.cpp b/eeschema/dialogs/dialog_symbol_fields_table.cpp index 5813801b2e..71746c9868 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table.cpp +++ b/eeschema/dialogs/dialog_symbol_fields_table.cpp @@ -54,6 +54,8 @@ #include #include "eda_list_dialog.h" +wxDEFINE_EVENT( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, wxCommandEvent ); + #ifdef __WXMAC__ #define COLUMN_MARGIN 5 #else @@ -298,6 +300,9 @@ DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent ) m_cbBomFmtPresets->Bind( wxEVT_CHOICE, &DIALOG_SYMBOL_FIELDS_TABLE::onBomFmtPresetChanged, this ); m_fieldsCtrl->Bind( wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &DIALOG_SYMBOL_FIELDS_TABLE::OnColLabelChange, this ); + + // Start listening for schematic changes + m_parent->Schematic().AddListener( this ); } @@ -415,26 +420,6 @@ void DIALOG_SYMBOL_FIELDS_TABLE::SetupAllColumnProperties() DIALOG_SYMBOL_FIELDS_TABLE::~DIALOG_SYMBOL_FIELDS_TABLE() { - savePresetsToSchematic(); - EESCHEMA_SETTINGS* cfg = m_parent->eeconfig(); - - cfg->m_FieldEditorPanel.width = GetSize().x; - cfg->m_FieldEditorPanel.height = GetSize().y; - cfg->m_FieldEditorPanel.page = m_nbPages->GetSelection(); - cfg->m_FieldEditorPanel.export_filename = m_outputFileName->GetValue(); - cfg->m_FieldEditorPanel.selection_mode = m_radioSelect->GetSelection(); - cfg->m_FieldEditorPanel.scope = m_radioScope->GetSelection(); - - - for( int i = 0; i < m_grid->GetNumberCols(); i++ ) - { - if( m_grid->IsColShown( i ) ) - { - std::string fieldName( m_dataModel->GetColFieldName( i ).ToUTF8() ); - cfg->m_FieldEditorPanel.field_widths[fieldName] = m_grid->GetColSize( i ); - } - } - // Disconnect Events m_grid->Disconnect( wxEVT_GRID_COL_SORT, wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColSort ), nullptr, @@ -1250,7 +1235,37 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnClose( wxCloseEvent& event ) } } - event.Skip(); + // Stop listening to schematic events + m_parent->Schematic().RemoveListener( this ); + + // Save all our settings since we're really closing + savePresetsToSchematic(); + EESCHEMA_SETTINGS* cfg = m_parent->eeconfig(); + + cfg->m_FieldEditorPanel.width = GetSize().x; + cfg->m_FieldEditorPanel.height = GetSize().y; + cfg->m_FieldEditorPanel.page = m_nbPages->GetSelection(); + cfg->m_FieldEditorPanel.export_filename = m_outputFileName->GetValue(); + cfg->m_FieldEditorPanel.selection_mode = m_radioSelect->GetSelection(); + cfg->m_FieldEditorPanel.scope = m_radioScope->GetSelection(); + + for( int i = 0; i < m_grid->GetNumberCols(); i++ ) + { + if( m_grid->IsColShown( i ) ) + { + std::string fieldName( m_dataModel->GetColFieldName( i ).ToUTF8() ); + cfg->m_FieldEditorPanel.field_widths[fieldName] = m_grid->GetColSize( i ); + } + } + + m_parent->FocusOnItem( nullptr ); + + wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, wxID_ANY ); + + wxWindow* parent = GetParent(); + + if( parent ) + wxQueueEvent( parent, evt ); } @@ -2004,3 +2019,79 @@ void DIALOG_SYMBOL_FIELDS_TABLE::savePresetsToSchematic() m_schSettings.m_BomFmtPresets = fmts; m_schSettings.m_BomFmtSettings = GetCurrentBomFmtSettings(); } + + +void DIALOG_SYMBOL_FIELDS_TABLE::OnSchItemsAdded( SCHEMATIC& aSch, + std::vector& aSchItem ) +{ + for( SCH_ITEM* item : aSchItem ) + { + if( item->Type() == SCH_SYMBOL_T ) + { + SCH_SYMBOL* symbol = static_cast( item ); + + // Add all fields again in case this symbol has a new one + for( SCH_FIELD& field : symbol->GetFields() ) + AddField( field.GetCanonicalName(), field.GetName(), true, false, true ); + + m_dataModel->AddReferences( *symbol, getSymbolReferences( symbol ) ); + } + } + + m_dataModel->RebuildRows(); +} + + +void DIALOG_SYMBOL_FIELDS_TABLE::OnSchItemsRemoved( SCHEMATIC& aSch, + std::vector& aSchItem ) +{ + for( SCH_ITEM* item : aSchItem ) + if( item->Type() == SCH_SYMBOL_T ) + m_dataModel->RemoveSymbol( *static_cast( item ) ); + + m_dataModel->RebuildRows(); +} + + +void DIALOG_SYMBOL_FIELDS_TABLE::OnSchItemsChanged( SCHEMATIC& aSch, + std::vector& aSchItem ) +{ + for( SCH_ITEM* item : aSchItem ) + { + if( item->Type() == SCH_SYMBOL_T ) + { + SCH_SYMBOL* symbol = static_cast( item ); + + // Add all fields again in case this symbol has a new one + for( SCH_FIELD& field : symbol->GetFields() ) + AddField( field.GetCanonicalName(), field.GetName(), true, false, true ); + + m_dataModel->UpdateReferences( *symbol, getSymbolReferences( symbol ) ); + } + } + + m_dataModel->RebuildRows(); +} + + +SCH_REFERENCE_LIST DIALOG_SYMBOL_FIELDS_TABLE::getSymbolReferences( SCH_SYMBOL* aSymbol ) +{ + SCH_SHEET_LIST sheets = m_parent->Schematic().GetSheets(); + SCH_REFERENCE_LIST allRefs; + SCH_REFERENCE_LIST symbolRefs; + + sheets.GetSymbols( allRefs ); + + for( size_t i = 0; i < allRefs.GetCount(); i++ ) + { + SCH_REFERENCE& ref = allRefs[i]; + + if( ref.GetSymbol() == aSymbol ) + { + ref.Split(); // Figures out if we are annotated or not + symbolRefs.AddItem( ref ); + } + } + + return symbolRefs; +} diff --git a/eeschema/dialogs/dialog_symbol_fields_table.h b/eeschema/dialogs/dialog_symbol_fields_table.h index b142606992..30174b1850 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table.h +++ b/eeschema/dialogs/dialog_symbol_fields_table.h @@ -28,7 +28,9 @@ #include #include +#include +wxDECLARE_EVENT( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, wxCommandEvent ); class SCHEMATIC_SETTINGS; struct BOM_PRESET; @@ -37,7 +39,7 @@ class SCH_EDIT_FRAME; class FIELDS_EDITOR_GRID_DATA_MODEL; -class DIALOG_SYMBOL_FIELDS_TABLE : public DIALOG_SYMBOL_FIELDS_TABLE_BASE +class DIALOG_SYMBOL_FIELDS_TABLE : public DIALOG_SYMBOL_FIELDS_TABLE_BASE, public SCHEMATIC_LISTENER { public: DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent ); @@ -103,7 +105,13 @@ private: void ApplyBomFmtPreset( const wxString& aPresetName ); void ApplyBomFmtPreset( const BOM_FMT_PRESET& aPreset ); + void OnSchItemsAdded( SCHEMATIC& aSch, std::vector& aSchItem ) override; + void OnSchItemsRemoved( SCHEMATIC& aSch, std::vector& aSchItem ) override; + void OnSchItemsChanged( SCHEMATIC& aSch, std::vector& aSchItem ) override; + private: + SCH_REFERENCE_LIST getSymbolReferences( SCH_SYMBOL* aSymbol ); + void syncBomPresetSelection(); void rebuildBomPresetsWidget(); void updateBomPresetSelection( const wxString& aName ); diff --git a/eeschema/fields_data_model.cpp b/eeschema/fields_data_model.cpp index cacc4dab14..dcb6be90bf 100644 --- a/eeschema/fields_data_model.cpp +++ b/eeschema/fields_data_model.cpp @@ -880,3 +880,51 @@ wxString FIELDS_EDITOR_GRID_DATA_MODEL::Export( const BOM_FMT_PRESET& settings ) return out; } + + +void FIELDS_EDITOR_GRID_DATA_MODEL::AddReferences( const SCH_SYMBOL& aSymbol, + const SCH_REFERENCE_LIST& aRefs ) +{ + // Update the fields of every reference + for( const SCH_FIELD& field : aSymbol.GetFields() ) + m_dataStore[aSymbol.m_Uuid][field.GetCanonicalName()] = field.GetText(); + + for( const SCH_REFERENCE& ref : aRefs ) + if( !m_symbolsList.Contains( ref ) ) + m_symbolsList.AddItem( ref ); +} + + +void FIELDS_EDITOR_GRID_DATA_MODEL::RemoveSymbol( const SCH_SYMBOL& aSymbol ) +{ + // The schematic event listener passes us the item after it has been removed, + // so we can't just work with a SCH_REFERENCE_LIST like the other handlers as the + // references are already gone. Instead we need to prune our list. + m_dataStore[aSymbol.m_Uuid].clear(); + + // Remove all refs that match this symbol using remove_if + m_symbolsList.erase( std::remove_if( m_symbolsList.begin(), m_symbolsList.end(), + [aSymbol]( const SCH_REFERENCE& ref ) -> bool + { + return ref.GetSymbol()->m_Uuid == aSymbol.m_Uuid; + } ), + m_symbolsList.end() ); +} + + +void FIELDS_EDITOR_GRID_DATA_MODEL::UpdateReferences( const SCH_SYMBOL& aSymbol, + const SCH_REFERENCE_LIST& aRefs ) +{ + wxCHECK_RET( m_dataStore.count( aSymbol.m_Uuid ) == 1, + "Trying to update a symbol that doesn't exist" ); + + // Update the fields of every reference. Do this by iterating through the data model + // colums; we must have all fields in the symbol added to the data model at this point, + // and some of the data model columns may be variables that are not present in the symbol + for( const DATA_MODEL_COL& col : m_cols ) + updateDataStoreSymbolField( aSymbol, col.m_fieldName ); + + for( const SCH_REFERENCE& ref : aRefs ) + if( !m_symbolsList.Contains( ref ) ) + m_symbolsList.AddItem( ref ); +} diff --git a/eeschema/fields_data_model.h b/eeschema/fields_data_model.h index 1114d1351f..397ccddcb5 100644 --- a/eeschema/fields_data_model.h +++ b/eeschema/fields_data_model.h @@ -210,6 +210,11 @@ public: BOM_PRESET GetBomSettings(); wxString Export( const BOM_FMT_PRESET& settings ); + void AddReferences( const SCH_SYMBOL& aSymbol, const SCH_REFERENCE_LIST& aRefs ); + void RemoveSymbol( const SCH_SYMBOL& aSymbol ); + void UpdateReferences( const SCH_SYMBOL& aSymbol, const SCH_REFERENCE_LIST& aRefs ); + + private: static bool cmp( const DATA_MODEL_ROW& lhGroup, const DATA_MODEL_ROW& rhGroup, FIELDS_EDITOR_GRID_DATA_MODEL* dataModel, int sortCol, bool ascending ); @@ -231,6 +236,8 @@ private: void Sort(); + SCH_REFERENCE_LIST getSymbolReferences( SCH_SYMBOL* aSymbol ); + void storeReferenceFields( SCH_REFERENCE& aRef ); void updateDataStoreSymbolField( const SCH_SYMBOL& aSymbol, const wxString& aFieldName ); diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index 96b35f29c0..91de3ed983 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -125,6 +126,7 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, SCH_EDIT_FRAME_NAME ), m_ercDialog( nullptr ), m_diffSymbolDialog( nullptr ), + m_symbolFieldsTableDialog( nullptr ), m_netNavigator( nullptr ), m_highlightedConnChanged( false ) { @@ -378,6 +380,8 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : Bind( EDA_EVT_CLOSE_DIALOG_BOOK_REPORTER, &SCH_EDIT_FRAME::onCloseSymbolDiffDialog, this ); Bind( EDA_EVT_CLOSE_ERC_DIALOG, &SCH_EDIT_FRAME::onCloseErcDialog, this ); + Bind( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, &SCH_EDIT_FRAME::onCloseSymbolFieldsTableDialog, + this ); } @@ -918,6 +922,12 @@ bool SCH_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent ) if( !Kiway().PlayerClose( FRAME_SIMULATOR, false ) ) // Can close the simulator? return false; + if( m_symbolFieldsTableDialog + && !m_symbolFieldsTableDialog->Close( false ) ) // Can close the symbol fields table? + { + return false; + } + // We may have gotten multiple events; don't clean up twice if( !Schematic().IsValid() ) return false; @@ -954,6 +964,8 @@ void SCH_EDIT_FRAME::doCloseWindow() // Close modeless dialogs. They're trouble when they get destroyed after the frame. Unbind( EDA_EVT_CLOSE_DIALOG_BOOK_REPORTER, &SCH_EDIT_FRAME::onCloseSymbolDiffDialog, this ); Unbind( EDA_EVT_CLOSE_ERC_DIALOG, &SCH_EDIT_FRAME::onCloseErcDialog, this ); + Unbind( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, + &SCH_EDIT_FRAME::onCloseSymbolFieldsTableDialog, this ); m_netNavigator->Unbind( wxEVT_TREE_SEL_CHANGING, &SCH_EDIT_FRAME::onNetNavigatorSelChanging, this ); m_netNavigator->Unbind( wxEVT_TREE_SEL_CHANGED, &SCH_EDIT_FRAME::onNetNavigatorSelection, @@ -981,6 +993,12 @@ void SCH_EDIT_FRAME::doCloseWindow() m_ercDialog = nullptr; } + if( m_symbolFieldsTableDialog ) + { + m_symbolFieldsTableDialog->Destroy(); + m_symbolFieldsTableDialog = nullptr; + } + // Shutdown all running tools if( m_toolManager ) { @@ -2215,6 +2233,25 @@ void SCH_EDIT_FRAME::onCloseErcDialog( wxCommandEvent& aEvent ) } +DIALOG_SYMBOL_FIELDS_TABLE* SCH_EDIT_FRAME::GetSymbolFieldsTableDialog() +{ + if( !m_symbolFieldsTableDialog ) + m_symbolFieldsTableDialog = new DIALOG_SYMBOL_FIELDS_TABLE( this ); + + return m_symbolFieldsTableDialog; +} + + +void SCH_EDIT_FRAME::onCloseSymbolFieldsTableDialog( wxCommandEvent& aEvent ) +{ + if( m_symbolFieldsTableDialog ) + { + m_symbolFieldsTableDialog->Destroy(); + m_symbolFieldsTableDialog = nullptr; + } +} + + void SCH_EDIT_FRAME::AddSchematicChangeListener( wxEvtHandler* aListener ) { auto it = std::find( m_schematicChangeListeners.begin(), m_schematicChangeListeners.end(), diff --git a/eeschema/sch_edit_frame.h b/eeschema/sch_edit_frame.h index 467f2048a2..3b8cf0c53e 100644 --- a/eeschema/sch_edit_frame.h +++ b/eeschema/sch_edit_frame.h @@ -58,6 +58,7 @@ class SCHEMATIC; class SCH_COMMIT; class DIALOG_BOOK_REPORTER; class DIALOG_ERC; +class DIALOG_SYMBOL_FIELDS_TABLE; class DIALOG_SCH_FIND; class RESCUER; class HIERARCHY_PANE; @@ -824,6 +825,8 @@ public: DIALOG_ERC* GetErcDialog(); + DIALOG_SYMBOL_FIELDS_TABLE* GetSymbolFieldsTableDialog(); + wxTreeCtrl* GetNetNavigator() { return m_netNavigator; } const SCH_ITEM* GetSelectedNetNavigatorItem() const; @@ -896,6 +899,8 @@ protected: void onCloseErcDialog( wxCommandEvent& aEvent ); + void onCloseSymbolFieldsTableDialog( wxCommandEvent& aEvent ); + void unitsChangeRefresh() override; private: @@ -998,6 +1003,8 @@ private: DIALOG_ERC* m_ercDialog; DIALOG_BOOK_REPORTER* m_diffSymbolDialog; HIERARCHY_PANE* m_hierarchy; + DIALOG_SYMBOL_FIELDS_TABLE* m_symbolFieldsTableDialog; + wxTreeCtrl* m_netNavigator; diff --git a/eeschema/tools/sch_editor_control.cpp b/eeschema/tools/sch_editor_control.cpp index 4df9056c33..0e2e442005 100644 --- a/eeschema/tools/sch_editor_control.cpp +++ b/eeschema/tools/sch_editor_control.cpp @@ -2052,8 +2052,16 @@ int SCH_EDITOR_CONTROL::ShowCvpcb( const TOOL_EVENT& aEvent ) int SCH_EDITOR_CONTROL::EditSymbolFields( const TOOL_EVENT& aEvent ) { - DIALOG_SYMBOL_FIELDS_TABLE dlg( m_frame ); - dlg.ShowQuasiModal(); + DIALOG_SYMBOL_FIELDS_TABLE* dlg = m_frame->GetSymbolFieldsTableDialog(); + + wxCHECK( dlg, 0 ); + + // Needed at least on Windows. Raise() is not enough + dlg->Show( true ); + + // Bring it to the top if already open. Dual monitor users need this. + dlg->Raise(); + return 0; }