25#include <magic_enum.hpp>
29#include <unordered_set>
40using namespace std::chrono_literals;
57 static std::mutex& registryLock = *
new std::mutex;
58 static std::map<wxString, std::unique_ptr<std::mutex>>& registry =
59 *
new std::map<wxString, std::unique_ptr<std::mutex>>;
61 std::lock_guard guard( registryLock );
62 std::unique_ptr<std::mutex>& slot = registry[aNickname];
65 slot = std::make_unique<std::mutex>();
80 std::vector<LIBRARY_TABLE_TYPE> aTablesToLoad )
99 wxCHECK_MSG(
false,
m_tables,
"Invalid scope passed to loadTables" );
103 std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>& aTarget = getTarget();
105 if( aTablesToLoad.size() == 0 )
110 aTarget.erase( type );
114 if( fn.IsFileReadable() )
116 std::unique_ptr<LIBRARY_TABLE>
table = std::make_unique<LIBRARY_TABLE>( fn, aScope );
118 if(
table->Type() != type )
120 auto actualName = magic_enum::enum_name(
table->Type() );
121 auto expectedName = magic_enum::enum_name( type );
122 wxLogWarning( wxS(
"Library table '%s' has type %s but expected %s; skipping" ),
124 wxString( actualName.data(), actualName.size() ),
125 wxString( expectedName.data(), expectedName.size() ) );
129 aTarget[type] = std::move(
table );
134 wxLogTrace(
traceLibraries,
"No library table found at %s", fn.GetFullPath() );
142 std::unordered_set<wxString> seenTables;
147 seenTables.insert( aTable.Path() );
156 wxFileName file(
ExpandURI( row.URI(),
Pgm().GetSettingsManager().
Prj() ) );
159 file.MakeAbsolute( wxFileName( aTable.Path() ).GetPath() );
162 wxString src = file.GetFullPath();
164 if( seenTables.contains( src ) )
166 wxLogTrace(
traceLibraries,
"Library table %s has already been loaded!", src );
168 row.SetErrorDescription(
_(
"A reference to this library table already exists" ) );
172 auto child = std::make_unique<LIBRARY_TABLE>( file, aRootTable.
Scope() );
174 processOneTable( *child );
179 row.SetErrorDescription( child->ErrorDescription() );
184 m_childTables.insert_or_assign( row.URI(), std::move( child ) );
189 processOneTable( aRootTable );
204 wxString tablePath = aTable.
Path();
211 const std::map<wxString, LIB_OVERRIDE>& overrides = it->second;
215 auto overIt = overrides.find( row.Nickname() );
217 if( overIt != overrides.end() )
219 row.SetDisabled( overIt->second.disabled );
220 row.SetHidden( overIt->second.hidden );
233 bool aDisabled,
bool aHidden )
238 wxCHECK( settings, );
240 if( !aDisabled && !aHidden )
246 settings->
m_LibOverrides[aTablePath][aNickname] = { aDisabled, aHidden };
255 wxCHECK( settings, );
262 tableIt->second.erase( aNickname );
264 if( tableIt->second.empty() )
276 default: wxCHECK(
false, wxEmptyString );
285 wxCHECK( !
m_tables.contains( aType ), );
294 wxFileName fn(
Pgm().GetSettingsManager().
Prj().GetProjectDirectory(),
tableFileName( aType ) );
306 const wxString& aPrefix ) :
312 wxFileName f( aBasePath,
"" );
318 .value_or(
nullptr );
322 wxDirTraverseResult
OnFile(
const wxString& aFilePath )
override
324 wxFileName file = wxFileName::FileName( aFilePath );
328 if( file.GetExt() == wxT(
"kicad_sym" )
335 return wxDIR_CONTINUE;
339 wxDirTraverseResult
OnDir(
const wxString& dirPath )
override
342 wxFileName dir = wxFileName::DirName( dirPath );
346 if( dirPath.EndsWith( wxS(
".pretty" ) )
352 else if( dirPath.EndsWith( designBlockExt )
359 return wxDIR_CONTINUE;
367 if( aTable->
HasRow( aNickname ) )
373 aNickname = wxString::Format(
"%s%s_%d",
m_lib_prefix, aBaseName, increment );
375 }
while( aTable->
HasRow( aNickname ) );
386 int aExtensionLength )
388 wxString versionedPath = wxString::Format( wxS(
"${%s}" ),
391 wxArrayString parts = aSource.GetDirs();
393 parts.Insert( versionedPath, 0 );
396 parts.Add( aSource.GetFullName() );
398 wxString libPath = wxJoin( parts,
'/' );
402 wxString
name = parts.Last().substr( 0, parts.Last().length() - aExtensionLength );
407 wxLogTrace(
traceLibraries,
"Manager: Adding PCM lib '%s' as '%s'", libPath, nickname );
419 wxLogTrace(
traceLibraries,
"Manager: Not adding existing PCM lib '%s'", libPath );
444 return fn.GetFullPath();
455 return fn.GetFullPath();
463 return wxString::Format( wxS(
"${%s}/%s" ), templateDirVar,
tableFileName( aType ) );
477 auto it = common->m_Env.vars.find( templateDirVar );
479 if( it != common->m_Env.vars.end() && it->second.GetDefinedExternally() )
489 if( wxFileName fn( aPath ); fn.IsFileReadable() )
509 std::vector<LIBRARY_TABLE_TYPE> invalidTables;
519 invalidTables.emplace_back( tableType );
522 return invalidTables;
531 table.SetType( aType );
532 table.Rows().clear();
536 if( aPopulateDefaultLibraries && defaultLib.IsFileReadable() )
544 else if( aPopulateDefaultLibraries )
546 auto typeName = magic_enum::enum_name( aType );
547 wxLogTrace(
traceLibraries,
"No stock library table for %s at '%s'; creating empty global table",
548 wxString( typeName.data(), typeName.size() ), defaultLib.GetFullPath() );
554 table.Format( &formatter );
573 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
574 adapter->GlobalTablesChanged( aTablesToLoad );
582 wxCHECK( settings, );
590 wxFileName d( *packagesPath,
"" );
595 wxDir dir( d.GetPath() );
597 dir.Traverse( traverser );
601 table->Save().map_error(
604 wxLogTrace(
traceLibraries, wxT(
"Warning: save failed after PCM auto-add: %s" ),
611 auto cleanupRemovedPCMLibraries =
619 auto toErase = std::ranges::remove_if(
table->Rows(),
622 if( !IsPcmManagedRow( aRow ) )
625 wxString path = GetFullURI( &aRow, true );
626 return !wxFileName::Exists( path );
629 bool hadRemovals = !toErase.empty();
630 table->Rows().erase( toErase.begin(), toErase.end() );
634 table->Save().map_error(
637 wxLogTrace(
traceLibraries, wxT(
"Warning: save failed after PCM auto-remove: %s" ),
669 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
670 adapter->ProjectChanged();
678 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
679 adapter->AbortAsyncLoad();
684 std::unique_ptr<LIBRARY_MANAGER_ADAPTER>&& aAdapter )
688 wxCHECK_MSG( !
m_adapters.contains( aType ), ,
"You should only register an adapter once!" );
726 wxCHECK_MSG(
false, std::nullopt,
"Table() requires a single scope" );
733 magic_enum::enum_name( aType ) );
745 if( !
Pgm().GetSettingsManager().
Prj().IsNullProject() )
760 bool aIncludeInvalid )
const
762 std::map<wxString, LIBRARY_TABLE_ROW*> rows;
763 std::vector<wxString> rowOrder;
765 std::list<std::ranges::ref_view<const std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>>> tables;
770 tables = { std::views::all(
m_tables ) };
785 std::function<void(
const std::unique_ptr<LIBRARY_TABLE>&,
bool parentHidden)> processTable =
786 [&](
const std::unique_ptr<LIBRARY_TABLE>& aTable,
const bool parentHidden )
788 if( aTable->Type() != aType )
791 if( aTable->IsOk() || aIncludeInvalid )
795 if( row.IsOk() || aIncludeInvalid )
799 row.SetHidden(
true );
814 if( !rows.contains( row.Nickname() ) )
815 rowOrder.emplace_back( row.Nickname() );
817 rows[ row.Nickname() ] = &row;
824 for(
const std::unique_ptr<LIBRARY_TABLE>&
table :
825 std::views::join( tables ) | std::views::values )
827 processTable(
table,
false );
830 std::vector<LIBRARY_TABLE_ROW*> ret;
832 for(
const wxString& row : rowOrder )
833 ret.emplace_back( rows[row] );
844 auto key = std::make_tuple( aType, aScope, aNickname );
852 if( row->Nickname() == aNickname )
855 m_rowCache[std::make_tuple( aType, aScope, aNickname )] = row;
865 const wxString& aUri,
881 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter =
Adapter( aType ); adapter )
882 ( *adapter )->ReloadLibraryEntry( aNickname, aScope );
887 const wxString& aNickname )
889 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter =
Adapter( aType ); adapter )
890 return ( *adapter )->LoadLibraryEntry( aNickname );
897 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
906 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
907 adapter->ProjectTablesChanged( aTablesToLoad );
910 if( wxFileName::IsDirReadable( aProjectPath ) )
925 wxLogTrace(
traceLibraries,
"New project path %s is not readable, not loading project tables", aProjectPath );
935 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
936 adapter->ProjectTablesReloaded( aTablesToLoad );
942 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
959 if( std::optional<const LIBRARY_TABLE_ROW*>
result =
GetRow( aType, aNickname ) )
981 return path.GetFullPath();
996 const wxString& uri = aRow.
URI();
998 if( !uri.StartsWith( wxS(
"${" ) ) )
1001 size_t end = uri.find( wxS(
'}' ) );
1003 if(
end == wxString::npos ||
end <= 2 )
1006 wxString varName = uri.SubString( 2,
end - 1 );
1014 if(
end + 1 >= uri.length() || uri[
end + 1] != wxS(
'/' ) )
1021 wxArrayString parts = wxSplit( uri.Mid(
end + 2 ),
'/',
'\0' );
1023 if( parts.size() < 3 )
1026 for(
const wxString& part : parts )
1028 if( part.IsEmpty() )
1032 wxString category = parts[0];
1033 wxString leaf = parts.Last();
1038 auto hasLibExtension = [&leaf](
const wxString& aExt )
1040 return leaf.length() > aExt.length() && leaf.EndsWith( aExt );
1043 if( category == wxS(
"symbols" ) )
1044 return hasLibExtension( wxS(
".kicad_sym" ) );
1046 if( category == wxS(
"footprints" ) )
1047 return hasLibExtension( wxS(
".pretty" ) );
1049 if( category == wxS(
"design_blocks" ) )
1051 static const wxString designBlockExt =
1054 return hasLibExtension( designBlockExt );
1064 if( aURI1.Find(
"://" ) != wxNOT_FOUND )
1067 return aURI1 == aURI2;
1071 const wxFileName fn1( aURI1 );
1072 const wxFileName fn2( aURI2 );
1137 bool me = aChangedTables.size() == 0;
1141 if( type ==
Type() )
1170 if( it->second.global_owner ==
this )
1180 bool me = aChangedTables.size() == 0;
1184 if( type ==
Type() )
1199 std::initializer_list<LIBRARY_TABLE_TYPE> aChangedTables )
1201 bool me = aChangedTables.size() == 0;
1205 if( type ==
Type() )
1224 [
this](
const auto& aEntry )
1240 if( loadedRow->
URI() == aRow.
URI() && loadedRow->
Type() == aRow.
Type() )
1257 std::optional<LIB_STATUS> status =
LoadOne( &lib );
1259 if( status.has_value() )
1263 if( status.value().error.has_value() )
1274 aRow.
SetOk(
false );
1299 return row->Nickname();
1302 return std::nullopt;
1308 std::vector<wxString> ret;
1309 std::vector<LIBRARY_TABLE_ROW*> rows =
m_manager.Rows(
Type() );
1311 wxLogTrace(
traceLibraries,
"GetLibraryNames: checking %zu rows from table", rows.size() );
1315 wxString nickname = row->Nickname();
1316 std::optional<const LIB_DATA*> loaded =
fetchIfLoaded( nickname );
1319 ret.emplace_back( nickname );
1324 wxLogTrace(
traceLibraries,
"GetLibraryNames: returning %zu of %zu libraries", ret.size(), rows.size() );
1331 std::optional<const LIB_DATA*> r =
fetchIfLoaded( aNickname );
1334 return !aCheckEnabled || !r.value()->row->Disabled();
1349 std::lock_guard pluginGuard(
pluginMutex( aNickname ) );
1367 if( std::optional<const LIB_DATA*> optRow =
fetchIfLoaded( aNickname ); optRow )
1368 return ( *optRow )->row->Description();
1370 return std::nullopt;
1375 bool aIncludeInvalid )
const
1389 const wxString& aUri,
1426 return std::nullopt;
1429 return loaded /
static_cast<float>( total );
1435 wxLogTrace(
traceLibraries,
"BlockUntilLoaded: entry, acquiring m_loadMutex" );
1436 std::unique_lock<std::mutex> asyncLock(
m_loadMutex );
1440 for(
const std::future<void>& future :
m_futures )
1443 wxLogTrace(
traceLibraries,
"BlockUntilLoaded: all futures complete, loadCount=%zu, loadTotal=%zu",
1474 return it->second.status.error;
1481 return it->second.status.error;
1484 return std::nullopt;
1490 std::vector<std::pair<wxString, LIB_STATUS>> ret;
1494 if( row->Disabled() )
1499 ret.emplace_back( std::make_pair( row->Nickname(), *
result ) );
1509 ret.emplace_back( std::make_pair( row->Nickname(),
1526 if( !errors.IsEmpty() )
1527 errors += wxS(
"\n" );
1529 errors += wxString::Format(
_(
"Library '%s': %s" ),
1530 nickname, status.error->message );
1545 return std::nullopt;
1557 std::shared_mutex& aMutex )
1559 bool wasLoaded =
false;
1562 std::unique_lock lock( aMutex );
1563 auto it = aTarget.find( aNickname );
1565 if( it != aTarget.end() && it->second.plugin )
1568 aTarget.erase( it );
1576 if( !
result.has_value() )
1578 wxLogTrace(
traceLibraries,
"ReloadLibraryEntry: failed to reload %s (%s): %s",
1579 aNickname, magic_enum::enum_name( aScopeToReload ),
1580 result.error().message );
1612 std::lock_guard pluginGuard(
pluginMutex( aNickname ) );
1629 std::lock_guard pluginGuard(
pluginMutex( aNickname ) );
1638 wxLogTrace(
traceLibraries,
"CreateLibrary: IO_ERROR for %s: %s",
1639 aNickname, ioe.
What() );
1642 catch(
const std::exception& e )
1644 wxLogTrace(
traceLibraries,
"CreateLibrary: std::exception for %s: %s",
1645 aNickname, e.what() );
1650 wxLogTrace(
traceLibraries,
"CreateLibrary: library row '%s' not found", aNickname );
1671 return std::nullopt;
1683 return std::nullopt;
1687 return std::nullopt;
1701 return std::nullopt;
1713 return std::nullopt;
1717 return std::nullopt;
1723 std::map<wxString, LIB_DATA>& aTarget,
1724 std::shared_mutex& aMutex )
1726 bool present =
false;
1729 std::shared_lock lock( aMutex );
1730 present = aTarget.contains( aNickname ) && aTarget.at( aNickname ).plugin;
1738 wxLogTrace(
traceLibraries,
"Library %s (%s) not yet loaded, will attempt...",
1739 aNickname, magic_enum::enum_name( aScope ) );
1743 std::unique_lock lock( aMutex );
1746 aTarget[ row->
Nickname() ].row = row;
1750 aTarget[ row->
Nickname() ].global_owner =
this;
1752 return &aTarget.at( aNickname );
1756 return tl::unexpected(
plugin.error() );
1763 std::shared_lock lock( aMutex );
1764 return &aTarget.at( aNickname );
1781 wxString msg = wxString::Format(
_(
"Library %s not found" ), aNickname );
1792 return it->second.status;
1799 return it->second.status;
1802 return std::nullopt;
1808 std::unique_lock<std::mutex> asyncLock(
m_loadMutex, std::try_to_lock );
1814 []( std::future<void>& aFuture )
1816 return aFuture.valid()
1817 && aFuture.wait_for( 0s ) == std::future_status::ready;
1822 wxLogTrace(
traceLibraries,
"Cannot AsyncLoad, futures from a previous call remain!" );
1826 std::vector<LIBRARY_TABLE_ROW*> rows =
m_manager.Rows(
Type() );
1833 wxLogTrace(
traceLibraries,
"AsyncLoad: no libraries left to load; exiting" );
1840 [&](
const wxString& aLib, std::map<wxString, LIB_DATA>& aMap, std::shared_mutex& aMutex )
1842 std::shared_lock lock( aMutex );
1844 if(
auto it = aMap.find( aLib ); it != aMap.end() )
1846 LOAD_STATUS status = it->second.status.load_status;
1864 auto workQueue = std::make_shared<std::vector<LOAD_WORK>>();
1865 workQueue->reserve( rows.size() );
1869 wxString nickname = row->Nickname();
1884 workQueue->emplace_back( LOAD_WORK{ nickname, scope,
getUri( row ) } );
1887 if( workQueue->empty() )
1889 wxLogTrace(
traceLibraries,
"AsyncLoad: all libraries already loaded; exiting" );
1896 size_t poolSize =
tp.get_thread_count();
1897 size_t maxLoadThreads = std::max<size_t>( 1, poolSize > 2 ? poolSize - 2 : 1 );
1898 size_t numWorkers = std::min( maxLoadThreads, workQueue->size() );
1900 auto workIndex = std::make_shared<std::atomic<size_t>>( 0 );
1902 wxLogTrace(
traceLibraries,
"AsyncLoad: %zu libraries to load, using %zu worker threads (pool has %zu)",
1903 workQueue->size(), numWorkers, poolSize );
1905 for(
size_t w = 0; w < numWorkers; ++w )
1908 [
this, workQueue, workIndex]()
1912 if( m_abort.load() )
1915 size_t idx = workIndex->fetch_add( 1 );
1917 if( idx >= workQueue->size() )
1920 const LOAD_WORK& work = ( *workQueue )[idx];
1921 LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( work.nickname );
1923 if( result.has_value() )
1925 LIB_DATA* lib = *result;
1930 std::unique_lock lock(
1931 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
1933 : m_librariesMutex );
1934 lib->status.load_status = LOAD_STATUS::LOADING;
1937 enumerateLibrary( lib, work.uri );
1940 std::unique_lock lock(
1941 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
1943 : m_librariesMutex );
1944 lib->status.load_status = LOAD_STATUS::LOADED;
1947 catch( IO_ERROR& e )
1949 std::unique_lock lock(
1950 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
1952 : m_librariesMutex );
1953 lib->status.load_status = LOAD_STATUS::LOAD_ERROR;
1954 lib->status.error = LIBRARY_ERROR( { e.What() } );
1955 wxLogTrace( traceLibraries,
"%s: plugin threw exception: %s",
1956 work.nickname, e.What() );
1961 std::unique_lock lock(
1962 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
1964 : m_librariesMutex );
1966 std::map<wxString, LIB_DATA>& target =
1967 ( work.scope == LIBRARY_TABLE_SCOPE::GLOBAL ) ? globalLibs()
1970 target[work.nickname].status = LIB_STATUS( {
1971 .load_status = LOAD_STATUS::LOAD_ERROR,
1972 .error = result.error()
1978 }, BS::pr::lowest ) );
1981 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.
static std::mutex & pluginMutex(const wxString &aNickname)
Serializes access to a library's shared plugin instance so its single mutable cache is not raced by c...
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.
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().