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 std::map<std::string, UTF8> options = aLib->row->GetOptionsMap();
81 schplugin( aLib )->EnumerateSymbolLib( dummyList, aUri, &options );
82}
83
84
85std::optional<LIB_STATUS> SYMBOL_LIBRARY_ADAPTER::LoadOne( LIB_DATA* aLib )
86{
88
89 std::map<std::string, UTF8> options = aLib->row->GetOptionsMap();
90
91 try
92 {
93 wxArrayString dummyList;
94 schplugin( aLib )->EnumerateSymbolLib( dummyList, getUri( aLib->row ), &options );
95 wxLogTrace( traceLibraries, "Sym: %s: library enumerated %zu items", aLib->row->Nickname(), dummyList.size() );
97 }
98 catch( IO_ERROR& e )
99 {
101 aLib->status.error = LIBRARY_ERROR( { e.What() } );
102 wxLogTrace( traceLibraries, "Sym: %s: plugin threw exception: %s", aLib->row->Nickname(), e.What() );
103 }
104
105 return aLib->status;
106}
107
108
109std::optional<LIB_STATUS> SYMBOL_LIBRARY_ADAPTER::LoadOne( const wxString& nickname )
110{
112
113 if( result.has_value() )
114 return LoadOne( *result );
115
116 return LIB_STATUS { .load_status = LOAD_STATUS::LOAD_ERROR,
117 .error = LIBRARY_ERROR( { result.error() } ) };
118}
119
120
122{
123 SCH_IO_MGR::SCH_FILE_T type = SCH_IO_MGR::EnumFromStr( row->Type() );
124
125 if( type == SCH_IO_MGR::SCH_NESTED_TABLE )
126 {
127 wxString msg;
128 wxFileName fileName( m_manager.GetFullURI( row, true ) );
129
130 if( fileName.FileExists() )
131 return tl::unexpected( LIBRARY_TABLE_OK() );
132 else
133 msg = wxString::Format( _( "Nested table '%s' not found." ), row->URI() );
134
135 return tl::unexpected( LIBRARY_ERROR( msg ) );
136 }
137 else if( type == SCH_IO_MGR::SCH_FILE_UNKNOWN )
138 {
139 wxLogTrace( traceLibraries, "Sym: Plugin type %s is unknown!", row->Type() );
140 wxString msg = wxString::Format( _( "Unknown library type %s " ), row->Type() );
141 return tl::unexpected( LIBRARY_ERROR( msg ) );
142 }
143
144 SCH_IO* plugin = SCH_IO_MGR::FindPlugin( type );
145 wxCHECK( plugin, tl::unexpected( LIBRARY_ERROR( _( "Internal error" ) ) ) );
146
147 plugin->SetLibraryManagerAdapter( this );
148
149 wxLogTrace( traceLibraries, "Sym: Library %s (%s) plugin created", row->Nickname(),
150 magic_enum::enum_name( row->Scope() ) );
151
152 return plugin;
153}
154
155
156std::vector<LIB_SYMBOL*> SYMBOL_LIBRARY_ADAPTER::GetSymbols( const wxString& aNickname, SYMBOL_TYPE aType )
157{
158 std::vector<LIB_SYMBOL*> symbols;
159
160 std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname );
161
162 if( !maybeLib )
163 return symbols;
164
165 const LIB_DATA* lib = *maybeLib;
166 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
167
168 if( aType == SYMBOL_TYPE::POWER_ONLY )
169 options[PropPowerSymsOnly] = "";
170
171 try
172 {
173 schplugin( lib )->EnumerateSymbolLib( symbols, getUri( lib->row ), &options );
174 }
175 catch( IO_ERROR& e )
176 {
177 wxLogTrace( traceLibraries, "Sym: Exception enumerating library %s: %s", lib->row->Nickname(), e.What() );
178 }
179
180 for( LIB_SYMBOL* symbol : symbols )
181 {
182 LIB_ID id = symbol->GetLibId();
183 id.SetLibNickname( lib->row->Nickname() );
184 symbol->SetLibId( id );
185 }
186
187 return symbols;
188}
189
190
191std::vector<wxString> SYMBOL_LIBRARY_ADAPTER::GetSymbolNames( const wxString& aNickname, SYMBOL_TYPE aType )
192{
193 wxArrayString namesAS;
194 std::vector<wxString> names;
195
196 if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
197 {
198 const LIB_DATA* lib = *maybeLib;
199 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
200
201 if( aType == SYMBOL_TYPE::POWER_ONLY )
202 options[PropPowerSymsOnly] = "";
203
204 try
205 {
206 schplugin( lib )->EnumerateSymbolLib( namesAS, getUri( lib->row ), &options );
207 }
208 catch( const IO_ERROR& e )
209 {
210 wxLogTrace( traceLibraries, "Sym: Exception enumerating library %s: %s",
211 lib->row->Nickname(), e.What() );
212 }
213 }
214
215 for( const wxString& name : namesAS )
216 names.emplace_back( name );
217
218 return names;
219}
220
221
222LIB_SYMBOL* SYMBOL_LIBRARY_ADAPTER::LoadSymbol( const wxString& aNickname, const wxString& aName )
223{
224 if( std::optional<const LIB_DATA*> lib = fetchIfLoaded( aNickname ) )
225 {
226 if( LIB_SYMBOL* symbol = schplugin( *lib )->LoadSymbol( getUri( ( *lib )->row ), aName ) )
227 {
228 LIB_ID id = symbol->GetLibId();
229 id.SetLibNickname( ( *lib )->row->Nickname() );
230 symbol->SetLibId( id );
231 return symbol;
232 }
233 }
234 else
235 {
236 wxLogTrace( traceLibraries, "LoadSymbol: requested library %s not loaded", aNickname );
237 }
238
239 return nullptr;
240}
241
242
244 const LIB_SYMBOL* aSymbol, bool aOverwrite )
245{
246 wxCHECK( aSymbol, SAVE_SKIPPED );
247
248 LIBRARY_RESULT<LIB_DATA*> libResult = loadIfNeeded( aNickname );
249
250 if( !libResult.has_value() )
251 {
252 wxLogTrace( traceLibraries, "SaveSymbol: unable to load library %s: %s", aNickname,
253 libResult.error().message );
254 return SAVE_SKIPPED;
255 }
256
257 LIB_DATA* lib = *libResult;
258
259 if( !lib )
260 {
261 wxLogTrace( traceLibraries, "SaveSymbol: library %s not found", aNickname );
262 return SAVE_SKIPPED;
263 }
264
265 SCH_IO* plugin = schplugin( lib );
266 wxCHECK( plugin, SAVE_SKIPPED );
267
268 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
269
270 if( !aOverwrite )
271 {
272 try
273 {
274 std::unique_ptr<LIB_SYMBOL> existing( plugin->LoadSymbol( getUri( lib->row ), aSymbol->GetName(),
275 &options ) );
276
277 if( existing )
278 return SAVE_SKIPPED;
279 }
280 catch( const IO_ERROR& e )
281 {
282 wxLogTrace( traceLibraries, "SaveSymbol: error checking for existing symbol %s:%s: %s", aNickname,
283 aSymbol->GetName(), e.What() );
284 return SAVE_SKIPPED;
285 }
286 }
287
288 try
289 {
290 plugin->SaveSymbol( getUri( lib->row ), aSymbol, &options );
291 }
292 catch( const IO_ERROR& e )
293 {
294 wxLogTrace( traceLibraries, "SaveSymbol: error saving %s:%s: %s", aNickname, aSymbol->GetName(), e.What() );
295 return SAVE_SKIPPED;
296 }
297
298 return SAVE_OK;
299}
300
301
302void SYMBOL_LIBRARY_ADAPTER::DeleteSymbol( const wxString& aNickname, const wxString& aSymbolName )
303{
304 wxCHECK_MSG( false, /* void */, "Unimplemented!" );
305}
306
307
309{
310 // Route through fetchIfLoaded() so LOAD_ERROR sentinel entries, which carry a null
311 // plugin, are filtered out instead of dereferenced.
312 if( std::optional<const LIB_DATA*> lib = fetchIfLoaded( aLib ) )
313 return ( *lib )->plugin->IsLibraryWritable( getUri( ( *lib )->row ) );
314
315 return false;
316}
317
318
319std::vector<wxString> SYMBOL_LIBRARY_ADAPTER::GetAvailableExtraFields( const wxString& aNickname )
320{
321 std::vector<wxString> fields;
322
323 if( std::optional<LIB_DATA*> result = fetchIfLoaded( aNickname ) )
324 {
325 LIB_DATA* rowData = *result;
326
327 int hash = schplugin( rowData )->GetModifyHash();
328
329 if( hash != rowData->modify_hash )
330 {
331 rowData->modify_hash = hash;
333 }
334
335 return rowData->available_fields_cache;
336 }
337
338 return fields;
339}
340
341
342bool SYMBOL_LIBRARY_ADAPTER::SupportsSubLibraries( const wxString& aNickname ) const
343{
344 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( aNickname ) )
345 {
346 const LIB_DATA* rowData = *result;
347 return schplugin( rowData )->SupportsSubLibraries();
348 }
349
350 return false;
351}
352
353
354std::vector<SUB_LIBRARY> SYMBOL_LIBRARY_ADAPTER::GetSubLibraries( const wxString& aNickname ) const
355{
356 std::vector<SUB_LIBRARY> ret;
357
358 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( aNickname ) )
359 {
360 const LIB_DATA* rowData = *result;
361
362 try
363 {
364 std::vector<wxString> names;
365 schplugin( rowData )->GetSubLibraryNames( names );
366
367 for( const wxString& name : names )
368 {
369 ret.emplace_back( SUB_LIBRARY {
370 .nickname = name,
371 .description = schplugin( rowData )->GetSubLibraryDescription( name ) } );
372 }
373 }
374 catch( const IO_ERROR& e )
375 {
376 wxLogTrace( traceLibraries, "Sym: Exception getting sub-libraries for %s: %s",
377 aNickname, e.What() );
378 }
379 }
380
381 return ret;
382}
383
384
385bool SYMBOL_LIBRARY_ADAPTER::SupportsConfigurationDialog( const wxString& aNickname ) const
386{
387 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( aNickname ) )
388 return ( *result )->plugin->SupportsConfigurationDialog();
389
390 return false;
391}
392
393
394void SYMBOL_LIBRARY_ADAPTER::ShowConfigurationDialog( const wxString& aNickname, wxWindow* aParent ) const
395{
396 std::optional<const LIB_DATA*> optRow = fetchIfLoaded( aNickname );
397
398 if( !optRow )
399 return;
400
401 if( !( *optRow )->plugin->SupportsConfigurationDialog() )
402 return;
403
404 DIALOG_SHIM* dialog = ( *optRow )->plugin->CreateConfigurationDialog( aParent );
405 dialog->ShowModal();
406}
407
408
410{
411 int hash = 0;
412
413 for( const LIBRARY_TABLE_ROW* row : m_manager.Rows( Type() ) )
414 {
415 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( row->Nickname() ) )
416 {
417 const LIB_DATA* rowData = *result;
418 wxCHECK2( rowData->row, continue );
419 hash += schplugin( rowData )->GetModifyHash();
420 }
421 }
422
423 return hash;
424}
425
426
427std::optional<int> SYMBOL_LIBRARY_ADAPTER::GetLibraryModifyHash( const wxString& aNickname ) const
428{
429 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( aNickname ) )
430 {
431 const LIB_DATA* rowData = *result;
432 wxCHECK( rowData->row, std::nullopt );
433 return schplugin( rowData )->GetModifyHash();
434 }
435
436 return std::nullopt;
437}
const char * name
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition dialog_shim.h:65
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()
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.
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 wxString getUri(const LIBRARY_TABLE_ROW *aRow)
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:96
Define a library symbol object.
Definition lib_symbol.h:79
wxString GetName() const override
Definition lib_symbol.h:141
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:59
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:82
virtual bool SupportsSubLibraries() const
Definition sch_io.h:290
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:326
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:100
virtual wxString GetSubLibraryDescription(const wxString &aName)
Gets a description of a sublibrary.
Definition sch_io.h:315
virtual void GetSubLibraryNames(std::vector< wxString > &aNames)
Retrieves a list of sub-libraries in this library.
Definition sch_io.h:304
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.
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
SAVE_T SaveSymbol(const wxString &aNickname, const LIB_SYMBOL *aSymbol, bool aOverwrite=true)
Write aSymbol to an existing library given by aNickname.
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.
void ShowConfigurationDialog(const wxString &aNickname, wxWindow *aParent) const override
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.
The common library.
#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:77
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.