Add support for sub-libraries concept

Sub-libraries allow a single-level hierarchy inside a symbol library.

This is useful for database libraries and for supporting other EDA library types where a
single file can contain multiple logical groupings of symbols.
This commit is contained in:
Jon Evans 2022-08-26 23:52:56 -04:00
parent a76d1a791d
commit 49354e52a8
9 changed files with 108 additions and 8 deletions

View File

@ -43,6 +43,7 @@ void LIB_ID::clear()
{ {
m_libraryName.clear(); m_libraryName.clear();
m_itemName.clear(); m_itemName.clear();
m_subLibraryName.clear();
} }

View File

@ -136,6 +136,7 @@ public:
virtual void SetName( const wxString& aName ); virtual void SetName( const wxString& aName );
wxString GetName() const override { return m_name; } wxString GetName() const override { return m_name; }
LIB_ID& LibId() { return m_libId; }
LIB_ID GetLibId() const override { return m_libId; } LIB_ID GetLibId() const override { return m_libId; }
void SetLibId( const LIB_ID& aLibId ) { m_libId = aLibId; } void SetLibId( const LIB_ID& aLibId ) { m_libId = aLibId; }

View File

@ -443,6 +443,25 @@ public:
*/ */
virtual void SymbolLibOptions( PROPERTIES* aListToAppendTo ) const; 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<wxString>& aNames ) {}
/** /**
* Return true if the first line in @a aFileName begins with the expected header. * Return true if the first line in @a aFileName begins with the expected header.
* *

View File

@ -142,6 +142,17 @@ LIB_SYMBOL* SCH_DATABASE_PLUGIN::LoadSymbol( const wxString& aLibraryPath,
} }
void SCH_DATABASE_PLUGIN::GetSubLibraryNames( std::vector<wxString>& 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 ) bool SCH_DATABASE_PLUGIN::CheckHeader( const wxString& aFileName )
{ {
// TODO: Implement this sometime; but CheckHeader isn't even called... // 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 ) void SCH_DATABASE_PLUGIN::ensureSettings( const wxString& aSettingsPath )
{ {
if( !m_settings ) if( !m_settings && !aSettingsPath.IsEmpty() )
{ {
std::string path( aSettingsPath.ToUTF8() ); std::string path( aSettingsPath.ToUTF8() );
m_settings = std::make_unique<DATABASE_LIB_SETTINGS>( path ); m_settings = std::make_unique<DATABASE_LIB_SETTINGS>( path );
@ -166,7 +177,7 @@ void SCH_DATABASE_PLUGIN::ensureSettings( const wxString& aSettingsPath )
THROW_IO_ERROR( msg ); THROW_IO_ERROR( msg );
} }
} }
else else if( !m_settings )
{ {
wxASSERT_MSG( aSettingsPath == m_settings->GetFilename(), wxASSERT_MSG( aSettingsPath == m_settings->GetFilename(),
"Path changed for database library without re-initializing plugin!" ); "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->SetName( aSymbolName );
} }
symbol->LibId().SetSubLibraryName( aTable.name );
if( aRow.count( aTable.footprints_col ) ) if( aRow.count( aTable.footprints_col ) )
{ {
// TODO: Support multiple footprint choices // TODO: Support multiple footprint choices

View File

@ -73,6 +73,10 @@ public:
LIB_SYMBOL* LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName, LIB_SYMBOL* LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
const PROPERTIES* aProperties = nullptr ) override; const PROPERTIES* aProperties = nullptr ) override;
bool SupportsSubLibraries() const override { return true; }
void GetSubLibraryNames( std::vector<wxString>& aNames ) override;
bool CheckHeader( const wxString& aFileName ) override; bool CheckHeader( const wxString& aFileName ) override;
// Database libraries can never be written using the symbol editing API // Database libraries can never be written using the symbol editing API

View File

@ -86,6 +86,15 @@ bool SYMBOL_LIB_TABLE_ROW::Refresh()
} }
void SYMBOL_LIB_TABLE_ROW::GetSubLibraryNames( std::vector<wxString>& aNames ) const
{
if( !plugin )
return;
plugin->GetSubLibraryNames( aNames );
}
SYMBOL_LIB_TABLE::SYMBOL_LIB_TABLE( SYMBOL_LIB_TABLE* aFallBackTable ) : SYMBOL_LIB_TABLE::SYMBOL_LIB_TABLE( SYMBOL_LIB_TABLE* aFallBackTable ) :
LIB_TABLE( aFallBackTable ) LIB_TABLE( aFallBackTable )
{ {

View File

@ -80,6 +80,10 @@ public:
*/ */
bool Refresh(); bool Refresh();
bool SupportsSubLibraries() const { return plugin ? plugin->SupportsSubLibraries() : false; }
void GetSubLibraryNames( std::vector<wxString>& aNames ) const;
protected: protected:
SYMBOL_LIB_TABLE_ROW( const SYMBOL_LIB_TABLE_ROW& aRow ) : SYMBOL_LIB_TABLE_ROW( const SYMBOL_LIB_TABLE_ROW& aRow ) :
LIB_TABLE_ROW( aRow ), LIB_TABLE_ROW( aRow ),

View File

@ -118,17 +118,55 @@ bool SYMBOL_TREE_MODEL_ADAPTER::AddLibraries( const std::vector<wxString>& aNick
COMMON_SETTINGS* cfg = Pgm().GetCommonSettings(); COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
PROJECT_FILE& project = aFrame->Prj().GetProjectFile(); PROJECT_FILE& project = aFrame->Prj().GetProjectFile();
auto addFunc =
[&]( const wxString& aLibName, std::vector<LIB_SYMBOL*> aSymbolList,
const wxString& aDescription )
{
std::vector<LIB_TREE_ITEM*> 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<const wxString, std::vector<LIB_SYMBOL*>>& pair : loadedSymbols ) for( const std::pair<const wxString, std::vector<LIB_SYMBOL*>>& pair : loadedSymbols )
{ {
if( !m_libs->FindRow( pair.first )->GetIsVisible() ) SYMBOL_LIB_TABLE_ROW* row = m_libs->FindRow( pair.first );
if( !row->GetIsVisible() )
continue; continue;
std::vector<LIB_TREE_ITEM*> treeItems( pair.second.begin(), pair.second.end() ); if( row->SupportsSubLibraries() )
bool pinned = alg::contains( cfg->m_Session.pinned_symbol_libs, pair.first ) {
|| alg::contains( project.m_PinnedSymbolLibs, pair.first ); std::vector<wxString> subLibraries;
row->GetSubLibraryNames( subLibraries );
DoAddLibrary( pair.first, m_libs->GetDescription( pair.first ), treeItems, pinned, wxString parentDesc = m_libs->GetDescription( pair.first );
false );
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<LIB_SYMBOL*> 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 ) );
}
} }
} }

View File

@ -119,6 +119,16 @@ public:
*/ */
int SetLibItemName( const UTF8& aLibItemName ); 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. * @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_libraryName; ///< The nickname of the library or empty.
UTF8 m_itemName; ///< The name of the entry in the logical library. 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
}; };