KiCad PCB EDA Suite
Loading...
Searching...
No Matches
symbol_library_adapter.cpp
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#include <magic_enum.hpp>
22#include <chrono>
23#include <memory>
24
25#include <common.h>
26#include <dialog_shim.h>
27#include <ki_exception.h>
28#include <wx/log.h>
29
30#include <lib_symbol.h>
32
33#include <env_vars.h>
34#include <pgm_base.h>
35#include <project.h>
36#include <thread_pool.h>
37#include <trace_helpers.h>
39
40using namespace std::chrono_literals;
41
42
43const char* SYMBOL_LIBRARY_ADAPTER::PropPowerSymsOnly = "pwr_sym_only";
44const char* SYMBOL_LIBRARY_ADAPTER::PropNonPowerSymsOnly = "non_pwr_sym_only";
45
47
49
50
55
56
61
62
67
68
70{
71 SCH_IO* ret = dynamic_cast<SCH_IO*>( aRow->plugin.get() );
72 wxCHECK( aRow->plugin && ret, nullptr );
73 return ret;
74}
75
76
77void SYMBOL_LIBRARY_ADAPTER::enumerateLibrary( LIB_DATA* aLib, const wxString& aUri )
78{
79 wxArrayString dummyList;
80
81 std::lock_guard pluginGuard( pluginMutex( aLib->row->Nickname() ) );
82
83 std::map<std::string, UTF8> options = aLib->row->GetOptionsMap();
84 schplugin( aLib )->EnumerateSymbolLib( dummyList, aUri, &options );
85}
86
87
88std::optional<LIB_STATUS> SYMBOL_LIBRARY_ADAPTER::LoadOne( LIB_DATA* aLib )
89{
91
92 std::lock_guard pluginGuard( pluginMutex( aLib->row->Nickname() ) );
93
94 std::map<std::string, UTF8> options = aLib->row->GetOptionsMap();
95
96 try
97 {
98 wxArrayString dummyList;
99 schplugin( aLib )->EnumerateSymbolLib( dummyList, getUri( aLib->row ), &options );
100 wxLogTrace( traceLibraries, "Sym: %s: library enumerated %zu items", aLib->row->Nickname(), dummyList.size() );
102 }
103 catch( IO_ERROR& e )
104 {
106 aLib->status.error = LIBRARY_ERROR( e.Problem(), e.Where() );
107 wxLogTrace( traceLibraries, "Sym: %s: plugin threw exception: %s", aLib->row->Nickname(), e.What() );
108 }
109
110 return aLib->status;
111}
112
113
114std::optional<LIB_STATUS> SYMBOL_LIBRARY_ADAPTER::CheckLibrary( LIB_DATA* aLib )
115{
117
118 std::lock_guard pluginGuard( pluginMutex( aLib->row->Nickname() ) );
119
120 std::map<std::string, UTF8> options = aLib->row->GetOptionsMap();
121
122 try
123 {
124 schplugin( aLib )->CheckLibrary( getUri( aLib->row ), &options );
126 }
127 catch( IO_ERROR& e )
128 {
130 aLib->status.error = LIBRARY_ERROR( e.Problem(), e.Where() );
131 wxLogTrace( traceLibraries, "Sym: %s: library check failed: %s", aLib->row->Nickname(), e.What() );
132 }
133
134 return aLib->status;
135}
136
137
138std::optional<LIB_STATUS> SYMBOL_LIBRARY_ADAPTER::LoadOne( const wxString& nickname )
139{
141
142 if( result.has_value() )
143 return LoadOne( *result );
144
145 return LIB_STATUS { .load_status = LOAD_STATUS::LOAD_ERROR,
146 .error = LIBRARY_ERROR( { result.error() } ) };
147}
148
149
151{
152 SCH_IO_MGR::SCH_FILE_T type = SCH_IO_MGR::EnumFromStr( row->Type() );
153
154 if( type == SCH_IO_MGR::SCH_NESTED_TABLE )
155 {
156 wxString msg;
157 wxFileName fileName( m_manager.GetFullURI( row, true, &m_manager.Project() ) );
158
159 if( fileName.FileExists() )
160 return tl::unexpected( LIBRARY_TABLE_OK() );
161 else
162 msg = wxString::Format( _( "Nested table '%s' not found." ), row->URI() );
163
164 return tl::unexpected( LIBRARY_ERROR( msg ) );
165 }
166 else if( type == SCH_IO_MGR::SCH_FILE_UNKNOWN )
167 {
168 wxLogTrace( traceLibraries, "Sym: Plugin type %s is unknown!", row->Type() );
169 wxString msg = wxString::Format( _( "Unknown library type %s " ), row->Type() );
170 return tl::unexpected( LIBRARY_ERROR( msg ) );
171 }
172
173 SCH_IO* plugin = SCH_IO_MGR::FindPlugin( type );
174 wxCHECK( plugin, tl::unexpected( LIBRARY_ERROR( _( "Internal error" ) ) ) );
175
176 plugin->SetLibraryManagerAdapter( this );
177
178 wxLogTrace( traceLibraries, "Sym: Library %s (%s) plugin created", row->Nickname(),
179 magic_enum::enum_name( row->Scope() ) );
180
181 return plugin;
182}
183
184
185std::vector<LIB_SYMBOL*> SYMBOL_LIBRARY_ADAPTER::GetSymbols( const wxString& aNickname, SYMBOL_TYPE aType )
186{
187 std::vector<LIB_SYMBOL*> symbols;
188
189 std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname );
190
191 if( !maybeLib )
192 return symbols;
193
194 const LIB_DATA* lib = *maybeLib;
195
196 std::lock_guard pluginGuard( pluginMutex( aNickname ) );
197
198 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
199
200 if( aType == SYMBOL_TYPE::POWER_ONLY )
201 options[PropPowerSymsOnly] = "";
202
203 try
204 {
205 schplugin( lib )->EnumerateSymbolLib( symbols, getUri( lib->row ), &options );
206 }
207 catch( IO_ERROR& e )
208 {
209 wxLogTrace( traceLibraries, "Sym: Exception enumerating library %s: %s", lib->row->Nickname(), e.What() );
210 }
211
212 for( LIB_SYMBOL* symbol : symbols )
213 {
214 LIB_ID id = symbol->GetLibId();
215 id.SetLibNickname( lib->row->Nickname() );
216 symbol->SetLibId( id );
217 }
218
219 return symbols;
220}
221
222
223std::vector<wxString> SYMBOL_LIBRARY_ADAPTER::GetSymbolNames( const wxString& aNickname, SYMBOL_TYPE aType )
224{
225 wxArrayString namesAS;
226 std::vector<wxString> names;
227
228 if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
229 {
230 const LIB_DATA* lib = *maybeLib;
231
232 std::lock_guard pluginGuard( pluginMutex( aNickname ) );
233
234 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
235
236 if( aType == SYMBOL_TYPE::POWER_ONLY )
237 options[PropPowerSymsOnly] = "";
238
239 try
240 {
241 schplugin( lib )->EnumerateSymbolLib( namesAS, getUri( lib->row ), &options );
242 }
243 catch( const IO_ERROR& e )
244 {
245 wxLogTrace( traceLibraries, "Sym: Exception enumerating library %s: %s",
246 lib->row->Nickname(), e.What() );
247 }
248 }
249
250 for( const wxString& name : namesAS )
251 names.emplace_back( name );
252
253 return names;
254}
255
256
257LIB_SYMBOL* SYMBOL_LIBRARY_ADAPTER::LoadSymbol( const wxString& aNickname, const wxString& aName )
258{
259 if( std::optional<const LIB_DATA*> lib = fetchIfLoaded( aNickname ) )
260 {
261 std::lock_guard pluginGuard( pluginMutex( aNickname ) );
262
263 if( LIB_SYMBOL* symbol = schplugin( *lib )->LoadSymbol( getUri( ( *lib )->row ), aName ) )
264 {
265 LIB_ID id = symbol->GetLibId();
266 id.SetLibNickname( ( *lib )->row->Nickname() );
267 symbol->SetLibId( id );
268 return symbol;
269 }
270 }
271 else
272 {
273 wxLogTrace( traceLibraries, "LoadSymbol: requested library %s not loaded", aNickname );
274 }
275
276 return nullptr;
277}
278
279
281 std::unique_ptr<LIB_SYMBOL> aSymbol, bool aOverwrite )
282{
283 wxCHECK( aSymbol, SAVE_SKIPPED );
284
285 LIBRARY_RESULT<LIB_DATA*> libResult = loadIfNeeded( aNickname );
286
287 if( !libResult.has_value() )
288 {
289 wxLogTrace( traceLibraries, "SaveSymbol: unable to load library %s: %s", aNickname,
290 libResult.error().message );
291 return SAVE_SKIPPED;
292 }
293
294 LIB_DATA* lib = *libResult;
295
296 if( !lib )
297 {
298 wxLogTrace( traceLibraries, "SaveSymbol: library %s not found", aNickname );
299 return SAVE_SKIPPED;
300 }
301
302 SCH_IO* plugin = schplugin( lib );
303 wxCHECK( plugin, SAVE_SKIPPED );
304
305 const wxString symbolName = aSymbol->GetName();
306
307 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
308
309 if( !aOverwrite )
310 {
311 try
312 {
313 LIB_SYMBOL* existing = plugin->LoadSymbol( getUri( lib->row ), symbolName, &options );
314
315 if( existing )
316 return SAVE_SKIPPED;
317 }
318 catch( const IO_ERROR& e )
319 {
320 wxLogTrace( traceLibraries, "SaveSymbol: error checking for existing symbol %s:%s: %s", aNickname,
321 symbolName, e.What() );
322 return SAVE_SKIPPED;
323 }
324 }
325
326 try
327 {
328 plugin->SaveSymbol( getUri( lib->row ), std::move( aSymbol ), &options );
329 }
330 catch( const IO_ERROR& e )
331 {
332 wxLogTrace( traceLibraries, "SaveSymbol: error saving %s:%s: %s", aNickname, symbolName, e.What() );
333 return SAVE_SKIPPED;
334 }
335
336 return SAVE_OK;
337}
338
339
340void SYMBOL_LIBRARY_ADAPTER::DeleteSymbol( const wxString& aNickname, const wxString& aSymbolName )
341{
342 wxCHECK_MSG( false, /* void */, "Unimplemented!" );
343}
344
345
347{
348 // Route through fetchIfLoaded() so LOAD_ERROR sentinel entries, which carry a null
349 // plugin, are filtered out instead of dereferenced.
350 if( std::optional<const LIB_DATA*> lib = fetchIfLoaded( aLib ) )
351 return ( *lib )->plugin->IsLibraryWritable( getUri( ( *lib )->row ) );
352
353 return false;
354}
355
356
357std::vector<wxString> SYMBOL_LIBRARY_ADAPTER::GetAvailableExtraFields( const wxString& aNickname )
358{
359 std::vector<wxString> fields;
360
361 if( std::optional<LIB_DATA*> result = fetchIfLoaded( aNickname ) )
362 {
363 LIB_DATA* rowData = *result;
364
365 int hash = schplugin( rowData )->GetModifyHash();
366
367 if( hash != rowData->modify_hash )
368 {
369 rowData->modify_hash = hash;
371 }
372
373 return rowData->available_fields_cache;
374 }
375
376 return fields;
377}
378
379
380bool SYMBOL_LIBRARY_ADAPTER::SupportsSubLibraries( const wxString& aNickname ) const
381{
382 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( aNickname ) )
383 {
384 const LIB_DATA* rowData = *result;
385 return schplugin( rowData )->SupportsSubLibraries();
386 }
387
388 return false;
389}
390
391
392std::vector<SUB_LIBRARY> SYMBOL_LIBRARY_ADAPTER::GetSubLibraries( const wxString& aNickname ) const
393{
394 std::vector<SUB_LIBRARY> ret;
395
396 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( aNickname ) )
397 {
398 const LIB_DATA* rowData = *result;
399
400 try
401 {
402 std::vector<wxString> names;
403 schplugin( rowData )->GetSubLibraryNames( names );
404
405 for( const wxString& name : names )
406 {
407 ret.emplace_back( SUB_LIBRARY {
408 .nickname = name,
409 .description = schplugin( rowData )->GetSubLibraryDescription( name ) } );
410 }
411 }
412 catch( const IO_ERROR& e )
413 {
414 wxLogTrace( traceLibraries, "Sym: Exception getting sub-libraries for %s: %s",
415 aNickname, e.What() );
416 }
417 }
418
419 return ret;
420}
421
422
423bool SYMBOL_LIBRARY_ADAPTER::SupportsConfigurationDialog( const wxString& aNickname ) const
424{
425 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( aNickname ) )
426 return ( *result )->plugin->SupportsConfigurationDialog();
427
428 return false;
429}
430
431
432int SYMBOL_LIBRARY_ADAPTER::ShowConfigurationDialog( const wxString& aNickname, wxWindow* aParent ) const
433{
434 std::optional<const LIB_DATA*> optRow = fetchIfLoaded( aNickname );
435
436 if( !optRow )
437 return wxID_CANCEL;
438
439 if( !( *optRow )->plugin->SupportsConfigurationDialog() )
440 return wxID_CANCEL;
441
442 DIALOG_SHIM* dialog = ( *optRow )->plugin->CreateConfigurationDialog( aParent );
443
444 return dialog->ShowModal();
445}
446
447
449{
450 int hash = 0;
451
452 for( const LIBRARY_TABLE_ROW* row : m_manager.Rows( Type() ) )
453 {
454 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( row->Nickname() ) )
455 {
456 const LIB_DATA* rowData = *result;
457 wxCHECK2( rowData->row, continue );
458 hash += schplugin( rowData )->GetModifyHash();
459 }
460 }
461
462 return hash;
463}
464
465
466std::optional<int> SYMBOL_LIBRARY_ADAPTER::GetLibraryModifyHash( const wxString& aNickname ) const
467{
468 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( aNickname ) )
469 {
470 const LIB_DATA* rowData = *result;
471 wxCHECK( rowData->row, std::nullopt );
472 return schplugin( rowData )->GetModifyHash();
473 }
474
475 return std::nullopt;
476}
const char * name
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition dialog_shim.h:80
int ShowModal() override
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()
virtual const wxString Problem() const
what was the problem?
virtual const wxString Where() const
where did the Problem() occur?
A wrapper for static data that should not be destroyed at program exit.
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.
wxString getUri(const LIBRARY_TABLE_ROW *aRow) const
LIBRARY_RESULT< LIB_DATA * > loadIfNeeded(const wxString &aNickname)
Fetches a loaded library, triggering a load of that library if it isn't loaded yet.
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...
LIBRARY_MANAGER & m_manager
std::optional< const LIB_DATA * > fetchIfLoaded(const wxString &aNickname) const
LIBRARY_TABLE_SCOPE Scope() const
std::map< std::string, UTF8 > GetOptionsMap() const
const wxString & Type() const
const wxString & URI() const
const wxString & Nickname() const
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
Define a library symbol object.
Definition lib_symbol.h:119
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the #SCH_FILE_T from the corresponding plugin type name: "kicad", "legacy",...
Base class that schematic file and library loading and saving plugins should derive from.
Definition sch_io.h:60
virtual void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr)
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
Definition sch_io.cpp:90
virtual bool SupportsSubLibraries() const
Definition sch_io.h:322
virtual int GetModifyHash() const =0
Return the modification hash from the library cache.
virtual void GetAvailableSymbolFields(std::vector< wxString > &aNames)
Retrieves a list of (custom) field names that are present on symbols in this library.
Definition sch_io.h:358
virtual void CheckLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr)
Validate that the library at aLibraryPath is reachable and well-formed, without necessarily loading s...
Definition sch_io.cpp:108
virtual LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aPartName, const std::map< std::string, UTF8 > *aProperties=nullptr)
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
Definition sch_io.cpp:116
virtual wxString GetSubLibraryDescription(const wxString &aName)
Gets a description of a sublibrary.
Definition sch_io.h:347
virtual void GetSubLibraryNames(std::vector< wxString > &aNames)
Retrieves a list of sub-libraries in this library.
Definition sch_io.h:336
bool SupportsConfigurationDialog(const wxString &aNickname) const override
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
Loads or reloads the given library, if it exists.
static SCH_IO * schplugin(const LIB_DATA *aRow)
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
void DeleteSymbol(const wxString &aNickname, const wxString &aSymbolName)
Deletes the aSymbolName from the library given by aNickname.
std::optional< LIB_STATUS > CheckLibrary(LIB_DATA *aLib) override
Validates that a library is loadable. May not necessarily load the library!
SAVE_T SaveSymbol(const wxString &aNickname, std::unique_ptr< LIB_SYMBOL > aSymbol, bool aOverwrite=true)
Write aSymbol to an existing library given by aNickname.
void enumerateLibrary(LIB_DATA *aLib, const wxString &aUri) override
Override in derived class to perform library-specific enumeration.
std::vector< wxString > GetSymbolNames(const wxString &aNickname, SYMBOL_TYPE aType=SYMBOL_TYPE::ALL_SYMBOLS)
bool SupportsSubLibraries(const wxString &aNickname) const
LIBRARY_RESULT< IO_BASE * > createPlugin(const LIBRARY_TABLE_ROW *row) override
Creates a concrete plugin for the given row.
std::vector< SUB_LIBRARY > GetSubLibraries(const wxString &aNickname) const
SYMBOL_LIBRARY_ADAPTER(LIBRARY_MANAGER &aManager)
static wxString GlobalPathEnvVariableName()
static const char * PropPowerSymsOnly
LIBRARY_TABLE_TYPE Type() const override
The type of library table this adapter works with.
IO_BASE * plugin(const LIB_DATA *aRow) override
std::vector< LIB_SYMBOL * > GetSymbols(const wxString &aNickname, SYMBOL_TYPE aType=SYMBOL_TYPE::ALL_SYMBOLS)
static LEAK_AT_EXIT< std::shared_mutex > GlobalLibraryMutex
static LEAK_AT_EXIT< std::map< wxString, LIB_DATA > > GlobalLibraries
std::vector< wxString > GetAvailableExtraFields(const wxString &aNickname)
Returns a list of additional (non-mandatory) symbol fields present in the given library.
SAVE_T
The set of return values from SaveSymbol() below.
static const char * PropNonPowerSymsOnly
bool IsSymbolLibWritable(const wxString &aNickname)
Return true if the library given by aNickname is writable.
std::optional< int > GetLibraryModifyHash(const wxString &aNickname) const
Return the modify hash of a single library if it is currently loaded.
int ShowConfigurationDialog(const wxString &aNickname, wxWindow *aParent) const override
#define _(s)
Functions related to environment variables, including help functions.
const wxChar *const traceLibraries
Flag to enable library table and library manager tracing.
tl::expected< ResultType, LIBRARY_ERROR > LIBRARY_RESULT
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
Definition env_vars.cpp:78
see class PGM_BASE
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
const LIBRARY_TABLE_ROW * row
The overall status of a loaded or loading library.
std::optional< LIBRARY_ERROR > error
LOAD_STATUS load_status
A descriptor for a sub-library (supported by database and http libraries)
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.