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