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