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