From ff9b75b2fb974848eab105d98bf5ab65c511a733 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Fri, 8 Dec 2017 16:12:05 -0800 Subject: [PATCH] Eeschema: Asynchronous library loading Fixes the slow library load time by offloading the process to its own thread that runs on loading Eeschema or changing the library table. Filtered library parts such as power symbols are still loaded when requested. --- eeschema/cmp_tree_model.cpp | 10 ++++++ eeschema/cmp_tree_model.h | 5 +++ eeschema/cmp_tree_model_adapter_base.cpp | 6 +++- eeschema/cmp_tree_model_adapter_base.h | 4 ++- eeschema/files-io.cpp | 3 ++ eeschema/getpart.cpp | 54 ++++++++++++++++++++------------ eeschema/libeditframe.cpp | 2 ++ eeschema/project_rescue.cpp | 2 ++ eeschema/sch_base_frame.cpp | 35 +++++++++++++++++++-- eeschema/sch_base_frame.h | 14 +++++++++ 10 files changed, 111 insertions(+), 24 deletions(-) diff --git a/eeschema/cmp_tree_model.cpp b/eeschema/cmp_tree_model.cpp index 335339d76..bc53bac1d 100644 --- a/eeschema/cmp_tree_model.cpp +++ b/eeschema/cmp_tree_model.cpp @@ -266,6 +266,16 @@ CMP_TREE_NODE_ROOT::CMP_TREE_NODE_ROOT() } +void CMP_TREE_NODE_ROOT::DelLib( wxString const& aName ) +{ + Children.erase( + std::remove_if( Children.begin(), Children.end(), + [ &aName ]( std::unique_ptr& node ){ return node->Name == aName; } ), + Children.end() + ); +} + + CMP_TREE_NODE_LIB& CMP_TREE_NODE_ROOT::AddLib( wxString const& aName ) { CMP_TREE_NODE_LIB* lib = new CMP_TREE_NODE_LIB( this, aName ); diff --git a/eeschema/cmp_tree_model.h b/eeschema/cmp_tree_model.h index ab062ee4a..b851e7829 100644 --- a/eeschema/cmp_tree_model.h +++ b/eeschema/cmp_tree_model.h @@ -269,6 +269,11 @@ public: */ CMP_TREE_NODE_ROOT(); + /** + * Construct an empty library node, add it to the root, and return it. + */ + void DelLib( wxString const& aName ); + /** * Construct an empty library node, add it to the root, and return it. */ diff --git a/eeschema/cmp_tree_model_adapter_base.cpp b/eeschema/cmp_tree_model_adapter_base.cpp index 46b6240f7..22ead2b5b 100644 --- a/eeschema/cmp_tree_model_adapter_base.cpp +++ b/eeschema/cmp_tree_model_adapter_base.cpp @@ -129,8 +129,12 @@ void CMP_TREE_MODEL_ADAPTER_BASE::AddLibrariesWithProgress( void CMP_TREE_MODEL_ADAPTER_BASE::AddAliasList( wxString const& aNodeName, - std::vector const& aAliasList ) + std::vector const& aAliasList, + const bool aOverwrite) { + if( aOverwrite ) + m_tree.DelLib( aNodeName ); + auto& lib_node = m_tree.AddLib( aNodeName ); for( auto a: aAliasList ) diff --git a/eeschema/cmp_tree_model_adapter_base.h b/eeschema/cmp_tree_model_adapter_base.h index 026be485c..3432251e1 100644 --- a/eeschema/cmp_tree_model_adapter_base.h +++ b/eeschema/cmp_tree_model_adapter_base.h @@ -177,10 +177,12 @@ public: * * @param aNodeName the parent node the components will appear under * @param aAliasList list of aliases + * @param aOverwrite true if we should delete the remove the existing node */ void AddAliasList( wxString const& aNodeName, - std::vector const& aAliasList ); + std::vector const& aAliasList, + const bool aOverwrite = false ); /** * Set the search string provided by the user. diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index d42f86b08..50404f629 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -378,6 +378,7 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in SetSheetNumberAndCount(); m_canvas->Refresh( true ); + RefreshLibraryAdapter(); return true; } @@ -633,6 +634,7 @@ bool SCH_EDIT_FRAME::AppendSchematic() SCH_SCREENS screens( GetCurrentSheet().Last() ); screens.UpdateSymbolLinks( true ); + RefreshLibraryAdapter(); GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId ); Zoom_Automatique( false ); SetSheetNumberAndCount(); @@ -791,6 +793,7 @@ bool SCH_EDIT_FRAME::ImportFile( const wxString& aFileName, int aFileType ) UpdateFileHistory( fullFileName ); schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets. + RefreshLibraryAdapter(); // Ensure the schematic is fully segmented on first display BreakSegmentsOnJunctions(); diff --git a/eeschema/getpart.cpp b/eeschema/getpart.cpp index 099b8ce13..f98082e92 100644 --- a/eeschema/getpart.cpp +++ b/eeschema/getpart.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -109,27 +110,47 @@ SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibrary( bool aAllowFields ) { wxString dialogTitle; - SYMBOL_LIB_TABLE* libs = Prj().SchSymbolLibTable(); - - auto adapter( CMP_TREE_MODEL_ADAPTER::Create( libs ) ); - bool loaded = false; + CMP_TREE_MODEL_ADAPTER_BASE::PTR adapter; if( aFilter ) { + adapter = CMP_TREE_MODEL_ADAPTER::Create( m_libs ); + if( aFilter->GetFilterPowerParts() ) + adapter->SetFilter( CMP_TREE_MODEL_ADAPTER::CMP_FILTER_POWER ); + const wxArrayString& liblist = aFilter->GetAllowedLibList(); - for( unsigned ii = 0; ii < liblist.GetCount(); ii++ ) + if( liblist.size() > 0 ) + { + std::vector< wxString > allowed_libs; + for( auto lib : liblist ) + if( m_libs->HasLibrary( lib ) ) + allowed_libs.push_back( lib ); + + adapter->AddLibrariesWithProgress( allowed_libs, this ); + } + else + adapter->AddLibrariesWithProgress( m_libNicknames, this ); + + } + else + { + adapter = m_adapter; + if( m_numLoaded < m_libNicknames.size() ) { - if( libs->HasLibrary( liblist[ii] ) ) + auto* prg = new wxProgressDialog( + _( "Loading symbol libraries" ), + wxEmptyString, + m_libNicknames.size(), + this ); + while( m_numLoaded < m_libNicknames.size() ) { - loaded = true; - adapter->AddLibrary( liblist[ii] ); + prg->Update( m_numLoaded, wxString::Format( _( "Loading library '%s'" ), + m_libNicknames[ m_numLoaded ] ) ); + std::this_thread::yield(); } + prg->Destroy(); } - - if( aFilter->GetFilterPowerParts() ) - adapter->SetFilter( CMP_TREE_MODEL_ADAPTER::CMP_FILTER_POWER ); - } if( !aHistoryList.empty() ) @@ -144,17 +165,10 @@ SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibrary( history_list.push_back( alias ); } - adapter->AddAliasList( "-- " + _( "History" ) + " --", history_list ); + adapter->AddAliasList( "-- " + _( "History" ) + " --", history_list, true ); adapter->SetPreselectNode( aHistoryList[0].LibId, aHistoryList[0].Unit ); } - const std::vector< wxString > libNicknames = libs->GetLogicalLibs(); - - if( !loaded ) - { - adapter->AddLibrariesWithProgress( libNicknames, this ); - } - if( aHighlight && aHighlight->IsValid() ) adapter->SetPreselectNode( *aHighlight, /* aUnit */ 0 ); diff --git a/eeschema/libeditframe.cpp b/eeschema/libeditframe.cpp index 81da87cc1..2f954f12a 100644 --- a/eeschema/libeditframe.cpp +++ b/eeschema/libeditframe.cpp @@ -1500,6 +1500,8 @@ void LIB_EDIT_FRAME::refreshSchematic() schematic.UpdateSymbolLinks(); schematic.TestDanglingEnds(); + RefreshLibraryAdapter(); + // There may be no parent window so use KIWAY message to refresh the schematic editor // in case any symbols have changed. Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_REFRESH, std::string( "" ), this ); diff --git a/eeschema/project_rescue.cpp b/eeschema/project_rescue.cpp index 61a096ac0..ae744511a 100644 --- a/eeschema/project_rescue.cpp +++ b/eeschema/project_rescue.cpp @@ -555,6 +555,8 @@ bool SCH_EDIT_FRAME::rescueProject( RESCUER& aRescuer, bool aRunningOnDemand ) if( viewer ) viewer->ReCreateListLib(); + RefreshLibraryAdapter(); + // Clean up wire ends SchematicCleanUp(); GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 ); diff --git a/eeschema/sch_base_frame.cpp b/eeschema/sch_base_frame.cpp index 5d9e179e4..ea0713bd9 100644 --- a/eeschema/sch_base_frame.cpp +++ b/eeschema/sch_base_frame.cpp @@ -77,7 +77,22 @@ LIB_PART* SchGetLibPart( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aLibTable, PART } -// Sttaic members: +// Static members: +static bool load_async_libraries( const std::vector< wxString > aLibraries, + CMP_TREE_MODEL_ADAPTER_BASE::PTR aAdapter, + std::atomic_uint* aNumLoaded, + std::mutex* aLock ) +{ + for( auto nickname : aLibraries ) + { + aAdapter->AddLibrary( nickname ); + (*aNumLoaded)++; + } + + aLock->unlock(); + return true; +} + SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aWindowType, const wxString& aTitle, @@ -92,15 +107,29 @@ SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, // but this is an acceptable value m_repeatStep = wxPoint( DEFAULT_REPEAT_OFFSET_X, DEFAULT_REPEAT_OFFSET_Y ); m_repeatDeltaLabel = DEFAULT_REPEAT_LABEL_INC; + m_libs = NULL; } - SCH_BASE_FRAME::~SCH_BASE_FRAME() { } +void SCH_BASE_FRAME::RefreshLibraryAdapter() +{ + if( m_libMutex.try_lock() ) + { + m_libs = Prj().SchSymbolLibTable(); + m_adapter = ( CMP_TREE_MODEL_ADAPTER::Create( m_libs ) ); + m_libNicknames = m_libs->GetLogicalLibs(); + m_numLoaded = 0; + m_finishedLoading = std::async( std::launch::async, load_async_libraries, + m_libNicknames, m_adapter, &m_numLoaded, &m_libMutex ); + } +} + + void SCH_BASE_FRAME::OnOpenLibraryViewer( wxCommandEvent& event ) { LIB_VIEW_FRAME* viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, true ); @@ -270,6 +299,8 @@ void SCH_BASE_FRAME::OnEditSymbolLibTable( wxCommandEvent& aEvent ) saveSymbolLibTables( true, true ); + RefreshLibraryAdapter(); + LIB_EDIT_FRAME* editor = (LIB_EDIT_FRAME*) Kiway().Player( FRAME_SCH_LIB_EDITOR, false ); if( this == editor ) diff --git a/eeschema/sch_base_frame.h b/eeschema/sch_base_frame.h index 231f4e180..5d6352bb1 100644 --- a/eeschema/sch_base_frame.h +++ b/eeschema/sch_base_frame.h @@ -28,6 +28,9 @@ #include #include +#include + +#include class PAGE_INFO; class TITLE_BLOCK; @@ -81,6 +84,12 @@ protected: int m_repeatDeltaLabel; ///< the increment value of labels like bus members ///< when they are repeated + SYMBOL_LIB_TABLE* m_libs; + CMP_TREE_MODEL_ADAPTER_BASE::PTR m_adapter; + std::vector< wxString > m_libNicknames; + std::future< bool > m_finishedLoading; + std::atomic_uint m_numLoaded; + std::mutex m_libMutex; public: SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, @@ -237,6 +246,11 @@ public: protected: + /** + * Spawn a thread to update the library symbols. + */ + void RefreshLibraryAdapter(); + /** * Open the library viewer only to browse library contents. * If the viewed is already opened from this, raise the viewer -- 2.15.0