diff --git a/common/lib_id.cpp b/common/lib_id.cpp index 0b005a1a45..041e773385 100644 --- a/common/lib_id.cpp +++ b/common/lib_id.cpp @@ -43,6 +43,7 @@ void LIB_ID::clear() { m_libraryName.clear(); m_itemName.clear(); + m_subLibraryName.clear(); } diff --git a/eeschema/lib_symbol.h b/eeschema/lib_symbol.h index b9a74bd441..d3a385df37 100644 --- a/eeschema/lib_symbol.h +++ b/eeschema/lib_symbol.h @@ -136,6 +136,7 @@ public: virtual void SetName( const wxString& aName ); wxString GetName() const override { return m_name; } + LIB_ID& LibId() { return m_libId; } LIB_ID GetLibId() const override { return m_libId; } void SetLibId( const LIB_ID& aLibId ) { m_libId = aLibId; } diff --git a/eeschema/sch_io_mgr.h b/eeschema/sch_io_mgr.h index b455b54c23..a945681ad9 100644 --- a/eeschema/sch_io_mgr.h +++ b/eeschema/sch_io_mgr.h @@ -443,6 +443,25 @@ public: */ virtual void SymbolLibOptions( PROPERTIES* aListToAppendTo ) const; + /** + * @return true if this plugin supports libraries that contain sub-libraries. + */ + virtual bool SupportsSubLibraries() const { return false; } + + /** + * Retrieves a list of sub-libraries in this library. + * + * Some types of symbol library support sub-libraries, which are a single-level organizational + * hierarchy that is implementation-defined per plugin. Most of KiCad ignores sub-libraries and + * treats the hierarchy between library and symbol as flat, but the sub-libraries are used for + * sorting and grouping symbols in the symbol chooser. + * + * Has no effect if SupportsSubLibraries() returns false. + * + * @param aNames will be filled with a list of sub-libraries within this symbol library + */ + virtual void GetSubLibraryNames( std::vector& aNames ) {} + /** * Return true if the first line in @a aFileName begins with the expected header. * diff --git a/eeschema/sch_plugins/database/sch_database_plugin.cpp b/eeschema/sch_plugins/database/sch_database_plugin.cpp index 99139d5f3a..75da555ca6 100644 --- a/eeschema/sch_plugins/database/sch_database_plugin.cpp +++ b/eeschema/sch_plugins/database/sch_database_plugin.cpp @@ -142,6 +142,17 @@ LIB_SYMBOL* SCH_DATABASE_PLUGIN::LoadSymbol( const wxString& aLibraryPath, } +void SCH_DATABASE_PLUGIN::GetSubLibraryNames( std::vector& aNames ) +{ + ensureSettings( wxEmptyString ); + + aNames.clear(); + + for( const DATABASE_LIB_TABLE& tableIter : m_settings->m_Tables ) + aNames.emplace_back( tableIter.name ); +} + + bool SCH_DATABASE_PLUGIN::CheckHeader( const wxString& aFileName ) { // TODO: Implement this sometime; but CheckHeader isn't even called... @@ -151,7 +162,7 @@ bool SCH_DATABASE_PLUGIN::CheckHeader( const wxString& aFileName ) void SCH_DATABASE_PLUGIN::ensureSettings( const wxString& aSettingsPath ) { - if( !m_settings ) + if( !m_settings && !aSettingsPath.IsEmpty() ) { std::string path( aSettingsPath.ToUTF8() ); m_settings = std::make_unique( path ); @@ -166,7 +177,7 @@ void SCH_DATABASE_PLUGIN::ensureSettings( const wxString& aSettingsPath ) THROW_IO_ERROR( msg ); } } - else + else if( !m_settings ) { wxASSERT_MSG( aSettingsPath == m_settings->GetFilename(), "Path changed for database library without re-initializing plugin!" ); @@ -251,6 +262,8 @@ LIB_SYMBOL* SCH_DATABASE_PLUGIN::loadSymbolFromRow( const wxString& aSymbolName, symbol->SetName( aSymbolName ); } + symbol->LibId().SetSubLibraryName( aTable.name ); + if( aRow.count( aTable.footprints_col ) ) { // TODO: Support multiple footprint choices diff --git a/eeschema/sch_plugins/database/sch_database_plugin.h b/eeschema/sch_plugins/database/sch_database_plugin.h index dcd2331869..da16cc0a8d 100644 --- a/eeschema/sch_plugins/database/sch_database_plugin.h +++ b/eeschema/sch_plugins/database/sch_database_plugin.h @@ -73,6 +73,10 @@ public: LIB_SYMBOL* LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName, const PROPERTIES* aProperties = nullptr ) override; + bool SupportsSubLibraries() const override { return true; } + + void GetSubLibraryNames( std::vector& aNames ) override; + bool CheckHeader( const wxString& aFileName ) override; // Database libraries can never be written using the symbol editing API diff --git a/eeschema/symbol_lib_table.cpp b/eeschema/symbol_lib_table.cpp index 27cfc17d13..ef0d84f048 100644 --- a/eeschema/symbol_lib_table.cpp +++ b/eeschema/symbol_lib_table.cpp @@ -86,6 +86,15 @@ bool SYMBOL_LIB_TABLE_ROW::Refresh() } +void SYMBOL_LIB_TABLE_ROW::GetSubLibraryNames( std::vector& aNames ) const +{ + if( !plugin ) + return; + + plugin->GetSubLibraryNames( aNames ); +} + + SYMBOL_LIB_TABLE::SYMBOL_LIB_TABLE( SYMBOL_LIB_TABLE* aFallBackTable ) : LIB_TABLE( aFallBackTable ) { diff --git a/eeschema/symbol_lib_table.h b/eeschema/symbol_lib_table.h index 643a17fc16..a7a46f2d9b 100644 --- a/eeschema/symbol_lib_table.h +++ b/eeschema/symbol_lib_table.h @@ -80,6 +80,10 @@ public: */ bool Refresh(); + bool SupportsSubLibraries() const { return plugin ? plugin->SupportsSubLibraries() : false; } + + void GetSubLibraryNames( std::vector& aNames ) const; + protected: SYMBOL_LIB_TABLE_ROW( const SYMBOL_LIB_TABLE_ROW& aRow ) : LIB_TABLE_ROW( aRow ), diff --git a/eeschema/symbol_tree_model_adapter.cpp b/eeschema/symbol_tree_model_adapter.cpp index 20667bb597..26a68665f2 100644 --- a/eeschema/symbol_tree_model_adapter.cpp +++ b/eeschema/symbol_tree_model_adapter.cpp @@ -118,17 +118,55 @@ bool SYMBOL_TREE_MODEL_ADAPTER::AddLibraries( const std::vector& aNick COMMON_SETTINGS* cfg = Pgm().GetCommonSettings(); PROJECT_FILE& project = aFrame->Prj().GetProjectFile(); + auto addFunc = + [&]( const wxString& aLibName, std::vector aSymbolList, + const wxString& aDescription ) + { + std::vector treeItems( aSymbolList.begin(), aSymbolList.end() ); + bool pinned = alg::contains( cfg->m_Session.pinned_symbol_libs, aLibName ) + || alg::contains( project.m_PinnedSymbolLibs, aLibName ); + + DoAddLibrary( aLibName, aDescription, treeItems, pinned, false ); + }; + for( const std::pair>& pair : loadedSymbols ) { - if( !m_libs->FindRow( pair.first )->GetIsVisible() ) + SYMBOL_LIB_TABLE_ROW* row = m_libs->FindRow( pair.first ); + + if( !row->GetIsVisible() ) continue; - std::vector treeItems( pair.second.begin(), pair.second.end() ); - bool pinned = alg::contains( cfg->m_Session.pinned_symbol_libs, pair.first ) - || alg::contains( project.m_PinnedSymbolLibs, pair.first ); + if( row->SupportsSubLibraries() ) + { + std::vector subLibraries; + row->GetSubLibraryNames( subLibraries ); - DoAddLibrary( pair.first, m_libs->GetDescription( pair.first ), treeItems, pinned, - false ); + wxString parentDesc = m_libs->GetDescription( pair.first ); + + for( const wxString& lib : subLibraries ) + { + wxString name = wxString::Format( wxT( "%s - %s" ), pair.first, lib ); + wxString desc; + + if( !parentDesc.IsEmpty() ) + desc = wxString::Format( wxT( "%s (%s)" ), parentDesc, lib ); + + std::vector symbols; + + std::copy_if( pair.second.begin(), pair.second.end(), + std::back_inserter( symbols ), + [&lib]( LIB_SYMBOL* aSym ) + { + return lib.IsSameAs( aSym->GetLibId().GetSubLibraryName() ); + } ); + + addFunc( name, symbols, desc ); + } + } + else + { + addFunc( pair.first, pair.second, m_libs->GetDescription( pair.first ) ); + } } } diff --git a/include/lib_id.h b/include/lib_id.h index 3a511d022a..3af04c611b 100644 --- a/include/lib_id.h +++ b/include/lib_id.h @@ -119,6 +119,16 @@ public: */ int SetLibItemName( const UTF8& aLibItemName ); + /** + * Some LIB_IDs can have a sub-library identifier in addition to a library nickname. + * This identifier is *not* part of the canonical LIB_ID and is not written out / parsed. + * It is only used for internal sorting/grouping, if present. + * + * @return the sub-library name for this LIB_ID, if one exists + */ + UTF8 GetSubLibraryName() const { return m_subLibraryName; } + void SetSubLibraryName( const UTF8& aName ) { m_subLibraryName = aName; } + /** * @return the fully formatted text of the LIB_ID in a UTF8 string. */ @@ -253,6 +263,7 @@ protected: UTF8 m_libraryName; ///< The nickname of the library or empty. UTF8 m_itemName; ///< The name of the entry in the logical library. + UTF8 m_subLibraryName; ///< Optional sub-library name used for grouping within a library };