25#include <magic_enum.hpp>
29#include <unordered_set>
40using namespace std::chrono_literals;
62 std::vector<LIBRARY_TABLE_TYPE> aTablesToLoad )
81 wxCHECK_MSG(
false,
m_tables,
"Invalid scope passed to loadTables" );
85 std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>& aTarget = getTarget();
87 if( aTablesToLoad.size() == 0 )
92 aTarget.erase( type );
96 if( fn.IsFileReadable() )
98 std::unique_ptr<LIBRARY_TABLE>
table = std::make_unique<LIBRARY_TABLE>( fn, aScope );
100 if(
table->Type() != type )
102 auto actualName = magic_enum::enum_name(
table->Type() );
103 auto expectedName = magic_enum::enum_name( type );
104 wxLogWarning( wxS(
"Library table '%s' has type %s but expected %s; skipping" ),
106 wxString( actualName.data(), actualName.size() ),
107 wxString( expectedName.data(), expectedName.size() ) );
111 aTarget[type] = std::move(
table );
116 wxLogTrace(
traceLibraries,
"No library table found at %s", fn.GetFullPath() );
124 std::unordered_set<wxString> seenTables;
129 seenTables.insert( aTable.Path() );
138 wxFileName file(
ExpandURI( row.URI(),
Pgm().GetSettingsManager().
Prj() ) );
141 file.MakeAbsolute( wxFileName( aTable.Path() ).GetPath() );
144 wxString src = file.GetFullPath();
146 if( seenTables.contains( src ) )
148 wxLogTrace(
traceLibraries,
"Library table %s has already been loaded!", src );
150 row.SetErrorDescription(
_(
"A reference to this library table already exists" ) );
154 auto child = std::make_unique<LIBRARY_TABLE>( file, aRootTable.
Scope() );
156 processOneTable( *child );
161 row.SetErrorDescription( child->ErrorDescription() );
166 m_childTables.insert_or_assign( row.URI(), std::move( child ) );
171 processOneTable( aRootTable );
186 wxString tablePath = aTable.
Path();
193 const std::map<wxString, LIB_OVERRIDE>& overrides = it->second;
197 auto overIt = overrides.find( row.Nickname() );
199 if( overIt != overrides.end() )
201 row.SetDisabled( overIt->second.disabled );
202 row.SetHidden( overIt->second.hidden );
215 bool aDisabled,
bool aHidden )
220 wxCHECK( settings, );
222 if( !aDisabled && !aHidden )
228 settings->
m_LibOverrides[aTablePath][aNickname] = { aDisabled, aHidden };
237 wxCHECK( settings, );
244 tableIt->second.erase( aNickname );
246 if( tableIt->second.empty() )
258 default: wxCHECK(
false, wxEmptyString );
267 wxCHECK( !
m_tables.contains( aType ), );
276 wxFileName fn(
Pgm().GetSettingsManager().
Prj().GetProjectDirectory(),
tableFileName( aType ) );
288 const wxString& aPrefix ) :
294 wxFileName f( aBasePath,
"" );
300 .value_or(
nullptr );
304 wxDirTraverseResult
OnFile(
const wxString& aFilePath )
override
306 wxFileName file = wxFileName::FileName( aFilePath );
310 if( file.GetExt() == wxT(
"kicad_sym" )
317 return wxDIR_CONTINUE;
321 wxDirTraverseResult
OnDir(
const wxString& dirPath )
override
324 wxFileName dir = wxFileName::DirName( dirPath );
328 if( dirPath.EndsWith( wxS(
".pretty" ) )
334 else if( dirPath.EndsWith( designBlockExt )
341 return wxDIR_CONTINUE;
349 if( aTable->
HasRow( aNickname ) )
355 aNickname = wxString::Format(
"%s%s_%d",
m_lib_prefix, aBaseName, increment );
357 }
while( aTable->
HasRow( aNickname ) );
368 int aExtensionLength )
370 wxString versionedPath = wxString::Format( wxS(
"${%s}" ),
373 wxArrayString parts = aSource.GetDirs();
375 parts.Insert( versionedPath, 0 );
378 parts.Add( aSource.GetFullName() );
380 wxString libPath = wxJoin( parts,
'/' );
384 wxString
name = parts.Last().substr( 0, parts.Last().length() - aExtensionLength );
389 wxLogTrace(
traceLibraries,
"Manager: Adding PCM lib '%s' as '%s'", libPath, nickname );
401 wxLogTrace(
traceLibraries,
"Manager: Not adding existing PCM lib '%s'", libPath );
426 return fn.GetFullPath();
437 return fn.GetFullPath();
445 return wxString::Format( wxS(
"${%s}/%s" ), templateDirVar,
tableFileName( aType ) );
459 auto it = common->m_Env.vars.find( templateDirVar );
461 if( it != common->m_Env.vars.end() && it->second.GetDefinedExternally() )
471 if( wxFileName fn( aPath ); fn.IsFileReadable() )
491 std::vector<LIBRARY_TABLE_TYPE> invalidTables;
501 invalidTables.emplace_back( tableType );
504 return invalidTables;
513 table.SetType( aType );
514 table.Rows().clear();
518 if( aPopulateDefaultLibraries && defaultLib.IsFileReadable() )
526 else if( aPopulateDefaultLibraries )
528 auto typeName = magic_enum::enum_name( aType );
529 wxLogTrace(
traceLibraries,
"No stock library table for %s at '%s'; creating empty global table",
530 wxString( typeName.data(), typeName.size() ), defaultLib.GetFullPath() );
536 table.Format( &formatter );
555 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
556 adapter->GlobalTablesChanged( aTablesToLoad );
564 wxCHECK( settings, );
572 wxFileName d( *packagesPath,
"" );
577 wxDir dir( d.GetPath() );
579 dir.Traverse( traverser );
583 table->Save().map_error(
586 wxLogTrace(
traceLibraries, wxT(
"Warning: save failed after PCM auto-add: %s" ),
593 auto cleanupRemovedPCMLibraries =
601 auto toErase = std::ranges::remove_if(
table->Rows(),
604 if( !IsPcmManagedRow( aRow ) )
607 wxString path = GetFullURI( &aRow, true );
608 return !wxFileName::Exists( path );
611 bool hadRemovals = !toErase.empty();
612 table->Rows().erase( toErase.begin(), toErase.end() );
616 table->Save().map_error(
619 wxLogTrace(
traceLibraries, wxT(
"Warning: save failed after PCM auto-remove: %s" ),
651 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
652 adapter->ProjectChanged();
660 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
661 adapter->AbortAsyncLoad();
666 std::unique_ptr<LIBRARY_MANAGER_ADAPTER>&& aAdapter )
670 wxCHECK_MSG( !
m_adapters.contains( aType ), ,
"You should only register an adapter once!" );
708 wxCHECK_MSG(
false, std::nullopt,
"Table() requires a single scope" );
715 magic_enum::enum_name( aType ) );
727 if( !
Pgm().GetSettingsManager().
Prj().IsNullProject() )
742 bool aIncludeInvalid )
const
744 std::map<wxString, LIBRARY_TABLE_ROW*> rows;
745 std::vector<wxString> rowOrder;
747 std::list<std::ranges::ref_view<const std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>>> tables;
752 tables = { std::views::all(
m_tables ) };
767 std::function<void(
const std::unique_ptr<LIBRARY_TABLE>&,
bool parentHidden)> processTable =
768 [&](
const std::unique_ptr<LIBRARY_TABLE>& aTable,
const bool parentHidden )
770 if( aTable->Type() != aType )
773 if( aTable->IsOk() || aIncludeInvalid )
777 if( row.IsOk() || aIncludeInvalid )
781 row.SetHidden(
true );
796 if( !rows.contains( row.Nickname() ) )
797 rowOrder.emplace_back( row.Nickname() );
799 rows[ row.Nickname() ] = &row;
806 for(
const std::unique_ptr<LIBRARY_TABLE>&
table :
807 std::views::join( tables ) | std::views::values )
809 processTable(
table,
false );
812 std::vector<LIBRARY_TABLE_ROW*> ret;
814 for(
const wxString& row : rowOrder )
815 ret.emplace_back( rows[row] );
826 auto key = std::make_tuple( aType, aScope, aNickname );
834 if( row->Nickname() == aNickname )
837 m_rowCache[std::make_tuple( aType, aScope, aNickname )] = row;
847 const wxString& aUri,
863 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter =
Adapter( aType ); adapter )
864 ( *adapter )->ReloadLibraryEntry( aNickname, aScope );
869 const wxString& aNickname )
871 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter =
Adapter( aType ); adapter )
872 return ( *adapter )->LoadLibraryEntry( aNickname );
879 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
888 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
889 adapter->ProjectTablesChanged( aTablesToLoad );
892 if( wxFileName::IsDirReadable( aProjectPath ) )
907 wxLogTrace(
traceLibraries,
"New project path %s is not readable, not loading project tables", aProjectPath );
917 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
918 adapter->ProjectTablesReloaded( aTablesToLoad );
924 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
941 if( std::optional<const LIBRARY_TABLE_ROW*>
result =
GetRow( aType, aNickname ) )
963 return path.GetFullPath();
978 const wxString& uri = aRow.
URI();
980 if( !uri.StartsWith( wxS(
"${" ) ) )
983 size_t end = uri.find( wxS(
'}' ) );
985 if(
end == wxString::npos ||
end <= 2 )
988 wxString varName = uri.SubString( 2,
end - 1 );
996 if(
end + 1 >= uri.length() || uri[
end + 1] != wxS(
'/' ) )
1003 wxArrayString parts = wxSplit( uri.Mid(
end + 2 ),
'/',
'\0' );
1005 if( parts.size() < 3 )
1008 for(
const wxString& part : parts )
1010 if( part.IsEmpty() )
1014 wxString category = parts[0];
1015 wxString leaf = parts.Last();
1020 auto hasLibExtension = [&leaf](
const wxString& aExt )
1022 return leaf.length() > aExt.length() && leaf.EndsWith( aExt );
1025 if( category == wxS(
"symbols" ) )
1026 return hasLibExtension( wxS(
".kicad_sym" ) );
1028 if( category == wxS(
"footprints" ) )
1029 return hasLibExtension( wxS(
".pretty" ) );
1031 if( category == wxS(
"design_blocks" ) )
1033 static const wxString designBlockExt =
1036 return hasLibExtension( designBlockExt );
1046 if( aURI1.Find(
"://" ) != wxNOT_FOUND )
1049 return aURI1 == aURI2;
1053 const wxFileName fn1( aURI1 );
1054 const wxFileName fn2( aURI2 );
1119 bool me = aChangedTables.size() == 0;
1123 if( type ==
Type() )
1152 if( it->second.global_owner ==
this )
1162 bool me = aChangedTables.size() == 0;
1166 if( type ==
Type() )
1181 std::initializer_list<LIBRARY_TABLE_TYPE> aChangedTables )
1183 bool me = aChangedTables.size() == 0;
1187 if( type ==
Type() )
1206 [
this](
const auto& aEntry )
1222 if( loadedRow->
URI() == aRow.
URI() && loadedRow->
Type() == aRow.
Type() )
1239 std::optional<LIB_STATUS> status =
LoadOne( &lib );
1241 if( status.has_value() )
1245 if( status.value().error.has_value() )
1256 aRow.
SetOk(
false );
1281 return row->Nickname();
1284 return std::nullopt;
1290 std::vector<wxString> ret;
1291 std::vector<LIBRARY_TABLE_ROW*> rows =
m_manager.Rows(
Type() );
1293 wxLogTrace(
traceLibraries,
"GetLibraryNames: checking %zu rows from table", rows.size() );
1297 wxString nickname = row->Nickname();
1298 std::optional<const LIB_DATA*> loaded =
fetchIfLoaded( nickname );
1301 ret.emplace_back( nickname );
1306 wxLogTrace(
traceLibraries,
"GetLibraryNames: returning %zu of %zu libraries", ret.size(), rows.size() );
1313 std::optional<const LIB_DATA*> r =
fetchIfLoaded( aNickname );
1316 return !aCheckEnabled || !r.value()->row->Disabled();
1345 if( std::optional<const LIB_DATA*> optRow =
fetchIfLoaded( aNickname ); optRow )
1346 return ( *optRow )->row->Description();
1348 return std::nullopt;
1353 bool aIncludeInvalid )
const
1367 const wxString& aUri,
1404 return std::nullopt;
1407 return loaded /
static_cast<float>( total );
1413 wxLogTrace(
traceLibraries,
"BlockUntilLoaded: entry, acquiring m_loadMutex" );
1414 std::unique_lock<std::mutex> asyncLock(
m_loadMutex );
1418 for(
const std::future<void>& future :
m_futures )
1421 wxLogTrace(
traceLibraries,
"BlockUntilLoaded: all futures complete, loadCount=%zu, loadTotal=%zu",
1452 return it->second.status.error;
1459 return it->second.status.error;
1462 return std::nullopt;
1468 std::vector<std::pair<wxString, LIB_STATUS>> ret;
1472 if( row->Disabled() )
1477 ret.emplace_back( std::make_pair( row->Nickname(), *
result ) );
1482 ret.emplace_back( std::make_pair( row->Nickname(),
1485 .error =
LIBRARY_ERROR(
_(
"Library not found in library table" ) )
1502 if( !errors.IsEmpty() )
1503 errors += wxS(
"\n" );
1505 errors += wxString::Format(
_(
"Library '%s': %s" ),
1506 nickname, status.error->message );
1521 return std::nullopt;
1529 std::shared_mutex& aMutex )
1531 bool wasLoaded =
false;
1534 std::unique_lock lock( aMutex );
1535 auto it = aTarget.find( aNickname );
1537 if( it != aTarget.end() && it->second.plugin )
1540 aTarget.erase( it );
1548 if( !
result.has_value() )
1550 wxLogTrace(
traceLibraries,
"ReloadLibraryEntry: failed to reload %s (%s): %s",
1551 aNickname, magic_enum::enum_name( aScopeToReload ),
1552 result.error().message );
1602 wxLogTrace(
traceLibraries,
"CreateLibrary: IO_ERROR for %s: %s",
1603 aNickname, ioe.
What() );
1606 catch(
const std::exception& e )
1608 wxLogTrace(
traceLibraries,
"CreateLibrary: std::exception for %s: %s",
1609 aNickname, e.what() );
1614 wxLogTrace(
traceLibraries,
"CreateLibrary: library row '%s' not found", aNickname );
1635 return std::nullopt;
1647 return std::nullopt;
1651 return std::nullopt;
1665 return std::nullopt;
1677 return std::nullopt;
1681 return std::nullopt;
1687 std::map<wxString, LIB_DATA>& aTarget,
1688 std::shared_mutex& aMutex )
1690 bool present =
false;
1693 std::shared_lock lock( aMutex );
1694 present = aTarget.contains( aNickname ) && aTarget.at( aNickname ).plugin;
1702 wxLogTrace(
traceLibraries,
"Library %s (%s) not yet loaded, will attempt...",
1703 aNickname, magic_enum::enum_name( aScope ) );
1707 std::unique_lock lock( aMutex );
1710 aTarget[ row->
Nickname() ].row = row;
1714 aTarget[ row->
Nickname() ].global_owner =
this;
1716 return &aTarget.at( aNickname );
1720 return tl::unexpected(
plugin.error() );
1727 std::shared_lock lock( aMutex );
1728 return &aTarget.at( aNickname );
1745 wxString msg = wxString::Format(
_(
"Library %s not found" ), aNickname );
1756 return it->second.status;
1763 return it->second.status;
1766 return std::nullopt;
1772 std::unique_lock<std::mutex> asyncLock(
m_loadMutex, std::try_to_lock );
1778 []( std::future<void>& aFuture )
1780 return aFuture.valid()
1781 && aFuture.wait_for( 0s ) == std::future_status::ready;
1786 wxLogTrace(
traceLibraries,
"Cannot AsyncLoad, futures from a previous call remain!" );
1790 std::vector<LIBRARY_TABLE_ROW*> rows =
m_manager.Rows(
Type() );
1797 wxLogTrace(
traceLibraries,
"AsyncLoad: no libraries left to load; exiting" );
1804 [&](
const wxString& aLib, std::map<wxString, LIB_DATA>& aMap, std::shared_mutex& aMutex )
1806 std::shared_lock lock( aMutex );
1808 if(
auto it = aMap.find( aLib ); it != aMap.end() )
1810 LOAD_STATUS status = it->second.status.load_status;
1828 auto workQueue = std::make_shared<std::vector<LOAD_WORK>>();
1829 workQueue->reserve( rows.size() );
1833 wxString nickname = row->Nickname();
1848 workQueue->emplace_back( LOAD_WORK{ nickname, scope,
getUri( row ) } );
1851 if( workQueue->empty() )
1853 wxLogTrace(
traceLibraries,
"AsyncLoad: all libraries already loaded; exiting" );
1860 size_t poolSize =
tp.get_thread_count();
1861 size_t maxLoadThreads = std::max<size_t>( 1, poolSize > 2 ? poolSize - 2 : 1 );
1862 size_t numWorkers = std::min( maxLoadThreads, workQueue->size() );
1864 auto workIndex = std::make_shared<std::atomic<size_t>>( 0 );
1866 wxLogTrace(
traceLibraries,
"AsyncLoad: %zu libraries to load, using %zu worker threads (pool has %zu)",
1867 workQueue->size(), numWorkers, poolSize );
1869 for(
size_t w = 0; w < numWorkers; ++w )
1872 [
this, workQueue, workIndex]()
1876 if( m_abort.load() )
1879 size_t idx = workIndex->fetch_add( 1 );
1881 if( idx >= workQueue->size() )
1884 const LOAD_WORK& work = ( *workQueue )[idx];
1885 LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( work.nickname );
1887 if( result.has_value() )
1889 LIB_DATA* lib = *result;
1894 std::unique_lock lock(
1895 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
1897 : m_librariesMutex );
1898 lib->status.load_status = LOAD_STATUS::LOADING;
1901 enumerateLibrary( lib, work.uri );
1904 std::unique_lock lock(
1905 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
1907 : m_librariesMutex );
1908 lib->status.load_status = LOAD_STATUS::LOADED;
1911 catch( IO_ERROR& e )
1913 std::unique_lock lock(
1914 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
1916 : m_librariesMutex );
1917 lib->status.load_status = LOAD_STATUS::LOAD_ERROR;
1918 lib->status.error = LIBRARY_ERROR( { e.What() } );
1919 wxLogTrace( traceLibraries,
"%s: plugin threw exception: %s",
1920 work.nickname, e.What() );
1925 std::unique_lock lock(
1926 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
1928 : m_librariesMutex );
1930 std::map<wxString, LIB_DATA>& target =
1931 ( work.scope == LIBRARY_TABLE_SCOPE::GLOBAL ) ? globalLibs()
1934 target[work.nickname].status = LIB_STATUS( {
1935 .load_status = LOAD_STATUS::LOAD_ERROR,
1936 .error = result.error()
1942 }, BS::pr::lowest ) );
1945 wxLogTrace(
traceLibraries,
"Started async load of %zu libraries", workQueue->size() );
virtual bool DeleteLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr)
Delete an existing library and returns true, or if library does not exist returns false,...
virtual bool IsLibraryWritable(const wxString &aLibraryPath)
Return true if the library at aLibraryPath is writable.
virtual void CreateLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr)
Create a new empty library at aLibraryPath empty.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
std::map< wxString, std::map< wxString, LIB_OVERRIDE > > m_LibOverrides
Overrides for libraries in read-only nested tables.
The interface used by the classes that actually can load IO plugins for the different parts of KiCad ...
std::optional< float > AsyncLoadProgress() const
Returns async load progress between 0.0 and 1.0, or nullopt if load is not in progress.
virtual std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib)=0
void resetProjectCache()
Aborts pending loads and resets every project-scope cache entry in place (plugin and row cleared,...
virtual std::optional< LIBRARY_ERROR > LibraryError(const wxString &aNickname) const
void ReloadLibraryEntry(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
std::optional< LIB_STATUS > GetLibraryStatus(const wxString &aNickname) const
Returns the status of a loaded library, or nullopt if the library hasn't been loaded (yet)
virtual ~LIBRARY_MANAGER_ADAPTER()
std::optional< LIBRARY_TABLE * > ProjectTable() const
Retrieves the project library table for this adapter type, or nullopt if one doesn't exist.
void AbortAsyncLoad()
Aborts any async load in progress; blocks until fully done aborting.
void ProjectTablesChanged(std::initializer_list< LIBRARY_TABLE_TYPE > aChangedTables={})
Notify the adapter that the project library tables are about to be rebuilt.
LIBRARY_TABLE * GlobalTable() const
Retrieves the global library table for this adapter type.
virtual std::shared_mutex & globalLibsMutex()=0
void evictOwnedGlobalEntries()
Erases this adapter's own entries (LIB_DATA::global_owner == this) from the process-wide globalLibs()...
LIBRARY_MANAGER_ADAPTER(LIBRARY_MANAGER &aManager)
Constructs a type-specific adapter into the library manager.
void CheckTableRow(LIBRARY_TABLE_ROW &aRow)
bool IsLibraryLoaded(const wxString &aNickname)
std::vector< LIBRARY_TABLE_ROW * > Rows(LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH, bool aIncludeInvalid=false) const
Like LIBRARY_MANAGER::Rows but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< LIBRARY_TABLE_ROW * > FindRowByURI(const wxString &aUri, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::FindRowByURI but filtered to the LIBRARY_TABLE_TYPE of this adapter.
virtual std::map< wxString, LIB_DATA > & globalLibs()=0
virtual LIBRARY_TABLE_TYPE Type() const =0
The type of library table this adapter works with.
bool DeleteLibrary(const wxString &aNickname)
Deletes the given library from disk if it exists; returns true if deleted.
LIBRARY_RESULT< LIB_DATA * > loadIfNeeded(const wxString &aNickname)
Fetches a loaded library, triggering a load of that library if it isn't loaded yet.
wxString GetLibraryLoadErrors() const
Returns all library load errors as newline-separated strings for display.
std::optional< wxString > FindLibraryByURI(const wxString &aURI) const
std::shared_mutex m_librariesMutex
LIBRARY_MANAGER & Manager() const
void abortLoad()
Aborts any async load in progress; blocks until fully done aborting.
std::optional< wxString > GetLibraryDescription(const wxString &aNickname) const
virtual LIBRARY_RESULT< IO_BASE * > createPlugin(const LIBRARY_TABLE_ROW *row)=0
Creates a concrete plugin for the given row.
void GlobalTablesChanged(std::initializer_list< LIBRARY_TABLE_TYPE > aChangedTables={})
Notify the adapter that the global library tables have changed.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::map< wxString, LIB_DATA > m_libraries
virtual IO_BASE * plugin(const LIB_DATA *aRow)=0
std::vector< wxString > GetLibraryNames() const
Returns a list of library nicknames that are available (skips any that failed to load)
virtual void ProjectChanged()
Notify the adapter that the active project has changed.
LIBRARY_RESULT< LIB_DATA * > loadFromScope(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope, std::map< wxString, LIB_DATA > &aTarget, std::shared_mutex &aMutex)
std::vector< std::future< void > > m_futures
static wxString getUri(const LIBRARY_TABLE_ROW *aRow)
bool CreateLibrary(const wxString &aNickname)
Creates the library (i.e. saves to disk) for the given row if it exists.
void AsyncLoad()
Loads all available libraries for this adapter type in the background.
virtual bool IsWritable(const wxString &aNickname) const
Return true if the given nickname exists and is not a read-only library.
std::vector< std::pair< wxString, LIB_STATUS > > GetLibraryStatuses() const
Returns a list of all library nicknames and their status (even if they failed to load)
std::atomic< size_t > m_loadTotal
void ProjectTablesReloaded(std::initializer_list< LIBRARY_TABLE_TYPE > aChangedTables={})
Complements ProjectTablesChanged by erasing project-scope cache entries whose nicknames no longer app...
std::atomic< size_t > m_loadCount
LIBRARY_MANAGER & m_manager
std::optional< LIB_STATUS > LoadLibraryEntry(const wxString &aNickname)
Synchronously loads the named library to LOADED state.
std::optional< const LIB_DATA * > fetchIfLoaded(const wxString &aNickname) const
void ReloadTables(LIBRARY_TABLE_SCOPE aScope, std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
static wxString StockTableTokenizedURI(LIBRARY_TABLE_TYPE aType)
static wxString ExpandURI(const wxString &aShortURI, const PROJECT &aProject)
std::mutex m_rowCacheMutex
void ClearLibOverride(const wxString &aTablePath, const wxString &aNickname)
Removes any override for a library that no longer needs one.
std::optional< LIBRARY_MANAGER_ADAPTER * > Adapter(LIBRARY_TABLE_TYPE aType) const
void applyLibOverrides(LIBRARY_TABLE &aTable)
Applies user overrides (disabled/hidden) to rows of a read-only nested table.
std::map< wxString, std::unique_ptr< LIBRARY_TABLE > > m_childTables
Map of full URI to table object for tables that are referenced by global or project tables.
void loadNestedTables(LIBRARY_TABLE &aTable)
std::map< ROW_CACHE_KEY, LIBRARY_TABLE_ROW * > m_rowCache
bool RemoveAdapter(LIBRARY_TABLE_TYPE aType, LIBRARY_MANAGER_ADAPTER *aAdapter)
void ReloadLibraryEntry(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
static bool UrisAreEquivalent(const wxString &aURI1, const wxString &aURI2)
std::mutex m_adaptersMutex
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
void ApplyLibOverrides(LIBRARY_TABLE &aTable)
Applies stored user overrides (disabled/hidden) to rows of a read-only table.
void RegisterAdapter(LIBRARY_TABLE_TYPE aType, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > &&aAdapter)
static wxString DefaultGlobalTablePath(LIBRARY_TABLE_TYPE aType)
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
static std::vector< LIBRARY_TABLE_TYPE > InvalidGlobalTables()
void createEmptyTable(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
void AbortAsyncLoads()
Abort any async library loading operations in progress.
std::optional< LIB_STATUS > LoadLibraryEntry(LIBRARY_TABLE_TYPE aType, const wxString &aNickname)
Synchronously loads the named library to LOADED state for the given type.
static bool GlobalTablesValid()
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_TABLE > > m_projectTables
std::optional< LIBRARY_TABLE_ROW * > FindRowByURI(LIBRARY_TABLE_TYPE aType, const wxString &aUri, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
void SetLibOverride(const wxString &aTablePath, const wxString &aNickname, bool aDisabled, bool aHidden)
Set a user override for a library in a read-only nested table.
void LoadProjectTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the project library tables in the given list, or all tables if no list is given
static bool CreateGlobalTable(LIBRARY_TABLE_TYPE aType, bool aPopulateDefaultLibraries)
void loadTables(const wxString &aTablePath, LIBRARY_TABLE_SCOPE aScope, std::vector< LIBRARY_TABLE_TYPE > aTablesToLoad={})
static wxString tableFileName(LIBRARY_TABLE_TYPE aType)
static bool IsPcmManagedRow(const LIBRARY_TABLE_ROW &aRow)
Return true if a library table row was added by the Plugin and Content Manager.
std::vector< LIBRARY_TABLE_ROW * > Rows(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH, bool aIncludeInvalid=false) const
Returns a flattened list of libraries of the given type.
void LoadGlobalTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the global library tables in the given list, or all tables if no list is given
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_TABLE > > m_tables
static wxString StockTableReferenceURI(LIBRARY_TABLE_TYPE aType)
static wxString StockTablePath(LIBRARY_TABLE_TYPE aType)
std::optional< LIBRARY_TABLE_ROW * > GetRow(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
void ProjectChanged()
Notify all adapters that the project has changed.
static bool IsTableValid(const wxString &aPath)
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > > m_adapters
void SetNickname(const wxString &aNickname)
void SetOk(bool aOk=true)
void SetType(const wxString &aType)
void SetErrorDescription(const wxString &aDescription)
std::map< std::string, UTF8 > GetOptionsMap() const
void SetDescription(const wxString &aDescription)
const wxString & Type() const
static const wxString TABLE_TYPE_NAME
void SetURI(const wxString &aUri)
const wxString & URI() const
const wxString & Nickname() const
bool IsReadOnly() const
Returns true if the underlying file exists but is not writable.
LIBRARY_TABLE_ROW & InsertRow()
Builds a new row and inserts it at the end of the table; returning a reference to the row.
const wxString & Path() const
LIBRARY_TABLE_SCOPE Scope() const
bool HasRow(const wxString &aNickname) const
bool HasRowWithURI(const wxString &aUri, const PROJECT &aProject, bool aSubstituted=false) const
Returns true if the given (fully-expanded) URI exists as a library in this table.
const std::deque< LIBRARY_TABLE_ROW > & Rows() const
static wxString GetStockTemplatesPath()
Gets the stock (install) templates path.
static wxString GetUserSettingsPath()
Return the user configuration path used to store KiCad's configuration files.
LIBRARY_TABLE * m_designBlockTable
std::set< LIBRARY_TABLE * > m_modified
LIBRARY_MANAGER & m_manager
std::set< LIBRARY_TABLE * > Modified() const
const PROJECT & m_project
PCM_LIB_TRAVERSER(const wxString &aBasePath, LIBRARY_MANAGER &aManager, const wxString &aPrefix)
void ensureUnique(LIBRARY_TABLE *aTable, const wxString &aBaseName, wxString &aNickname) const
LIBRARY_TABLE * m_symbolTable
wxDirTraverseResult OnDir(const wxString &dirPath) override
Handles footprint library and design block library directories, minimum nest level 3.
void addRowIfNecessary(LIBRARY_TABLE *aTable, const wxFileName &aSource, ADD_MODE aMode, int aExtensionLength)
LIBRARY_TABLE * m_fpTable
wxDirTraverseResult OnFile(const wxString &aFilePath) override
Handles symbol library files, minimum nest level 2.
size_t m_prefix_dir_count
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
virtual SETTINGS_MANAGER & GetSettingsManager() const
Container for project specific data.
T * GetAppSettings(const char *aFilename)
Return a handle to the a given settings by type.
static void ResolvePossibleSymlinks(wxFileName &aFilename)
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Functions related to environment variables, including help functions.
static const std::string KiCadDesignBlockLibPathExtension
static const std::string SymbolLibraryTableFileName
static const std::string DesignBlockLibraryTableFileName
static const std::string FootprintLibraryTableFileName
const wxChar *const traceLibraries
Flag to enable library table and library manager tracing.
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
LOAD_STATUS
Status of a library load managed by a library adapter.
tl::expected< ResultType, LIBRARY_ERROR > LIBRARY_RESULT
KICOMMON_API bool IsVersionedEnvVar(const wxString &aName, const wxString &aBaseName)
Test whether a name is a versioned KiCad environment variable for the given base, i....
KICOMMON_API std::optional< wxString > GetVersionedEnvVarValue(const std::map< wxString, ENV_VAR_ITEM > &aMap, const wxString &aBaseName)
Attempt to retrieve the value of a versioned environment variable, such as KICAD8_TEMPLATE_DIR.
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
PGM_BASE & Pgm()
The global program "get" accessor.
void StrNumSort(T &aList, CASE_SENSITIVITY aCaseSensitivity)
Sort a container of wxString objects, in place, using the StrNumCmp() function.
std::vector< LIBRARY_TABLE > tables
Storage for an actual loaded library (including library content owned by the plugin)
std::unique_ptr< IO_BASE > plugin
const LIBRARY_TABLE_ROW * row
The overall status of a loaded or loading library.
std::vector< std::vector< std::string > > table
wxString result
Test unit parsing edge cases and error handling.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().