diff --git a/eeschema/cmp_tree_model.cpp b/eeschema/cmp_tree_model.cpp index 3329512164..75b2b973cd 100644 --- a/eeschema/cmp_tree_model.cpp +++ b/eeschema/cmp_tree_model.cpp @@ -105,7 +105,6 @@ int CMP_TREE_NODE::Compare( CMP_TREE_NODE const& aNode1, CMP_TREE_NODE const& aN CMP_TREE_NODE::CMP_TREE_NODE() : Parent( nullptr ), Type( INVALID ), - InTree( false ), IntrinsicRank( 0 ), Score( kLowestDefaultScore ), Unit( 0 ) @@ -178,7 +177,6 @@ CMP_TREE_NODE_LIB_ID::CMP_TREE_NODE_LIB_ID( CMP_TREE_NODE* aParent, LIB_ALIAS* a CMP_TREE_NODE_UNIT& CMP_TREE_NODE_LIB_ID::AddUnit( int aUnit ) { CMP_TREE_NODE_UNIT* unit = new CMP_TREE_NODE_UNIT( this, aUnit ); - unit->InTree = true; Children.push_back( std::unique_ptr( unit ) ); return *unit; } @@ -245,7 +243,6 @@ CMP_TREE_NODE_LIB::CMP_TREE_NODE_LIB( CMP_TREE_NODE* aParent, wxString const& aN CMP_TREE_NODE_LIB_ID& CMP_TREE_NODE_LIB::AddAlias( LIB_ALIAS* aAlias ) { CMP_TREE_NODE_LIB_ID* alias = new CMP_TREE_NODE_LIB_ID( this, aAlias ); - alias->InTree = true; Children.push_back( std::unique_ptr( alias ) ); return *alias; } @@ -272,7 +269,6 @@ CMP_TREE_NODE_ROOT::CMP_TREE_NODE_ROOT() CMP_TREE_NODE_LIB& CMP_TREE_NODE_ROOT::AddLib( wxString const& aName ) { CMP_TREE_NODE_LIB* lib = new CMP_TREE_NODE_LIB( this, aName ); - lib->InTree = true; Children.push_back( std::unique_ptr( lib ) ); return *lib; } diff --git a/eeschema/cmp_tree_model.h b/eeschema/cmp_tree_model.h index 0460f8a1f8..ab062ee4a0 100644 --- a/eeschema/cmp_tree_model.h +++ b/eeschema/cmp_tree_model.h @@ -85,7 +85,6 @@ public: CMP_TREE_NODE* Parent; ///< Parent node or null PTR_VECTOR Children; ///< List of child nodes enum TYPE Type; ///< Node type - bool InTree; ///< Flag indicating whether the node is added to the tree /** * The rank of the item before any search terms are applied. This is diff --git a/eeschema/cmp_tree_model_adapter_base.cpp b/eeschema/cmp_tree_model_adapter_base.cpp index 9aef10ec70..53be1e4b8e 100644 --- a/eeschema/cmp_tree_model_adapter_base.cpp +++ b/eeschema/cmp_tree_model_adapter_base.cpp @@ -25,6 +25,7 @@ #include #include +#include CMP_TREE_MODEL_ADAPTER_BASE::WIDTH_CACHE CMP_TREE_MODEL_ADAPTER_BASE::m_width_cache; @@ -61,7 +62,7 @@ unsigned int CMP_TREE_MODEL_ADAPTER_BASE::IntoArray( for( auto const& child: aNode.Children ) { - if( child->Score > 0 && child->InTree ) + if( child->Score > 0 ) { aChildren.Add( ToItem( &*child ) ); ++n; @@ -144,7 +145,7 @@ void CMP_TREE_MODEL_ADAPTER_BASE::AddAliasList( void CMP_TREE_MODEL_ADAPTER_BASE::UpdateSearchString( wxString const& aSearch ) { - m_widget->Freeze(); + wxWindowUpdateLocker updateLock( m_widget ); m_tree.ResetScore(); wxStringTokenizer tokenizer( aSearch ); @@ -157,16 +158,23 @@ void CMP_TREE_MODEL_ADAPTER_BASE::UpdateSearchString( wxString const& aSearch ) m_tree.UpdateScore( matcher ); } - filterContents(); + m_tree.SortNodes(); + Cleared(); +#ifndef __WINDOWS__ + // The fastest method to update wxDataViewCtrl is to rebuild from scratch by calling Cleared(). + // Linux requires to reassociate model to display data, but Windows will create multiple + // associations. + AttachTo( m_widget ); +#endif + ShowResults() || ShowPreselect() || ShowSingleLibrary(); - m_widget->Thaw(); } void CMP_TREE_MODEL_ADAPTER_BASE::AttachTo( wxDataViewCtrl* aDataViewCtrl ) { + wxWindowUpdateLocker updateLock( aDataViewCtrl ); m_widget = aDataViewCtrl; - aDataViewCtrl->Freeze(); aDataViewCtrl->SetIndent( kDataViewIndent ); aDataViewCtrl->AssociateModel( this ); aDataViewCtrl->ClearColumns(); @@ -179,7 +187,6 @@ void CMP_TREE_MODEL_ADAPTER_BASE::AttachTo( wxDataViewCtrl* aDataViewCtrl ) m_col_desc = aDataViewCtrl->AppendTextColumn( desc_head, 1, wxDATAVIEW_CELL_INERT, ColWidth( m_tree, 1, desc_head ) ); m_col_part->SetSortOrder( 0 ); - aDataViewCtrl->Thaw(); } @@ -464,53 +471,3 @@ bool CMP_TREE_MODEL_ADAPTER_BASE::ShowSingleLibrary() n->Parent->Parent->Children.size() == 1; } ); } - - -void CMP_TREE_MODEL_ADAPTER_BASE::filterContents() -{ - // Rebuild the tree using only the filtered nodes - for( auto& lib : m_tree.Children ) - { - lib->InTree = false; - - for( auto& alias : lib->Children ) - { - alias->InTree = false; - - for( auto& unit : lib->Children ) - unit->InTree = false; - } - } - - m_tree.SortNodes(); - Cleared(); - - for( auto& lib : m_tree.Children ) - { - if( lib->Score <= 0 ) - continue; - - wxDataViewItem libItem = ToItem( lib.get() ); - lib->InTree = true; - ItemAdded( wxDataViewItem( nullptr ), libItem ); - - for( auto& alias : lib->Children ) - { - if( alias->Score > 0 ) - { - alias->InTree = true; - wxDataViewItem aliasItem = ToItem( alias.get() ); - ItemAdded( libItem, aliasItem ); - - if( !m_show_units ) - continue; - - for( auto& unit : alias->Children ) - { - unit->InTree = true; - ItemAdded( aliasItem, ToItem( unit.get() ) ); - } - } - } - } -} diff --git a/eeschema/cmp_tree_model_adapter_base.h b/eeschema/cmp_tree_model_adapter_base.h index d7e6c04f9b..026be485c8 100644 --- a/eeschema/cmp_tree_model_adapter_base.h +++ b/eeschema/cmp_tree_model_adapter_base.h @@ -395,11 +395,6 @@ private: * Find and expand a library if there is only one */ bool ShowSingleLibrary(); - - /** - * Filters the items shown in the view according to the score. - */ - void filterContents(); }; #endif // _CMP_TREE_MODEL_ADAPTER_BASE_H diff --git a/eeschema/lib_manager.cpp b/eeschema/lib_manager.cpp index e5981c0023..9c5077c943 100644 --- a/eeschema/lib_manager.cpp +++ b/eeschema/lib_manager.cpp @@ -358,7 +358,7 @@ bool LIB_MANAGER::UpdatePart( LIB_PART* aPart, const wxString& aLibrary, wxStrin screen->SetModify(); } - getAdapter()->UpdateLibrary( aLibrary ); + m_frame.SyncLibraries( false ); return true; } @@ -401,7 +401,7 @@ bool LIB_MANAGER::RevertLibrary( const wxString& aLibrary ) return false; m_libs.erase( it ); - getAdapter()->UpdateLibrary( aLibrary ); + m_frame.SyncLibraries( false ); return true; } @@ -414,7 +414,7 @@ bool LIB_MANAGER::RemovePart( const wxString& aAlias, const wxString& aLibrary ) wxCHECK( partBuf, false ); bool res = libBuf.DeleteBuffer( partBuf ); - getAdapter()->UpdateLibrary( aLibrary ); + m_frame.SyncLibraries( false ); return res; } @@ -549,7 +549,7 @@ bool LIB_MANAGER::addLibrary( const wxString& aFilePath, bool aCreate, SYMBOL_LI aTable->CreateSymbolLib( libName ); } - getAdapter()->AddLibrary( libName ); + m_frame.SyncLibraries( false ); return true; } diff --git a/eeschema/lib_manager_adapter.cpp b/eeschema/lib_manager_adapter.cpp index 10d819706e..4507a48dc6 100644 --- a/eeschema/lib_manager_adapter.cpp +++ b/eeschema/lib_manager_adapter.cpp @@ -37,32 +37,6 @@ CMP_TREE_MODEL_ADAPTER_BASE::PTR LIB_MANAGER_ADAPTER::Create( LIB_MANAGER* aLibM void LIB_MANAGER_ADAPTER::AddLibrary( const wxString& aLibNickname ) { - auto& lib_node = m_tree.AddLib( aLibNickname ); - ItemAdded( wxDataViewItem( nullptr ), ToItem( &lib_node ) ); - updateLibrary( lib_node ); - finishUpdate(); -} - - -void LIB_MANAGER_ADAPTER::RemoveLibrary( const wxString& aLibNickname ) -{ - auto it = std::find_if( m_tree.Children.begin(), m_tree.Children.end(), - [&] ( std::unique_ptr& node ) { return node->Name == aLibNickname; } ); - - if( it != m_tree.Children.end() ) - deleteLibrary( it ); -} - - -void LIB_MANAGER_ADAPTER::UpdateLibrary( const wxString& aLibraryName ) -{ - CMP_TREE_NODE* node = findLibrary( aLibraryName ); - - if( !node ) - return; - - updateLibrary( *(CMP_TREE_NODE_LIB*) node ); - finishUpdate(); } @@ -115,7 +89,9 @@ void LIB_MANAGER_ADAPTER::Sync( bool aForce, std::functionGetAliases( aLibNode.Name ) ) - { - auto& aliasNode = aLibNode.AddAlias( alias ); - ItemAdded( parent, ToItem( &aliasNode ) ); - } + aLibNode.AddAlias( alias ); } else { // update an existing libary std::list aliases = m_libMgr->GetAliases( aLibNode.Name ); - wxDataViewItem parent = ToItem( &aLibNode ); // remove the common part from the aliases list - //for( const auto& node : aLibNode.Children ) for( auto nodeIt = aLibNode.Children.begin(); nodeIt != aLibNode.Children.end(); /**/ ) { auto aliasIt = std::find_if( aliases.begin(), aliases.end(), @@ -173,17 +142,13 @@ void LIB_MANAGER_ADAPTER::updateLibrary( CMP_TREE_NODE_LIB& aLibNode ) else { // node does not exist in the library manager, remove the corresponding node - ItemDeleted( parent, ToItem( nodeIt->get() ) ); nodeIt = aLibNode.Children.erase( nodeIt ); } } // now the aliases list contains only new aliases that need to be added to the tree for( auto alias : aliases ) - { - auto& aliasNode = aLibNode.AddAlias( alias ); - ItemAdded( parent, ToItem( &aliasNode ) ); - } + aLibNode.AddAlias( alias ); } aLibNode.AssignIntrinsicRanks(); @@ -195,19 +160,12 @@ CMP_TREE_NODE::PTR_VECTOR::iterator LIB_MANAGER_ADAPTER::deleteLibrary( CMP_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt ) { CMP_TREE_NODE* node = aLibNodeIt->get(); - ItemDeleted( wxDataViewItem( nullptr ), ToItem( node ) ); m_libHashes.erase( node->Name ); auto it = m_tree.Children.erase( aLibNodeIt ); return it; } -void LIB_MANAGER_ADAPTER::finishUpdate() -{ - m_tree.AssignIntrinsicRanks(); -} - - CMP_TREE_NODE* LIB_MANAGER_ADAPTER::findLibrary( const wxString& aLibNickName ) { for( auto& lib : m_tree.Children ) diff --git a/eeschema/lib_manager_adapter.h b/eeschema/lib_manager_adapter.h index c64cd5035e..c2ca1f875c 100644 --- a/eeschema/lib_manager_adapter.h +++ b/eeschema/lib_manager_adapter.h @@ -37,14 +37,10 @@ public: void AddLibrary( const wxString& aLibNickname ) override; - void RemoveLibrary( const wxString& aLibNickname ); - void AddAliasList( const wxString& aNodeName, const wxArrayString& aAliasNameList ) override; bool IsContainer( const wxDataViewItem& aItem ) const override; - void UpdateLibrary( const wxString& aLibraryName ); - void Sync( bool aForce = false, std::function aProgressCallback = [](int, int, const wxString&){} ); @@ -56,8 +52,6 @@ protected: CMP_TREE_NODE::PTR_VECTOR::iterator deleteLibrary( CMP_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt ); - void finishUpdate(); - CMP_TREE_NODE* findLibrary( const wxString& aLibNickName ); bool GetAttr( wxDataViewItem const& aItem, unsigned int aCol, diff --git a/eeschema/libeditframe.cpp b/eeschema/libeditframe.cpp index 809e5eb5b3..81da87cc19 100644 --- a/eeschema/libeditframe.cpp +++ b/eeschema/libeditframe.cpp @@ -253,7 +253,7 @@ LIB_EDIT_FRAME::LIB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : m_canvas->SetEnableBlockCommands( true ); m_libMgr = new LIB_MANAGER( *this ); - SyncLibraries(); + SyncLibraries( true ); m_treePane = new CMP_TREE_PANE( this, m_libMgr ); ReCreateMenuBar(); @@ -485,7 +485,7 @@ void LIB_EDIT_FRAME::OnToggleSearchTree( wxCommandEvent& event ) void LIB_EDIT_FRAME::OnEditSymbolLibTable( wxCommandEvent& aEvent ) { SCH_BASE_FRAME::OnEditSymbolLibTable( aEvent ); - SyncLibraries(); + SyncLibraries( true ); } @@ -1614,23 +1614,24 @@ wxString LIB_EDIT_FRAME::getTargetLib() const } -void LIB_EDIT_FRAME::SyncLibraries() +void LIB_EDIT_FRAME::SyncLibraries( bool aProgress ) { - auto tree = m_treePane ? m_treePane->GetCmpTree() : nullptr; - wxBusyCursor cursor; + if( aProgress ) + { + wxProgressDialog progressDlg( _( "Loading symbol libraries" ), + wxEmptyString, m_libMgr->GetAdapter()->GetLibrariesCount(), this ); - if( tree ) - tree->Freeze(); + m_libMgr->Sync( true, [&]( int progress, int max, const wxString& libName ) { + progressDlg.Update( progress, wxString::Format( _( "Loading library '%s'" ), libName ) ); + } ); + } + else + { + m_libMgr->Sync( true ); + } - wxProgressDialog progressDlg( _( "Loading symbol libraries" ), - wxEmptyString, m_libMgr->GetAdapter()->GetLibrariesCount(), this ); - - m_libMgr->Sync( true, [&]( int progress, int max, const wxString& libName ) { - progressDlg.Update( progress, wxString::Format( _( "Loading library '%s'" ), libName ) ); - } ); - - if( tree ) - tree->Thaw(); + if( m_treePane ) + m_treePane->Regenerate(); } diff --git a/eeschema/libeditframe.h b/eeschema/libeditframe.h index 094401b56e..5587f91582 100644 --- a/eeschema/libeditframe.h +++ b/eeschema/libeditframe.h @@ -689,7 +689,7 @@ public: /** * Synchronize the library manager and the symbol library table. Displays a progress dialog. */ - void SyncLibraries(); + void SyncLibraries( bool aLoad ); private: ///> Helper screen used when no part is loaded diff --git a/eeschema/widgets/cmp_tree_pane.cpp b/eeschema/widgets/cmp_tree_pane.cpp index 915aefaf67..e4b0e8d063 100644 --- a/eeschema/widgets/cmp_tree_pane.cpp +++ b/eeschema/widgets/cmp_tree_pane.cpp @@ -30,20 +30,18 @@ #include #include + CMP_TREE_PANE::CMP_TREE_PANE( LIB_EDIT_FRAME* aParent, LIB_MANAGER* aLibMgr ) : wxPanel( aParent ), - m_libEditFrame( aParent ), - m_libMgr( aLibMgr ) + m_libEditFrame( aParent ), m_tree( nullptr ), m_libMgr( aLibMgr ) { // Create widgets wxBoxSizer* boxSizer = new wxBoxSizer( wxVERTICAL ); - m_tree = new COMPONENT_TREE( this, &SYMBOL_LIB_TABLE::GetGlobalLibTable(), m_libMgr->GetAdapter(), COMPONENT_TREE::SEARCH ); - boxSizer->Add( m_tree, 1, wxEXPAND | wxALL, 5 ); - SetSizer( boxSizer ); + SetSizer( boxSizer ); // should remove the previous sizer according to wxWidgets docs Layout(); boxSizer->Fit( this ); @@ -87,7 +85,14 @@ CMP_TREE_PANE::CMP_TREE_PANE( LIB_EDIT_FRAME* aParent, LIB_MANAGER* aLibMgr ) CMP_TREE_PANE::~CMP_TREE_PANE() { - delete m_tree; + m_tree->Destroy(); +} + + +void CMP_TREE_PANE::Regenerate() +{ + if( m_tree ) + m_tree->Regenerate(); } diff --git a/eeschema/widgets/cmp_tree_pane.h b/eeschema/widgets/cmp_tree_pane.h index 8800e8a681..f93e425141 100644 --- a/eeschema/widgets/cmp_tree_pane.h +++ b/eeschema/widgets/cmp_tree_pane.h @@ -26,10 +26,13 @@ #define CMP_TREE_PANE_H #include +#include +#include class COMPONENT_TREE; class LIB_EDIT_FRAME; class LIB_MANAGER; +class wxBoxSizer; /** * Library Editor pane with component tree and symbol library table selector. @@ -45,6 +48,9 @@ public: return m_tree; } + ///> Updates the component tree + void Regenerate(); + protected: void onComponentSelected( wxCommandEvent& aEvent ); diff --git a/eeschema/widgets/component_tree.cpp b/eeschema/widgets/component_tree.cpp index 8b6724d077..c24559744b 100644 --- a/eeschema/widgets/component_tree.cpp +++ b/eeschema/widgets/component_tree.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -138,6 +139,25 @@ void COMPONENT_TREE::SelectLibId( const LIB_ID& aLibId ) } +void COMPONENT_TREE::Regenerate() +{ + STATE current; + + // Store the state + if( !m_filtering ) + m_unfilteredState = getState(); + else + current = getState(); + + m_adapter->UpdateSearchString( m_query_ctrl->GetLineText( 0 ) ); + m_filtering = !m_query_ctrl->IsEmpty(); + postPreselectEvent(); + + // Restore the state + setState( m_filtering ? current : m_unfilteredState ); +} + + void COMPONENT_TREE::selectIfValid( const wxDataViewItem& aTreeId ) { if( aTreeId.IsOk() ) @@ -163,25 +183,42 @@ void COMPONENT_TREE::postSelectEvent() } +COMPONENT_TREE::STATE COMPONENT_TREE::getState() const +{ + STATE state; + wxDataViewItemArray items; + m_adapter->GetChildren( wxDataViewItem( nullptr ), items ); + + for( const auto& item : items ) + { + if( m_tree_ctrl->IsExpanded( item ) ) + state.expanded.push_back( item ); + } + + state.selection = m_tree_ctrl->GetSelection(); + + return state; +} + + +void COMPONENT_TREE::setState( const STATE& aState ) +{ + wxWindowUpdateLocker updateLock( m_tree_ctrl ); + + for( const auto& item : aState.expanded ) + m_tree_ctrl->Expand( item ); + + if( aState.selection.IsOk() ) + { + m_tree_ctrl->ExpandAncestors( aState.selection ); + m_tree_ctrl->SetCurrentItem( aState.selection ); + } +} + + void COMPONENT_TREE::onQueryText( wxCommandEvent& aEvent ) { - // Store the state - if( !m_filtering ) - { - m_selection = m_tree_ctrl->GetSelection(); - saveExpandFlag(); - } - - m_adapter->UpdateSearchString( m_query_ctrl->GetLineText( 0 ) ); - m_filtering = !m_query_ctrl->IsEmpty(); - postPreselectEvent(); - - // Restore the state - if( !m_filtering ) - { - selectIfValid( m_selection ); - restoreExpandFlag(); - } + Regenerate(); // Required to avoid interaction with SetHint() // See documentation for wxTextEntry::SetHint @@ -276,32 +313,5 @@ void COMPONENT_TREE::onContextMenu( wxDataViewEvent& aEvent ) } -void COMPONENT_TREE::saveExpandFlag() -{ - wxDataViewItemArray items; - m_adapter->GetChildren( wxDataViewItem( nullptr ), items ); - m_expanded.clear(); - - for( const auto& item : items ) - { - if( m_tree_ctrl->IsExpanded( item ) ) - m_expanded.push_back( item ); - } -} - - -void COMPONENT_TREE::restoreExpandFlag() -{ - m_tree_ctrl->Freeze(); - - for( const auto& item : m_expanded ) - { - m_tree_ctrl->Expand( item ); - } - - m_tree_ctrl->Thaw(); -} - - wxDEFINE_EVENT( COMPONENT_PRESELECTED, wxCommandEvent ); wxDEFINE_EVENT( COMPONENT_SELECTED, wxCommandEvent ); diff --git a/eeschema/widgets/component_tree.h b/eeschema/widgets/component_tree.h index 0917e4f951..2593c3a40e 100644 --- a/eeschema/widgets/component_tree.h +++ b/eeschema/widgets/component_tree.h @@ -86,6 +86,11 @@ public: return m_menuActive; } + /** + * Regenerates the tree. + */ + void Regenerate(); + protected: /** * If a wxDataViewitem is valid, select it and post a selection event. @@ -103,6 +108,28 @@ protected: */ void postSelectEvent(); + /** + * Structure storing state of the component tree widget. + */ + struct STATE + { + ///> List of expanded nodes + std::vector expanded; + + ///> Current selection, might be not valid if nothing was selected + wxDataViewItem selection; + }; + + /** + * Returns the component tree widget state. + */ + STATE getState() const; + + /** + * Restores the component tree widget state from an object. + */ + void setState( const STATE& aState ); + void onQueryText( wxCommandEvent& aEvent ); void onQueryEnter( wxCommandEvent& aEvent ); void onQueryCharHook( wxKeyEvent& aEvent ); @@ -114,16 +141,6 @@ protected: void onPreselect( wxCommandEvent& aEvent ); void onContextMenu( wxDataViewEvent& aEvent ); - /** - * Store the list of expanded nodes in the tree widget. - */ - void saveExpandFlag(); - - /** - * Restore the expanded nodes in the tree widget. - */ - void restoreExpandFlag(); - SYMBOL_LIB_TABLE* m_sym_lib_table; CMP_TREE_MODEL_ADAPTER_BASE::PTR m_adapter; @@ -137,11 +154,11 @@ protected: ///> Flag indicating whether a right-click context menu is active bool m_menuActive; + ///> Flag indicating whether the results are filtered using the search query bool m_filtering; - ///> List of expanded nodes - std::vector m_expanded; - wxDataViewItem m_selection; + ///> State of the widget before any filters applied + STATE m_unfilteredState; }; ///> Custom event sent when a new component is preselected