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