KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_io_database.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 (C) 2022 Jon Evans <[email protected]>
5 * Copyright (C) 2022-2024 KiCad Developers, see AUTHORS.txt for contributors.
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 <iostream>
22#include <unordered_set>
23#include <wx/datetime.h>
24#include <wx/log.h>
25
26#include <boost/algorithm/string.hpp>
27
30#include <fmt.h>
31#include <lib_symbol.h>
32#include <symbol_lib_table.h>
33
34#include "sch_io_database.h"
35
36
37SCH_IO_DATABASE::SCH_IO_DATABASE() : SCH_IO( wxS( "Database library" ) ),
38 m_libTable( nullptr ),
39 m_settings(),
40 m_conn()
41{
44}
45
46
48{
49}
50
51
52void SCH_IO_DATABASE::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
53 const wxString& aLibraryPath,
54 const STRING_UTF8_MAP* aProperties )
55{
56 std::vector<LIB_SYMBOL*> symbols;
57 EnumerateSymbolLib( symbols, aLibraryPath, aProperties );
58
59 for( LIB_SYMBOL* symbol : symbols )
60 aSymbolNameList.Add( symbol->GetName() );
61}
62
63
64void SCH_IO_DATABASE::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
65 const wxString& aLibraryPath,
66 const STRING_UTF8_MAP* aProperties )
67{
68 wxCHECK_RET( m_libTable, "Database plugin missing library table handle!" );
69 ensureSettings( aLibraryPath );
71 cacheLib();
72
73 if( !m_conn )
75
76 bool powerSymbolsOnly = ( aProperties &&
77 aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) !=
78 aProperties->end() );
79
80 for( auto const& pair : m_nameToSymbolcache )
81 {
82 LIB_SYMBOL* symbol = pair.second.get();
83
84 if( !powerSymbolsOnly || symbol->IsPower() )
85 aSymbolList.emplace_back( symbol );
86 }
87}
88
89
90LIB_SYMBOL* SCH_IO_DATABASE::LoadSymbol( const wxString& aLibraryPath,
91 const wxString& aAliasName,
92 const STRING_UTF8_MAP* aProperties )
93{
94 wxCHECK( m_libTable, nullptr );
95 ensureSettings( aLibraryPath );
97
98 if( !m_conn )
100
101 /*
102 * Table names are tricky, in order to allow maximum flexibility to the user.
103 * The slash character is used as a separator between a table name and symbol name, but symbol
104 * names may also contain slashes and table names may now also be empty (which results in the
105 * slash being dropped in the symbol name when placing a new symbol). So, if a slash is found,
106 * we check if the string before the slash is a valid table name. If not, we assume the table
107 * name is blank if our config has an entry for the null table.
108 */
109
110 std::string tableName = "";
111 std::string symbolName( aAliasName.ToUTF8() );
112
113 if( aAliasName.Contains( '/' ) )
114 {
115 tableName = std::string( aAliasName.BeforeFirst( '/' ).ToUTF8() );
116 symbolName = std::string( aAliasName.AfterFirst( '/' ).ToUTF8() );
117 }
118
119 std::vector<const DATABASE_LIB_TABLE*> tablesToTry;
120
121 for( const DATABASE_LIB_TABLE& tableIter : m_settings->m_Tables )
122 {
123 if( tableIter.name == tableName )
124 tablesToTry.emplace_back( &tableIter );
125 }
126
127 if( tablesToTry.empty() )
128 {
129 wxLogTrace( traceDatabase, wxT( "LoadSymbol: table '%s' not found in config" ), tableName );
130 return nullptr;
131 }
132
133 const DATABASE_LIB_TABLE* foundTable = nullptr;
135
136 for( const DATABASE_LIB_TABLE* table : tablesToTry )
137 {
138 if( m_conn->SelectOne( table->table, std::make_pair( table->key_col, symbolName ),
139 result ) )
140 {
141 foundTable = table;
142 wxLogTrace( traceDatabase, wxT( "LoadSymbol: SelectOne (%s, %s) found in %s" ),
143 table->key_col, symbolName, table->table );
144 }
145 else
146 {
147 wxLogTrace( traceDatabase, wxT( "LoadSymbol: SelectOne (%s, %s) failed for table %s" ),
148 table->key_col, symbolName, table->table );
149 }
150 }
151
152 wxCHECK( foundTable, nullptr );
153
154 return loadSymbolFromRow( aAliasName, *foundTable, result ).release();
155}
156
157
158void SCH_IO_DATABASE::GetSubLibraryNames( std::vector<wxString>& aNames )
159{
160 ensureSettings( wxEmptyString );
161
162 aNames.clear();
163
164 std::set<wxString> tableNames;
165
166 for( const DATABASE_LIB_TABLE& tableIter : m_settings->m_Tables )
167 {
168 if( tableNames.count( tableIter.name ) )
169 continue;
170
171 aNames.emplace_back( tableIter.name );
172 tableNames.insert( tableIter.name );
173 }
174}
175
176
177void SCH_IO_DATABASE::GetAvailableSymbolFields( std::vector<wxString>& aNames )
178{
179 std::copy( m_customFields.begin(), m_customFields.end(), std::back_inserter( aNames ) );
180}
181
182
183void SCH_IO_DATABASE::GetDefaultSymbolFields( std::vector<wxString>& aNames )
184{
185 std::copy( m_defaultShownFields.begin(), m_defaultShownFields.end(),
186 std::back_inserter( aNames ) );
187}
188
189
190bool SCH_IO_DATABASE::TestConnection( wxString* aErrorMsg )
191{
192 if( m_conn && m_conn->IsConnected() )
193 return true;
194
195 connect();
196
197 if( aErrorMsg && ( !m_conn || !m_conn->IsConnected() ) )
198 *aErrorMsg = m_lastError;
199
200 return m_conn && m_conn->IsConnected();
201}
202
203
205{
206 long long currentTimestampSeconds = wxDateTime::Now().GetValue().GetValue() / 1000;
207
209 && ( currentTimestampSeconds - m_cacheTimestamp ) < m_settings->m_Cache.max_age )
210 {
211 return;
212 }
213
214 for( const DATABASE_LIB_TABLE& table : m_settings->m_Tables )
215 {
216 std::vector<DATABASE_CONNECTION::ROW> results;
217
218 if( !m_conn->SelectAll( table.table, table.key_col, results ) )
219 {
220 if( !m_conn->GetLastError().empty() )
221 {
222 wxString msg = wxString::Format( _( "Error reading database table %s: %s" ),
223 table.table, m_conn->GetLastError() );
224 THROW_IO_ERROR( msg );
225 }
226
227 continue;
228 }
229
230 for( DATABASE_CONNECTION::ROW& result : results )
231 {
232 if( !result.count( table.key_col ) )
233 continue;
234
235 std::string prefix = table.name.empty() ? "" : fmt::format( "{}/", table.name );
236 wxString name( fmt::format( "{}{}", prefix,
237 std::any_cast<std::string>( result[table.key_col] ) ) );
238
239 std::unique_ptr<LIB_SYMBOL> symbol = loadSymbolFromRow( name, table, result );
240
241 if( symbol )
242 m_nameToSymbolcache[symbol->GetName()] = std::move( symbol );
243 }
244 }
245
246 m_cacheTimestamp = currentTimestampSeconds;
248}
249
250void SCH_IO_DATABASE::ensureSettings( const wxString& aSettingsPath )
251{
252 auto tryLoad =
253 [&]()
254 {
255 if( !m_settings->LoadFromFile() )
256 {
257 wxString msg = wxString::Format(
258 _( "Could not load database library: settings file %s missing or invalid" ),
259 aSettingsPath );
260
261 THROW_IO_ERROR( msg );
262 }
263 };
264
265 if( !m_settings && !aSettingsPath.IsEmpty() )
266 {
267 std::string path( aSettingsPath.ToUTF8() );
268 m_settings = std::make_unique<DATABASE_LIB_SETTINGS>( path );
269 m_settings->SetReadOnly( true );
270
271 tryLoad();
272 }
273 else if( !m_conn && m_settings )
274 {
275 // If we have valid settings but no connection yet; reload settings in case user is editing
276 tryLoad();
277 }
278 else if( m_conn && m_settings && !aSettingsPath.IsEmpty() )
279 {
280 wxASSERT_MSG( aSettingsPath == m_settings->GetFilename(),
281 "Path changed for database library without re-initializing plugin!" );
282 }
283 else if( !m_settings )
284 {
285 wxLogTrace( traceDatabase, wxT( "ensureSettings: no settings but no valid path!" ) );
286 }
287}
288
289
291{
292 wxCHECK_RET( m_settings, "Call ensureSettings before ensureConnection!" );
293
294 connect();
295
296 if( !m_conn || !m_conn->IsConnected() )
297 {
298 wxString msg = wxString::Format(
299 _( "Could not load database library: could not connect to database %s (%s)" ),
300 m_settings->m_Source.dsn, m_lastError );
301
302 THROW_IO_ERROR( msg );
303 }
304}
305
306
308{
309 wxCHECK_RET( m_settings, "Call ensureSettings before connect()!" );
310
311 if( m_conn && !m_conn->IsConnected() )
312 m_conn.reset();
313
314 if( !m_conn )
315 {
316 if( m_settings->m_Source.connection_string.empty() )
317 {
318 m_conn = std::make_unique<DATABASE_CONNECTION>( m_settings->m_Source.dsn,
319 m_settings->m_Source.username,
320 m_settings->m_Source.password,
321 m_settings->m_Source.timeout );
322 }
323 else
324 {
325 std::string cs = m_settings->m_Source.connection_string;
326 std::string basePath( wxFileName( m_settings->GetFilename() ).GetPath().ToUTF8() );
327
328 // Database drivers that use files operate on absolute paths, so provide a mechanism
329 // for specifying on-disk databases that live next to the kicad_dbl file
330 boost::replace_all( cs, "${CWD}", basePath );
331
332 m_conn = std::make_unique<DATABASE_CONNECTION>( cs, m_settings->m_Source.timeout );
333 }
334
335 if( !m_conn->IsConnected() )
336 {
337 m_lastError = m_conn->GetLastError();
338 m_conn.reset();
339 return;
340 }
341
342 for( const DATABASE_LIB_TABLE& tableIter : m_settings->m_Tables )
343 {
344 std::set<std::string> columns;
345
346 columns.insert( tableIter.key_col );
347 columns.insert( tableIter.footprints_col );
348 columns.insert( tableIter.symbols_col );
349
350 columns.insert( tableIter.properties.description );
351 columns.insert( tableIter.properties.footprint_filters );
352 columns.insert( tableIter.properties.keywords );
353 columns.insert( tableIter.properties.exclude_from_sim );
354 columns.insert( tableIter.properties.exclude_from_bom );
355 columns.insert( tableIter.properties.exclude_from_board );
356
357 for( const DATABASE_FIELD_MAPPING& field : tableIter.fields )
358 columns.insert( field.column );
359
360 m_conn->CacheTableInfo( tableIter.table, columns );
361 }
362
363 m_conn->SetCacheParams( m_settings->m_Cache.max_size, m_settings->m_Cache.max_age );
364 }
365}
366
367
368std::optional<bool> SCH_IO_DATABASE::boolFromAny( const std::any& aVal )
369{
370 try
371 {
372 bool val = std::any_cast<bool>( aVal );
373 return val;
374 }
375 catch( const std::bad_any_cast& )
376 {
377 }
378
379 try
380 {
381 int val = std::any_cast<int>( aVal );
382 return static_cast<bool>( val );
383 }
384 catch( const std::bad_any_cast& )
385 {
386 }
387
388 try
389 {
390 wxString strval( std::any_cast<std::string>( aVal ).c_str(), wxConvUTF8 );
391
392 if( strval.IsEmpty() )
393 return std::nullopt;
394
395 strval.MakeLower();
396
397 for( const auto& trueVal : { wxS( "true" ), wxS( "yes" ), wxS( "y" ), wxS( "1" ) } )
398 {
399 if( strval.Matches( trueVal ) )
400 return true;
401 }
402
403 for( const auto& falseVal : { wxS( "false" ), wxS( "no" ), wxS( "n" ), wxS( "0" ) } )
404 {
405 if( strval.Matches( falseVal ) )
406 return false;
407 }
408 }
409 catch( const std::bad_any_cast& )
410 {
411 }
412
413 return std::nullopt;
414}
415
416
417std::unique_ptr<LIB_SYMBOL> SCH_IO_DATABASE::loadSymbolFromRow( const wxString& aSymbolName,
418 const DATABASE_LIB_TABLE& aTable,
419 const DATABASE_CONNECTION::ROW& aRow )
420{
421 std::unique_ptr<LIB_SYMBOL> symbol = nullptr;
422
423 if( aRow.count( aTable.symbols_col ) )
424 {
425 LIB_SYMBOL* originalSymbol = nullptr;
426
427 // TODO: Support multiple options for symbol
428 std::string symbolIdStr = std::any_cast<std::string>( aRow.at( aTable.symbols_col ) );
429 LIB_ID symbolId;
430 symbolId.Parse( std::any_cast<std::string>( aRow.at( aTable.symbols_col ) ) );
431
432 if( symbolId.IsValid() )
433 originalSymbol = m_libTable->LoadSymbol( symbolId );
434
435 if( originalSymbol )
436 {
437 wxLogTrace( traceDatabase, wxT( "loadSymbolFromRow: found original symbol '%s'" ),
438 symbolIdStr );
439 symbol.reset( originalSymbol->Duplicate() );
440 symbol->SetSourceLibId( symbolId );
441 }
442 else if( !symbolId.IsValid() )
443 {
444 wxLogTrace( traceDatabase, wxT( "loadSymboFromRow: source symbol id '%s' is invalid, "
445 "will create empty symbol" ), symbolIdStr );
446 }
447 else
448 {
449 wxLogTrace( traceDatabase, wxT( "loadSymboFromRow: source symbol '%s' not found, "
450 "will create empty symbol" ), symbolIdStr );
451 }
452 }
453
454 if( !symbol )
455 {
456 // Actual symbol not found: return metadata only; error will be indicated in the
457 // symbol chooser
458 symbol.reset( new LIB_SYMBOL( aSymbolName ) );
459 }
460 else
461 {
462 symbol->SetName( aSymbolName );
463 }
464
465 LIB_ID libId = symbol->GetLibId();
466 libId.SetSubLibraryName( aTable.name );;
467 symbol->SetLibId( libId );
468
469 if( aRow.count( aTable.footprints_col ) )
470 {
471 std::string footprints = std::any_cast<std::string>( aRow.at( aTable.footprints_col ) );
472
473 wxString footprintsStr = wxString( footprints.c_str(), wxConvUTF8 );
474 wxArrayString footprintsList;
475 wxStringTokenizer tokenizer( footprintsStr, ';' );
476
477 while( tokenizer.HasMoreTokens() )
478 footprintsList.Add( tokenizer.GetNextToken() );
479
480 if( footprintsList.size() > 0 )
481 symbol->GetFootprintField().SetText( footprintsList[0] );
482
483 symbol->SetFPFilters( footprintsList );
484 }
485 else
486 {
487 wxLogTrace( traceDatabase, wxT( "loadSymboFromRow: footprint field %s not found." ),
488 aTable.footprints_col );
489 }
490
491 if( !aTable.properties.description.empty() && aRow.count( aTable.properties.description ) )
492 {
493 wxString value(
494 std::any_cast<std::string>( aRow.at( aTable.properties.description ) ).c_str(),
495 wxConvUTF8 );
496 symbol->SetDescription( value );
497 }
498
499 if( !aTable.properties.keywords.empty() && aRow.count( aTable.properties.keywords ) )
500 {
501 wxString value( std::any_cast<std::string>( aRow.at( aTable.properties.keywords ) ).c_str(),
502 wxConvUTF8 );
503 symbol->SetKeyWords( value );
504 }
505
506 if( !aTable.properties.footprint_filters.empty()
507 && aRow.count( aTable.properties.footprint_filters ) )
508 {
509 wxString value( std::any_cast<std::string>( aRow.at( aTable.properties.footprint_filters ) )
510 .c_str(),
511 wxConvUTF8 );
512 wxArrayString filters;
513 filters.push_back( value );
514 symbol->SetFPFilters( filters );
515 }
516
517 if( !aTable.properties.exclude_from_sim.empty()
518 && aRow.count( aTable.properties.exclude_from_sim ) )
519 {
520 std::optional<bool> val = boolFromAny( aRow.at( aTable.properties.exclude_from_sim ) );
521
522 if( val )
523 {
524 symbol->SetExcludedFromSim( *val );
525 }
526 else
527 {
528 wxLogTrace( traceDatabase, wxT( "loadSymbolFromRow: exclude_from_sim value for %s "
529 "could not be cast to a boolean" ), aSymbolName );
530 }
531 }
532
533 if( !aTable.properties.exclude_from_board.empty()
534 && aRow.count( aTable.properties.exclude_from_board ) )
535 {
536 std::optional<bool> val = boolFromAny( aRow.at( aTable.properties.exclude_from_board ) );
537
538 if( val )
539 {
540 symbol->SetExcludedFromBoard( *val );
541 }
542 else
543 {
544 wxLogTrace( traceDatabase, wxT( "loadSymbolFromRow: exclude_from_board value for %s "
545 "could not be cast to a boolean" ), aSymbolName );
546 }
547 }
548
549 if( !aTable.properties.exclude_from_bom.empty()
550 && aRow.count( aTable.properties.exclude_from_bom ) )
551 {
552 std::optional<bool> val = boolFromAny( aRow.at( aTable.properties.exclude_from_bom ) );
553
554 if( val )
555 {
556 symbol->SetExcludedFromBOM( *val );
557 }
558 else
559 {
560 wxLogTrace( traceDatabase, wxT( "loadSymbolFromRow: exclude_from_bom value for %s "
561 "could not be cast to a boolean" ), aSymbolName );
562 }
563 }
564
565 std::vector<SCH_FIELD*> fields;
566 symbol->GetFields( fields );
567
568 std::unordered_map<wxString, SCH_FIELD*> fieldsMap;
569
570 for( SCH_FIELD* field : fields )
571 fieldsMap[field->GetName()] = field;
572
573 static const wxString c_valueFieldName( wxS( "Value" ) );
574 static const wxString c_datasheetFieldName( wxS( "Datasheet" ) );
575
576 for( const DATABASE_FIELD_MAPPING& mapping : aTable.fields )
577 {
578 if( !aRow.count( mapping.column ) )
579 {
580 wxLogTrace( traceDatabase, wxT( "loadSymbolFromRow: field %s not found in result" ),
581 mapping.column );
582 continue;
583 }
584
585 std::string strValue;
586
587 try
588 {
589 strValue = std::any_cast<std::string>( aRow.at( mapping.column ) );
590 }
591 catch( std::bad_any_cast& )
592 {
593 }
594
595 wxString value( strValue.c_str(), wxConvUTF8 );
596
597 if( mapping.name_wx == c_valueFieldName )
598 {
599 SCH_FIELD& field = symbol->GetValueField();
600 field.SetText( value );
601
602 if( !mapping.inherit_properties )
603 {
604 field.SetVisible( mapping.visible_on_add );
605 field.SetNameShown( mapping.show_name );
606 }
607 continue;
608 }
609 else if( mapping.name_wx == c_datasheetFieldName )
610 {
611 SCH_FIELD& field = symbol->GetDatasheetField();
612 field.SetText( value );
613
614 if( !mapping.inherit_properties )
615 {
616 field.SetVisible( mapping.visible_on_add );
617 field.SetNameShown( mapping.show_name );
618
619 if( mapping.visible_on_add )
620 field.SetAutoAdded( true );
621 }
622
623 continue;
624 }
625
626 SCH_FIELD* field;
627 bool isNew = false;
628
629 if( fieldsMap.count( mapping.name_wx ) )
630 {
631 field = fieldsMap[mapping.name_wx];
632 }
633 else
634 {
635 field = new SCH_FIELD( nullptr, symbol->GetNextAvailableFieldId() );
636 field->SetName( mapping.name_wx );
637 isNew = true;
638 fieldsMap[mapping.name_wx] = field;
639 }
640
641 if( !mapping.inherit_properties || isNew )
642 {
643 field->SetVisible( mapping.visible_on_add );
644 field->SetAutoAdded( true );
645 field->SetNameShown( mapping.show_name );
646 }
647
648 field->SetText( value );
649
650 if( isNew )
651 symbol->AddDrawItem( field, false );
652
653 m_customFields.insert( mapping.name_wx );
654
655 if( mapping.visible_in_chooser )
656 m_defaultShownFields.insert( mapping.name_wx );
657 }
658
659 symbol->GetDrawItems().sort();
660
661 return symbol;
662}
const char * name
Definition: DXF_plotter.cpp:57
std::map< std::string, std::any > ROW
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:243
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:51
bool IsValid() const
Check if this LID_ID is valid.
Definition: lib_id.h:172
void SetSubLibraryName(const UTF8 &aName)
Definition: lib_id.h:131
Define a library symbol object.
Definition: lib_symbol.h:77
bool IsPower() const override
Definition: lib_symbol.cpp:663
virtual LIB_SYMBOL * Duplicate() const
Create a copy of a LIB_SYMBOL and assigns unique KIIDs to the copy and its children.
Definition: lib_symbol.h:93
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
void SetAutoAdded(bool aAutoAdded)
Definition: sch_field.h:224
void SetName(const wxString &aName)
Definition: sch_field.cpp:1097
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1107
void SetNameShown(bool aShown=true)
Definition: sch_field.h:206
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const STRING_UTF8_MAP *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
std::unique_ptr< DATABASE_CONNECTION > m_conn
Generally will be null if no valid connection is established.
void GetDefaultSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that should be shown by default for this library in the symb...
void ensureSettings(const wxString &aSettingsPath)
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const STRING_UTF8_MAP *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
bool TestConnection(wxString *aErrorMsg=nullptr)
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > m_nameToSymbolcache
SYMBOL_LIB_TABLE * m_libTable
std::set< wxString > m_defaultShownFields
virtual ~SCH_IO_DATABASE()
void GetSubLibraryNames(std::vector< wxString > &aNames) override
Retrieves a list of sub-libraries in this library.
std::unique_ptr< DATABASE_LIB_SETTINGS > m_settings
static std::optional< bool > boolFromAny(const std::any &aVal)
long long m_cacheTimestamp
void GetAvailableSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that are present on symbols in this library.
std::unique_ptr< LIB_SYMBOL > loadSymbolFromRow(const wxString &aSymbolName, const DATABASE_LIB_TABLE &aTable, const DATABASE_CONNECTION::ROW &aRow)
std::set< wxString > m_customFields
Base class that schematic file and library loading and saving plugins should derive from.
Definition: sch_io.h:57
A name/value tuple with unique names and optional values.
static const char * PropPowerSymsOnly
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
const char *const traceDatabase
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
static std::string strValue(double aValue)
bool visible_in_chooser
Whether the column is shown by default in the chooser.
std::string column
Database column name.
bool inherit_properties
Whether or not to inherit properties from symbol field.
bool visible_on_add
Whether to show the field when placing the symbol.
bool show_name
Whether or not to show the field name as well as its value.
wxString name_wx
KiCad field name (converted)
A database library table will be mapped to a sub-library provided by the database library entry in th...
std::string key_col
Unique key column name (will form part of the LIB_ID)
std::string name
KiCad library nickname (will form part of the LIB_ID)
std::string symbols_col
Column name containing KiCad symbol refs.
std::string footprints_col
Column name containing KiCad footprint refs.
std::vector< DATABASE_FIELD_MAPPING > fields
std::string table
Database table to pull content from.
MAPPABLE_SYMBOL_PROPERTIES properties