KiCad PCB EDA Suite
Loading...
Searching...
No Matches
library_manager.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 * @author Jon Evans <[email protected]>
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#ifndef LIBRARY_MANAGER_H
22#define LIBRARY_MANAGER_H
23
24#include <future>
25#include <memory>
26#include <mutex>
27#include <shared_mutex>
28
29#include <kicommon.h>
30#include <ki_error.h>
32#include <io/io_base.h>
33
34
35class LIBRARY_MANAGER;
37class PROJECT;
38
39
48
51{
53 std::optional<LIBRARY_ERROR> error = std::nullopt;
54};
55
56
59{
61 std::unique_ptr<IO_BASE> plugin;
62 const LIBRARY_TABLE_ROW* row = nullptr;
64
65 // For an entry in the process-wide globalLibs() cache, the adapter that loaded it and so owns
66 // the lifetime of row. Its destructor evicts the entry; identity is by adapter, not by the
67 // reusable row pointer.
69
70 int modify_hash = -1;
71 std::vector<wxString> available_fields_cache;
72};
73
74
80{
81public:
90
92
93 LIBRARY_MANAGER& Manager() const;
94
96 virtual LIBRARY_TABLE_TYPE Type() const = 0;
97
100
102 std::optional<LIBRARY_TABLE*> ProjectTable() const;
103
104 std::optional<wxString> FindLibraryByURI( const wxString& aURI ) const;
105
107 std::vector<wxString> GetLibraryNames() const;
108
116 bool HasLibrary( const wxString& aNickname, bool aCheckEnabled = false ) const;
117
119 bool DeleteLibrary( const wxString& aNickname );
120
121 std::optional<wxString> GetLibraryDescription( const wxString& aNickname ) const;
122
124 std::vector<LIBRARY_TABLE_ROW*> Rows( LIBRARY_TABLE_SCOPE aScope = LIBRARY_TABLE_SCOPE::BOTH,
125 bool aIncludeInvalid = false ) const;
126
128 std::optional<LIBRARY_TABLE_ROW*> GetRow( const wxString& aNickname,
130
132 std::optional<LIBRARY_TABLE_ROW*> FindRowByURI( const wxString& aUri,
134
136 virtual void ProjectChanged();
137
139 void GlobalTablesChanged( std::initializer_list<LIBRARY_TABLE_TYPE> aChangedTables = {} );
140
147 void ProjectTablesChanged( std::initializer_list<LIBRARY_TABLE_TYPE> aChangedTables = {} );
148
153 void ProjectTablesReloaded( std::initializer_list<LIBRARY_TABLE_TYPE> aChangedTables = {} );
154
155 void CheckTableRow( LIBRARY_TABLE_ROW& aRow );
156
158 void AsyncLoad();
159
160 virtual std::optional<LIB_STATUS> LoadOne( LIB_DATA* aLib ) = 0;
161
163 virtual std::optional<LIB_STATUS> CheckLibrary( LIB_DATA* aLib ) { return LoadOne( aLib ); }
164
173 std::optional<float> AsyncLoadProgress() const;
174
175 void BlockUntilLoaded();
176
179 void AbortAsyncLoad();
180
181 bool IsLibraryLoaded( const wxString& aNickname );
182
184 std::optional<LIB_STATUS> GetLibraryStatus( const wxString& aNickname ) const;
185
187 std::vector<std::pair<wxString, LIB_STATUS>> GetLibraryStatuses() const;
188
190 std::vector<KI_ERROR> GetLibraryLoadErrors() const;
191
193 void ReloadLibraryEntry( const wxString& aNickname,
195
198 std::optional<LIB_STATUS> LoadLibraryEntry( const wxString& aNickname );
199
201 virtual bool IsWritable( const wxString& aNickname ) const;
202
204 bool CreateLibrary( const wxString& aNickname );
205
210 virtual bool SupportsConfigurationDialog( const LIBRARY_TABLE_ROW& aRow ) const { return false; }
211
217 wxWindow* aParent )
218 {
219 return wxID_CANCEL;
220 }
221
222 virtual std::optional<LIBRARY_ERROR> LibraryError( const wxString& aNickname ) const;
223
224protected:
225 virtual std::map<wxString, LIB_DATA>& globalLibs() = 0;
226 virtual std::map<wxString, LIB_DATA>& globalLibs() const = 0;
227 virtual std::shared_mutex& globalLibsMutex() = 0;
228 virtual std::shared_mutex& globalLibsMutex() const = 0;
229
236 virtual void enumerateLibrary( LIB_DATA* aLib, const wxString& aUri ) = 0;
237
238 wxString getUri( const LIBRARY_TABLE_ROW* aRow ) const;
239
240 std::optional<const LIB_DATA*> fetchIfLoaded( const wxString& aNickname ) const;
241
242 std::optional<LIB_DATA*> fetchIfLoaded( const wxString& aNickname );
243
245 LIBRARY_RESULT<LIB_DATA*> loadIfNeeded( const wxString& aNickname );
246
247 LIBRARY_RESULT<LIB_DATA*> loadFromScope( const wxString& aNickname,
248 LIBRARY_TABLE_SCOPE aScope,
249 std::map<wxString, LIB_DATA>& aTarget,
250 std::shared_mutex& aMutex );
251
259
261 void abortLoad();
262
270 void resetProjectCache();
271
274
275 virtual IO_BASE* plugin( const LIB_DATA* aRow ) = 0;
276
284 static std::recursive_mutex& pluginMutex( const wxString& aNickname );
285
287
288 // The actual library content is held in an associated IO plugin
289 std::map<wxString, LIB_DATA> m_libraries;
290
291 mutable std::shared_mutex m_librariesMutex;
292
293 std::atomic_bool m_abort;
294 std::vector<std::future<void>> m_futures;
295
296 std::atomic<size_t> m_loadCount{ 0 };
297 std::atomic<size_t> m_loadTotal{ 0 };
298 std::mutex m_loadMutex;
299};
300
301
303{
304public:
306 explicit LIBRARY_MANAGER( const PROJECT* aProject = nullptr );
307
308 const PROJECT& Project() const;
309 bool IsProjectScoped() const { return m_project != nullptr; }
310
312
315
316 static wxString DefaultGlobalTablePath( LIBRARY_TABLE_TYPE aType );
317
318 static wxString StockTablePath( LIBRARY_TABLE_TYPE aType );
319
327 static wxString StockTableTokenizedURI( LIBRARY_TABLE_TYPE aType );
328
339 static wxString StockTableReferenceURI( LIBRARY_TABLE_TYPE aType );
340
341 static bool IsTableValid( const wxString& aPath );
342
344 static bool GlobalTablesValid();
345
347 static std::vector<LIBRARY_TABLE_TYPE> InvalidGlobalTables();
348
349 static bool CreateGlobalTable( LIBRARY_TABLE_TYPE aType, bool aPopulateDefaultLibraries );
350
352 void LoadGlobalTables( std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad = {} );
353
355 void LoadProjectTables( std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad = {} );
356
357 void ReloadTables( LIBRARY_TABLE_SCOPE aScope, std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad = {} );
358
360 void ProjectChanged();
361
365 void AbortAsyncLoads();
366
367 void RegisterAdapter( LIBRARY_TABLE_TYPE aType,
368 std::unique_ptr<LIBRARY_MANAGER_ADAPTER>&& aAdapter );
369
370 bool RemoveAdapter( LIBRARY_TABLE_TYPE aType, LIBRARY_MANAGER_ADAPTER* aAdapter );
371
372 std::optional<LIBRARY_MANAGER_ADAPTER*> Adapter( LIBRARY_TABLE_TYPE aType ) const;
373
382 std::optional<LIBRARY_TABLE*> Table( LIBRARY_TABLE_TYPE aType,
383 LIBRARY_TABLE_SCOPE aScope );
384
394 std::vector<LIBRARY_TABLE_ROW*> Rows( LIBRARY_TABLE_TYPE aType,
396 bool aIncludeInvalid = false ) const;
397
405 std::optional<LIBRARY_TABLE_ROW*> GetRow( LIBRARY_TABLE_TYPE aType, const wxString &aNickname,
407
408 std::optional<LIBRARY_TABLE_ROW*> FindRowByURI( LIBRARY_TABLE_TYPE aType, const wxString &aUri,
410
412 void ReloadLibraryEntry( LIBRARY_TABLE_TYPE aType, const wxString& aNickname,
414
417 std::optional<LIB_STATUS> LoadLibraryEntry( LIBRARY_TABLE_TYPE aType,
418 const wxString& aNickname );
419
420 void LoadProjectTables( const wxString& aProjectPath,
421 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad = {} );
422
432 std::optional<wxString> GetFullURI( LIBRARY_TABLE_TYPE aType, const wxString& aNickname,
433 bool aSubstituted = false );
434
435 static wxString GetFullURI( const LIBRARY_TABLE_ROW* aRow, bool aSubstituted = false,
436 const PROJECT* aProject = nullptr );
437
438 static wxString ExpandURI( const wxString& aShortURI, const PROJECT& aProject );
439
440 static bool UrisAreEquivalent( const wxString& aURI1, const wxString& aURI2 );
441
453 static bool IsPcmManagedRow( const LIBRARY_TABLE_ROW& aRow );
454
458 void ApplyLibOverrides( LIBRARY_TABLE& aTable );
459
468 void SetLibOverride( const wxString& aTablePath, const wxString& aNickname,
469 bool aDisabled, bool aHidden );
470
472 void ClearLibOverride( const wxString& aTablePath, const wxString& aNickname );
473
474private:
475 void loadTables( const wxString& aTablePath, LIBRARY_TABLE_SCOPE aScope,
476 std::vector<LIBRARY_TABLE_TYPE> aTablesToLoad = {} );
477
478 void loadNestedTables( LIBRARY_TABLE& aTable );
479
481 void applyLibOverrides( LIBRARY_TABLE& aTable );
482
483 static wxString tableFileName( LIBRARY_TABLE_TYPE aType );
484
485 void createEmptyTable( LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope );
486
487 const PROJECT* const m_project;
488 std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>> m_tables;
489
491 std::map<wxString, std::unique_ptr<LIBRARY_TABLE>> m_childTables;
492
493 // TODO: support multiple projects
494 std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>> m_projectTables;
495
496 std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_MANAGER_ADAPTER>> m_adapters;
497
498 mutable std::mutex m_adaptersMutex;
499
500 typedef std::tuple<LIBRARY_TABLE_TYPE, LIBRARY_TABLE_SCOPE, wxString> ROW_CACHE_KEY;
501
502 std::map<ROW_CACHE_KEY, LIBRARY_TABLE_ROW*> m_rowCache;
503 mutable std::mutex m_rowCacheMutex;
504};
505
506#endif //LIBRARY_MANAGER_H
The interface used by the classes that actually can load IO plugins for the different parts of KiCad ...
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::shared_mutex & globalLibsMutex() const =0
std::optional< LIBRARY_TABLE * > ProjectTable() const
Retrieves the project library table for this adapter type, or nullopt if one doesn't exist.
virtual void enumerateLibrary(LIB_DATA *aLib, const wxString &aUri)=0
Override in derived class to perform library-specific enumeration.
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.
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.
wxString getUri(const LIBRARY_TABLE_ROW *aRow) const
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.
std::optional< wxString > FindLibraryByURI(const wxString &aURI) const
virtual bool SupportsConfigurationDialog(const LIBRARY_TABLE_ROW &aRow) const
Configuration works from the row itself, so libraries that failed to load or are not yet committed to...
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)
LIBRARY_RESULT< LIB_DATA * > loadFromScope(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope, std::map< wxString, LIB_DATA > &aTarget, std::shared_mutex &aMutex)
virtual std::optional< LIB_STATUS > CheckLibrary(LIB_DATA *aLib)
Validates that a library is loadable. May not necessarily load the library!
std::vector< std::future< void > > m_futures
static std::recursive_mutex & pluginMutex(const wxString &aNickname)
Serializes access to a library's shared plugin instance so its single mutable cache is not raced by c...
virtual int ShowConfigurationDialog(const LIBRARY_TABLE_ROW &aRow, LIBRARY_TABLE_SCOPE aScope, wxWindow *aParent)
Shows the plugin's configuration dialog for a library table row.
std::atomic< size_t > m_loadTotal
virtual std::map< wxString, LIB_DATA > & globalLibs() const =0
std::atomic< size_t > m_loadCount
LIBRARY_MANAGER & m_manager
std::optional< const LIB_DATA * > fetchIfLoaded(const wxString &aNickname) const
static wxString StockTableTokenizedURI(LIBRARY_TABLE_TYPE aType)
const PROJECT *const m_project
std::mutex m_rowCacheMutex
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.
std::map< ROW_CACHE_KEY, LIBRARY_TABLE_ROW * > m_rowCache
const PROJECT & Project() const
std::mutex m_adaptersMutex
static wxString DefaultGlobalTablePath(LIBRARY_TABLE_TYPE aType)
static std::vector< LIBRARY_TABLE_TYPE > InvalidGlobalTables()
static bool GlobalTablesValid()
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_TABLE > > m_projectTables
LIBRARY_MANAGER(const LIBRARY_MANAGER &)=delete
bool IsProjectScoped() const
static bool CreateGlobalTable(LIBRARY_TABLE_TYPE aType, bool aPopulateDefaultLibraries)
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
LIBRARY_MANAGER & operator=(const LIBRARY_MANAGER &)=delete
std::tuple< LIBRARY_TABLE_TYPE, LIBRARY_TABLE_SCOPE, wxString > ROW_CACHE_KEY
static wxString StockTableReferenceURI(LIBRARY_TABLE_TYPE aType)
static wxString StockTablePath(LIBRARY_TABLE_TYPE aType)
static bool IsTableValid(const wxString &aPath)
LIBRARY_MANAGER(const PROJECT *aProject=nullptr)
An explicit project is borrowed until this manager and its adapters are destroyed.
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > > m_adapters
Container for project specific data.
Definition project.h:63
void ProjectChanged() override
#define KICOMMON_API
Definition kicommon.h:27
LOAD_STATUS
Status of a library load managed by a library adapter.
tl::expected< ResultType, LIBRARY_ERROR > LIBRARY_RESULT
LIBRARY_TABLE_TYPE
LIBRARY_TABLE_SCOPE
Storage for an actual loaded library (including library content owned by the plugin)
std::vector< wxString > available_fields_cache
LIB_STATUS status
std::unique_ptr< IO_BASE > plugin
Never destroyed while holding the map's mutex; a plugin's worker thread may be blocked on it.
const LIBRARY_MANAGER_ADAPTER * global_owner
const LIBRARY_TABLE_ROW * row
The overall status of a loaded or loading library.
std::optional< LIBRARY_ERROR > error
LOAD_STATUS load_status