KiCad PCB EDA Suite
Loading...
Searching...
No Matches
library_manager.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 * @author Jon Evans <[email protected]>
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <common.h>
22#include <env_vars.h>
23#include <list>
24#include <magic_enum.hpp>
25#include <unordered_set>
26
27#include <paths.h>
28#include <pgm_base.h>
29#include <richio.h>
30#include <trace_helpers.h>
32
36#include <wx/dir.h>
37#include <wx/log.h>
38
40{
41 std::vector<LIBRARY_TABLE> tables;
42};
43
44
48
49
51
52
53void LIBRARY_MANAGER::loadTables( const wxString& aTablePath, LIBRARY_TABLE_SCOPE aScope,
54 std::vector<LIBRARY_TABLE_TYPE> aTablesToLoad )
55{
56 auto getTarget =
57 [&]() -> std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>&
58 {
59 switch( aScope )
60 {
62 return m_tables;
63
65 return m_projectTables;
66
67 default:
68 wxCHECK_MSG( false, m_tables, "Invalid scope passed to loadTables" );
69 }
70 };
71
72 std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>& aTarget = getTarget();
73
74 if( aTablesToLoad.size() == 0 )
76
77 for( LIBRARY_TABLE_TYPE type : aTablesToLoad )
78 {
79 aTarget.erase( type );
80
81 wxFileName fn( aTablePath, tableFileName( type ) );
82
83 if( fn.IsFileReadable() )
84 {
85 auto table = std::make_unique<LIBRARY_TABLE>( fn, aScope );
86 wxCHECK2( table->Type() == type, continue );
87 aTarget[type] = std::move( table );
88 loadNestedTables( *aTarget[type] );
89 }
90 else
91 {
92 wxLogTrace( traceLibraries, "No library table found at %s", fn.GetFullPath() );
93 }
94 }
95}
96
97
99{
100 std::unordered_set<wxString> seenTables;
101
102 std::function<void(LIBRARY_TABLE&)> processOneTable =
103 [&]( LIBRARY_TABLE& aTable )
104 {
105 seenTables.insert( aTable.Path() );
106
107 if( !aTable.IsOk() )
108 return;
109
110 for( LIBRARY_TABLE_ROW& row : aTable.Rows() )
111 {
112 if( row.Type() == LIBRARY_TABLE_ROW::TABLE_TYPE_NAME )
113 {
114 wxFileName file( ExpandURI( row.URI(), Pgm().GetSettingsManager().Prj() ) );
115
116 // URI may be relative to parent
117 file.MakeAbsolute( wxFileName( aTable.Path() ).GetPath() );
118
120 wxString src = file.GetFullPath();
121
122 if( seenTables.contains( src ) )
123 {
124 wxLogTrace( traceLibraries, "Library table %s has already been loaded!", src );
125 row.SetOk( false );
126 row.SetErrorDescription( _( "A reference to this library table already exists" ) );
127 continue;
128 }
129
130 auto child = std::make_unique<LIBRARY_TABLE>( file, aRootTable.Scope() );
131
132 processOneTable( *child );
133
134 if( !child->IsOk() )
135 {
136 row.SetOk( false );
137 row.SetErrorDescription( child->ErrorDescription() );
138 }
139
140 m_childTables.insert( { row.URI(), std::move( child ) } );
141 }
142 }
143 };
144
145 processOneTable( aRootTable );
146}
147
148
150{
151 switch( aType )
152 {
156 default: wxCHECK( false, wxEmptyString );
157 }
158}
159
160
162{
163 if( aScope == LIBRARY_TABLE_SCOPE::GLOBAL )
164 {
165 wxCHECK( !m_tables.contains( aType ), /* void */ );
166 wxFileName fn( PATHS::GetUserSettingsPath(), tableFileName( aType ) );
167
168 m_tables[aType] = std::make_unique<LIBRARY_TABLE>( fn, LIBRARY_TABLE_SCOPE::GLOBAL );
169 m_tables[aType]->SetType( aType );
170 }
171 else if( aScope == LIBRARY_TABLE_SCOPE::PROJECT )
172 {
173 wxCHECK( !m_projectTables.contains( aType ), /* void */ );
174 wxFileName fn( Pgm().GetSettingsManager().Prj().GetProjectDirectory(), tableFileName( aType ) );
175
176 m_projectTables[aType] = std::make_unique<LIBRARY_TABLE>( fn, LIBRARY_TABLE_SCOPE::PROJECT );
177 m_projectTables[aType]->SetType( aType );
178 }
179}
180
181
182class PCM_LIB_TRAVERSER final : public wxDirTraverser
183{
184public:
185 explicit PCM_LIB_TRAVERSER( const wxString& aBasePath, LIBRARY_MANAGER& aManager,
186 const wxString& aPrefix ) :
187 m_manager( aManager ),
189 m_path_prefix( aBasePath ),
190 m_lib_prefix( aPrefix )
191 {
192 wxFileName f( aBasePath, "" );
193 m_prefix_dir_count = f.GetDirCount();
194
196 .value_or( nullptr );
198 .value_or( nullptr );
200 .value_or( nullptr );
201 }
202
204 wxDirTraverseResult OnFile( const wxString& aFilePath ) override
205 {
206 wxFileName file = wxFileName::FileName( aFilePath );
207
208 // consider a file to be a lib if it's name ends with .kicad_sym and
209 // it is under $KICADn_3RD_PARTY/symbols/<pkgid>/ i.e. has nested level of at least +2
210 if( file.GetExt() == wxT( "kicad_sym" ) && file.GetDirCount() >= m_prefix_dir_count + 2
211 && file.GetDirs()[m_prefix_dir_count] == wxT( "symbols" ) )
212 {
214 }
215
216 return wxDIR_CONTINUE;
217 }
218
220 wxDirTraverseResult OnDir( const wxString& dirPath ) override
221 {
222 static wxString designBlockExt = wxString::Format( wxS( ".%s" ),
224 wxFileName dir = wxFileName::DirName( dirPath );
225
226 // consider a directory to be a lib if it's name ends with .pretty and
227 // it is under $KICADn_3RD_PARTY/footprints/<pkgid>/ i.e. has nested level of at least +3
228 if( dirPath.EndsWith( wxS( ".pretty" ) ) && dir.GetDirCount() >= m_prefix_dir_count + 3
229 && dir.GetDirs()[m_prefix_dir_count] == wxT( "footprints" ) )
230 {
232 }
233 else if( dirPath.EndsWith( designBlockExt )
234 && dir.GetDirCount() >= m_prefix_dir_count + 3
235 && dir.GetDirs()[m_prefix_dir_count] == wxT( "design_blocks" ) )
236 {
237 addRowIfNecessary( m_designBlockTable, dir, ADD_MODE::AM_DIRECTORY, designBlockExt.Len() );
238 }
239
240 return wxDIR_CONTINUE;
241 }
242
243 std::set<LIBRARY_TABLE*> Modified() const { return m_modified; }
244
245private:
246 void ensureUnique( LIBRARY_TABLE* aTable, const wxString& aBaseName, wxString& aNickname ) const
247 {
248 if( aTable->HasRow( aNickname ) )
249 {
250 int increment = 1;
251
252 do
253 {
254 aNickname = wxString::Format( "%s%s_%d", m_lib_prefix, aBaseName, increment );
255 increment++;
256 } while( aTable->HasRow( aNickname ) );
257 }
258 }
259
260 enum class ADD_MODE
261 {
264 };
265
266 void addRowIfNecessary( LIBRARY_TABLE* aTable, const wxFileName& aSource, ADD_MODE aMode,
267 int aExtensionLength )
268 {
269 wxString versionedPath = wxString::Format( wxS( "${%s}" ),
270 ENV_VAR::GetVersionedEnvVarName( wxS( "3RD_PARTY" ) ) );
271
272 wxArrayString parts = aSource.GetDirs();
273 parts.RemoveAt( 0, m_prefix_dir_count );
274 parts.Insert( versionedPath, 0 );
275
276 if( aMode == ADD_MODE::AM_FILE )
277 parts.Add( aSource.GetFullName() );
278
279 wxString libPath = wxJoin( parts, '/' );
280
281 if( !aTable->HasRowWithURI( libPath, m_project ) )
282 {
283 wxString name = parts.Last().substr( 0, parts.Last().length() - aExtensionLength );
284 wxString nickname = wxString::Format( "%s%s", m_lib_prefix, name );
285
286 ensureUnique( aTable, name, nickname );
287
288 wxLogTrace( traceLibraries, "Manager: Adding PCM lib '%s' as '%s'", libPath, nickname );
289
290 LIBRARY_TABLE_ROW& row = aTable->InsertRow();
291
292 row.SetNickname( nickname );
293 row.SetURI( libPath );
294 row.SetType( wxT( "KiCad" ) );
295 row.SetDescription( _( "Added by Plugin and Content Manager" ) );
296 m_modified.insert( aTable );
297 }
298 else
299 {
300 wxLogTrace( traceLibraries, "Manager: Not adding existing PCM lib '%s'", libPath );
301 }
302 }
303
307 wxString m_lib_prefix;
309 std::set<LIBRARY_TABLE*> m_modified;
310
314};
315
316
318{
319 wxString basePath = PATHS::GetUserSettingsPath();
320
321 wxFileName fn( basePath, tableFileName( aType ) );
322 fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
323
324 return fn.GetFullPath();
325}
326
327
328bool LIBRARY_MANAGER::IsTableValid( const wxString& aPath )
329{
330 if( wxFileName fn( aPath ); fn.IsFileReadable() )
331 {
332 if( LIBRARY_TABLE temp( fn, LIBRARY_TABLE_SCOPE::GLOBAL ); temp.IsOk() )
333 return true;
334 }
335
336 return false;
337}
338
339
341{
342 return InvalidGlobalTables().empty();
343}
344
345
346std::vector<LIBRARY_TABLE_TYPE> LIBRARY_MANAGER::InvalidGlobalTables()
347{
348 std::vector<LIBRARY_TABLE_TYPE> invalidTables;
349 wxString basePath = PATHS::GetUserSettingsPath();
350
354 {
355 if( wxFileName fn( basePath, tableFileName( tableType ) ); !IsTableValid( fn.GetFullPath() ) )
356 invalidTables.emplace_back( tableType );
357 }
358
359 return invalidTables;
360}
361
362
363bool LIBRARY_MANAGER::CreateGlobalTable( LIBRARY_TABLE_TYPE aType, bool aPopulateDefaultLibraries )
364{
365 wxFileName fn( DefaultGlobalTablePath( aType ) );
366
368 table.SetType( aType );
369 table.Rows().clear();
370
371 wxFileName defaultLib( PATHS::GetStockTemplatesPath(), tableFileName( aType ) );
372
373 if( !defaultLib.IsFileReadable() )
374 {
375 wxLogTrace( traceLibraries, "Warning: couldn't read default library table for %s at '%s'",
376 magic_enum::enum_name( aType ), defaultLib.GetFullPath() );
377 }
378
379 if( aPopulateDefaultLibraries )
380 {
381 LIBRARY_TABLE_ROW& chained = table.InsertRow();
383 chained.SetNickname( wxT( "KiCad" ) );
384 chained.SetDescription( _( "KiCad Default Libraries" ) );
385 chained.SetURI( defaultLib.GetFullPath() );
386 }
387
388 try
389 {
390 PRETTIFIED_FILE_OUTPUTFORMATTER formatter( fn.GetFullPath(), KICAD_FORMAT::FORMAT_MODE::LIBRARY_TABLE );
391 table.Format( &formatter );
392 }
393 catch( IO_ERROR& e )
394 {
395 wxLogTrace( traceLibraries, "Exception while saving: %s", e.What() );
396 return false;
397 }
398
399 return true;
400}
401
402
403void LIBRARY_MANAGER::LoadGlobalTables( std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
404{
405 // Cancel any in-progress load
406 {
407 std::scoped_lock lock( m_adaptersMutex );
408
409 for( const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter : m_adapters | std::views::values )
410 adapter->GlobalTablesChanged( aTablesToLoad );
411 }
412
414
416 KICAD_SETTINGS* settings = mgr.GetAppSettings<KICAD_SETTINGS>( "kicad" );
417
418 wxCHECK( settings, /* void */ );
419
420 const ENV_VAR_MAP& vars = Pgm().GetLocalEnvVariables();
421 std::optional<wxString> packagesPath = ENV_VAR::GetVersionedEnvVarValue( vars, wxT( "3RD_PARTY" ) );
422
423 if( packagesPath && settings->m_PcmLibAutoAdd )
424 {
425 // Scan for libraries in PCM packages directory
426 wxFileName d( *packagesPath, "" );
427
428 if( d.DirExists() )
429 {
430 PCM_LIB_TRAVERSER traverser( *packagesPath, *this, settings->m_PcmLibPrefix );
431 wxDir dir( d.GetPath() );
432
433 dir.Traverse( traverser );
434
435 for( LIBRARY_TABLE* table : traverser.Modified() )
436 {
437 table->Save().map_error(
438 []( const LIBRARY_ERROR& aError )
439 {
440 wxLogTrace( traceLibraries, wxT( "Warning: save failed after PCM auto-add: %s" ),
441 aError.message );
442 } );
443 }
444 }
445 }
446
447 auto cleanupRemovedPCMLibraries =
448 [&]( LIBRARY_TABLE_TYPE aType )
449 {
450 LIBRARY_TABLE* table = Table( aType, LIBRARY_TABLE_SCOPE::GLOBAL ).value_or( nullptr );
451 wxCHECK( table, /* void */ );
452
453 auto toErase = std::ranges::remove_if( table->Rows(),
454 [&]( const LIBRARY_TABLE_ROW& aRow )
455 {
456 wxString path = GetFullURI( &aRow, true );
457 return path.StartsWith( *packagesPath ) && !wxFile::Exists( path );
458 } );
459
460 table->Rows().erase( toErase.begin(), toErase.end() );
461
462 if( !toErase.empty() )
463 {
464 table->Save().map_error(
465 []( const LIBRARY_ERROR& aError )
466 {
467 wxLogTrace( traceLibraries, wxT( "Warning: save failed after PCM auto-remove: %s" ),
468 aError.message );
469 } );
470 }
471 };
472
473 if( packagesPath && settings->m_PcmLibAutoRemove )
474 {
475 cleanupRemovedPCMLibraries( LIBRARY_TABLE_TYPE::SYMBOL );
476 cleanupRemovedPCMLibraries( LIBRARY_TABLE_TYPE::FOOTPRINT );
477 cleanupRemovedPCMLibraries( LIBRARY_TABLE_TYPE::DESIGN_BLOCK );
478 }
479}
480
481
482void LIBRARY_MANAGER::LoadProjectTables( std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
483{
484 LoadProjectTables( Pgm().GetSettingsManager().Prj().GetProjectDirectory(), aTablesToLoad );
485}
486
487
489{
490 LoadProjectTables( Pgm().GetSettingsManager().Prj().GetProjectDirectory() );
491
492 std::scoped_lock lock( m_adaptersMutex );
493
494 for( const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter : m_adapters | std::views::values )
495 adapter->ProjectChanged();
496}
497
498
500 std::unique_ptr<LIBRARY_MANAGER_ADAPTER>&& aAdapter )
501{
502 std::scoped_lock lock( m_adaptersMutex );
503
504 wxCHECK_MSG( !m_adapters.contains( aType ), /**/, "You should only register an adapter once!" );
505
506 m_adapters[aType] = std::move( aAdapter );
507}
508
509
511{
512 std::scoped_lock lock( m_adaptersMutex );
513 if( !m_adapters.contains( aType ) )
514 return false;
515
516 if( m_adapters[aType].get() != aAdapter )
517 return false;
518
519 m_adapters.erase( aType );
520 return true;
521}
522
523
524std::optional<LIBRARY_MANAGER_ADAPTER*> LIBRARY_MANAGER::Adapter( LIBRARY_TABLE_TYPE aType ) const
525{
526 std::scoped_lock lock( m_adaptersMutex );
527
528 if( m_adapters.contains( aType ) )
529 return m_adapters.at( aType ).get();
530
531 return std::nullopt;
532}
533
534
535std::optional<LIBRARY_TABLE*> LIBRARY_MANAGER::Table( LIBRARY_TABLE_TYPE aType,
536 LIBRARY_TABLE_SCOPE aScope )
537{
538 switch( aScope )
539 {
542 wxCHECK_MSG( false, std::nullopt, "Table() requires a single scope" );
543
545 {
546 if( !m_tables.contains( aType ) )
547 {
548 wxLogTrace( traceLibraries, "WARNING: missing global table (%s)",
549 magic_enum::enum_name( aType ) );
550 return std::nullopt;
551 }
552
553 return m_tables.at( aType ).get();
554 }
555
557 {
558 // TODO: handle multiple projects
559 if( !m_projectTables.contains( aType ) )
560 {
561 if( !Pgm().GetSettingsManager().Prj().IsNullProject() )
563 else
564 return std::nullopt;
565 }
566
567 return m_projectTables.at( aType ).get();
568 }
569 }
570
571 return std::nullopt;
572}
573
574
575std::vector<LIBRARY_TABLE_ROW*> LIBRARY_MANAGER::Rows( LIBRARY_TABLE_TYPE aType,
576 LIBRARY_TABLE_SCOPE aScope,
577 bool aIncludeInvalid ) const
578{
579 std::map<wxString, LIBRARY_TABLE_ROW*> rows;
580 std::vector<wxString> rowOrder;
581
582 std::list<std::ranges::ref_view<
583 const std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>
584 >> tables;
585
586 switch( aScope )
587 {
589 tables = { std::views::all( m_tables ) };
590 break;
591
593 tables = { std::views::all( m_projectTables ) };
594 break;
595
597 tables = { std::views::all( m_tables ), std::views::all( m_projectTables ) };
598 break;
599
601 wxFAIL;
602 }
603
604 std::function<void(const std::unique_ptr<LIBRARY_TABLE>&)> processTable =
605 [&]( const std::unique_ptr<LIBRARY_TABLE>& aTable )
606 {
607 if( aTable->Type() != aType )
608 return;
609
610 if( aTable->IsOk() || aIncludeInvalid )
611 {
612 for( LIBRARY_TABLE_ROW& row : aTable->Rows() )
613 {
614 if( row.IsOk() || aIncludeInvalid )
615 {
616 if( row.Type() == LIBRARY_TABLE_ROW::TABLE_TYPE_NAME )
617 {
618 if( !m_childTables.contains( row.URI() ) )
619 continue;
620
621 processTable( m_childTables.at( row.URI() ) );
622 }
623 else
624 {
625 if( !rows.contains( row.Nickname() ) )
626 rowOrder.emplace_back( row.Nickname() );
627
628 rows[ row.Nickname() ] = &row;
629 }
630 }
631 }
632 }
633 };
634
635 for( const std::unique_ptr<LIBRARY_TABLE>& table :
636 std::views::join( tables ) | std::views::values )
637 {
638 processTable( table );
639 }
640
641 std::vector<LIBRARY_TABLE_ROW*> ret;
642
643 for( const wxString& row : rowOrder )
644 ret.emplace_back( rows[row] );
645
646 return ret;
647}
648
649
650std::optional<LIBRARY_TABLE_ROW*> LIBRARY_MANAGER::GetRow( LIBRARY_TABLE_TYPE aType,
651 const wxString& aNickname,
652 LIBRARY_TABLE_SCOPE aScope ) const
653{
654 for( LIBRARY_TABLE_ROW* row : Rows( aType, aScope, true ) )
655 {
656 if( row->Nickname() == aNickname )
657 return row;
658 }
659
660 return std::nullopt;
661}
662
663
664std::optional<LIBRARY_TABLE_ROW*> LIBRARY_MANAGER::FindRowByURI( LIBRARY_TABLE_TYPE aType,
665 const wxString& aUri,
666 LIBRARY_TABLE_SCOPE aScope ) const
667{
668 for( LIBRARY_TABLE_ROW* row : Rows( aType, aScope, true ) )
669 {
670 if( UrisAreEquivalent( GetFullURI( row, true ), aUri ) )
671 return row;
672 }
673
674 return std::nullopt;
675}
676
677
678void LIBRARY_MANAGER::ReloadLibraryEntry( LIBRARY_TABLE_TYPE aType, const wxString& aNickname,
679 LIBRARY_TABLE_SCOPE aScope )
680{
681 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter = Adapter( aType ); adapter )
682 ( *adapter )->ReloadLibraryEntry( aNickname, aScope );
683}
684
685
686void LIBRARY_MANAGER::LoadProjectTables( const wxString& aProjectPath,
687 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
688{
689 if( wxFileName::IsDirReadable( aProjectPath ) )
690 {
691 loadTables( aProjectPath, LIBRARY_TABLE_SCOPE::PROJECT, aTablesToLoad );
692 }
693 else
694 {
695 m_projectTables.clear();
696 wxLogTrace( traceLibraries, "New project path %s is not readable, not loading project tables",
697 aProjectPath );
698 }
699}
700
701
703 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
704{
705 if( aScope == LIBRARY_TABLE_SCOPE::PROJECT )
706 LoadProjectTables( aTablesToLoad );
707 else
708 LoadGlobalTables( aTablesToLoad );
709}
710
711
712std::optional<wxString> LIBRARY_MANAGER::GetFullURI( LIBRARY_TABLE_TYPE aType,
713 const wxString& aNickname,
714 bool aSubstituted ) const
715{
716 if( std::optional<const LIBRARY_TABLE_ROW*> result = GetRow( aType, aNickname ) )
717 return GetFullURI( *result, aSubstituted );
718
719 return std::nullopt;
720}
721
722
724 bool aSubstituted )
725{
726 if( aSubstituted )
727 return ExpandEnvVarSubstitutions( aRow->URI(), nullptr );
728
729 return aRow->URI();
730}
731
732
733wxString LIBRARY_MANAGER::ExpandURI( const wxString& aShortURI, const PROJECT& aProject )
734{
735 wxFileName path( ExpandEnvVarSubstitutions( aShortURI, &aProject ) );
736 path.MakeAbsolute();
737 return path.GetFullPath();
738}
739
740
741bool LIBRARY_MANAGER::UrisAreEquivalent( const wxString& aURI1, const wxString& aURI2 )
742{
743 // Avoid comparing filenames as wxURIs
744 if( aURI1.Find( "://" ) != wxNOT_FOUND )
745 {
746 // found as full path
747 return aURI1 == aURI2;
748 }
749 else
750 {
751 const wxFileName fn1( aURI1 );
752 const wxFileName fn2( aURI2 );
753
754 // This will also test if the file is a symlink so if we are comparing
755 // a symlink to the same real file, the comparison will be true. See
756 // wxFileName::SameAs() in the wxWidgets source.
757
758 // found as full path and file name
759 return fn1 == fn2;
760 }
761}
762
763
767
768
773
774
778
779
784
785
787{
788 abortLoad();
789
790 {
791 std::lock_guard lock( m_libraries_mutex );
792 m_libraries.clear();
793 }
794}
795
796
797void LIBRARY_MANAGER_ADAPTER::GlobalTablesChanged( std::initializer_list<LIBRARY_TABLE_TYPE> aChangedTables )
798{
799 bool me = aChangedTables.size() == 0;
800
801 for( LIBRARY_TABLE_TYPE type : aChangedTables )
802 {
803 if( type == Type() )
804 {
805 me = true;
806 break;
807 }
808 }
809
810 if( !me )
811 return;
812
813 abortLoad();
814
815 {
816 std::lock_guard lock( globalLibsMutex() );
817 globalLibs().clear();
818 }
819}
820
821
823{
824 abortLoad();
825
827
828 if( plugin.has_value() )
829 {
830 LIB_DATA lib;
831 lib.row = &aRow;
832 lib.plugin.reset( *plugin );
833
834 std::optional<LIB_STATUS> status = LoadOne( &lib );
835
836 if( status.has_value() )
837 {
838 aRow.SetOk( status.value().load_status == LOAD_STATUS::LOADED );
839
840 if( status.value().error.has_value() )
841 aRow.SetErrorDescription( status.value().error.value().message );
842 }
843 }
844 else
845 {
846 aRow.SetOk( false );
847 aRow.SetErrorDescription( plugin.error().message );
848 }
849}
850
851
852
854{
855 wxCHECK( m_manager.Table( Type(), LIBRARY_TABLE_SCOPE::GLOBAL ), nullptr );
856 return *m_manager.Table( Type(), LIBRARY_TABLE_SCOPE::GLOBAL );
857}
858
859
860std::optional<LIBRARY_TABLE*> LIBRARY_MANAGER_ADAPTER::ProjectTable() const
861{
863}
864
865
866std::optional<wxString> LIBRARY_MANAGER_ADAPTER::FindLibraryByURI( const wxString& aURI ) const
867{
868 for( const LIBRARY_TABLE_ROW* row : m_manager.Rows( Type() ) )
869 {
870 if( LIBRARY_MANAGER::UrisAreEquivalent( row->URI(), aURI ) )
871 return row->Nickname();
872 }
873
874 return std::nullopt;
875}
876
877
878std::vector<wxString> LIBRARY_MANAGER_ADAPTER::GetLibraryNames() const
879{
880 std::vector<wxString> ret;
881
882 for( const LIBRARY_TABLE_ROW* row : m_manager.Rows( Type() ) )
883 {
884 if( fetchIfLoaded( row->Nickname() ) )
885 ret.emplace_back( row->Nickname() );
886 }
887
888 return ret;
889}
890
891
892bool LIBRARY_MANAGER_ADAPTER::HasLibrary( const wxString& aNickname,
893 bool aCheckEnabled ) const
894{
895 if( std::optional<const LIB_DATA*> r = fetchIfLoaded( aNickname ); r.has_value() )
896 return !aCheckEnabled || !( *r )->row->Disabled();
897
898 return false;
899}
900
901
902bool LIBRARY_MANAGER_ADAPTER::DeleteLibrary( const wxString& aNickname )
903{
904 if( LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( aNickname ); result.has_value() )
905 {
906 LIB_DATA* data = *result;
907 std::map<std::string, UTF8> options = data->row->GetOptionsMap();
908
909 try
910 {
911 return data->plugin->DeleteLibrary( getUri( data->row ), &options );
912 }
913 catch( ... )
914 {
915 return false;
916 }
917 }
918
919 return false;
920}
921
922
923std::optional<wxString> LIBRARY_MANAGER_ADAPTER::GetLibraryDescription( const wxString& aNickname ) const
924{
925 if( std::optional<const LIB_DATA*> optRow = fetchIfLoaded( aNickname ); optRow )
926 return ( *optRow )->row->Description();
927
928 return std::nullopt;
929}
930
931
932std::vector<LIBRARY_TABLE_ROW*> LIBRARY_MANAGER_ADAPTER::Rows( LIBRARY_TABLE_SCOPE aScope,
933 bool aIncludeInvalid ) const
934{
935 return m_manager.Rows( Type(), aScope, aIncludeInvalid );
936}
937
938
939std::optional<LIBRARY_TABLE_ROW*> LIBRARY_MANAGER_ADAPTER::GetRow( const wxString &aNickname,
940 LIBRARY_TABLE_SCOPE aScope ) const
941{
942 return m_manager.GetRow( Type(), aNickname, aScope );
943}
944
945
946std::optional<LIBRARY_TABLE_ROW*> LIBRARY_MANAGER_ADAPTER::FindRowByURI(
947 const wxString& aUri,
948 LIBRARY_TABLE_SCOPE aScope ) const
949{
950 return m_manager.FindRowByURI( Type(), aUri, aScope );
951}
952
953
955{
956 if( m_futures.empty() )
957 return;
958
959 wxLogTrace( traceLibraries, "Aborting library load..." );
960 m_abort.store( true );
961
963 wxLogTrace( traceLibraries, "Aborted" );
964
965 m_abort.store( false );
966 m_futures.clear();
967 m_loadTotal = 0;
968}
969
970
972{
973 if( m_loadTotal == 0 )
974 return std::nullopt;
975
976 size_t loaded = m_loadCount.load();
977 return loaded / static_cast<float>( m_loadTotal );
978}
979
980
982{
983 for( const std::future<void>& future : m_futures )
984 future.wait();
985}
986
987
988bool LIBRARY_MANAGER_ADAPTER::IsLibraryLoaded( const wxString& aNickname )
989{
990 // TODO: row->IsOK() doesn't actually tell you if a library is loaded
991 // Once we are preloading libraries we can cache the status of plugin load instead
992
993 if( m_libraries.contains( aNickname ) )
994 return m_libraries[aNickname].row->IsOk();
995
996 if( globalLibs().contains( aNickname ) )
997 return globalLibs()[aNickname].row->IsOk();
998
999 return false;
1000}
1001
1002
1003std::optional<LIBRARY_ERROR> LIBRARY_MANAGER_ADAPTER::LibraryError( const wxString& aNickname ) const
1004{
1005 if( m_libraries.contains( aNickname ) )
1006 {
1007 return m_libraries.at( aNickname ).status.error;
1008 }
1009
1010 if( globalLibs().contains( aNickname ) )
1011 {
1012 return globalLibs().at( aNickname ).status.error;
1013 }
1014
1015 return std::nullopt;
1016}
1017
1018
1019std::vector<std::pair<wxString, LIB_STATUS>> LIBRARY_MANAGER_ADAPTER::GetLibraryStatuses() const
1020{
1021 std::vector<std::pair<wxString, LIB_STATUS>> ret;
1022
1023 for( const LIBRARY_TABLE_ROW* row : m_manager.Rows( Type() ) )
1024 {
1025 if( std::optional<LIB_STATUS> result = GetLibraryStatus( row->Nickname() ) )
1026 {
1027 ret.emplace_back( std::make_pair( row->Nickname(), *result ) );
1028 }
1029 else
1030 {
1031 // This should probably never happen, but until that can be proved...
1032 ret.emplace_back( std::make_pair( row->Nickname(), LIB_STATUS( {
1033 .load_status = LOAD_STATUS::LOAD_ERROR,
1034 .error = LIBRARY_ERROR( _( "Library not found in library table" ) )
1035 } ) ) );
1036 }
1037 }
1038
1039 return ret;
1040}
1041
1042
1044{
1045 wxString errors;
1046
1047 for( const auto& [nickname, status] : GetLibraryStatuses() )
1048 {
1049 if( status.load_status == LOAD_STATUS::LOAD_ERROR && status.error )
1050 {
1051 if( !errors.IsEmpty() )
1052 errors += wxS( "\n" );
1053
1054 errors += wxString::Format( _( "Library '%s': %s" ),
1055 nickname, status.error->message );
1056 }
1057 }
1058
1059 return errors;
1060}
1061
1062
1063void LIBRARY_MANAGER_ADAPTER::ReloadLibraryEntry( const wxString& aNickname,
1064 LIBRARY_TABLE_SCOPE aScope )
1065{
1066 auto reloadScope =
1067 [&]( LIBRARY_TABLE_SCOPE aScopeToReload, std::map<wxString, LIB_DATA>& aTarget,
1068 std::mutex& aMutex )
1069 {
1070 bool wasLoaded = false;
1071
1072 {
1073 std::lock_guard lock( aMutex );
1074 auto it = aTarget.find( aNickname );
1075
1076 if( it != aTarget.end() && it->second.plugin )
1077 {
1078 wasLoaded = true;
1079 aTarget.erase( it );
1080 }
1081 }
1082
1083 if( wasLoaded )
1084 {
1086 loadFromScope( aNickname, aScopeToReload, aTarget, aMutex );
1087 !result.has_value() )
1088 {
1089 wxLogTrace( traceLibraries,
1090 "ReloadLibraryEntry: failed to reload %s (%s): %s",
1091 aNickname, magic_enum::enum_name( aScopeToReload ),
1092 result.error().message );
1093 }
1094 }
1095 };
1096
1097 switch( aScope )
1098 {
1101 break;
1102
1105 break;
1106
1111 break;
1112 }
1113}
1114
1115
1116bool LIBRARY_MANAGER_ADAPTER::IsWritable( const wxString& aNickname ) const
1117{
1118 if( std::optional<const LIB_DATA*> result = fetchIfLoaded( aNickname ) )
1119 {
1120 const LIB_DATA* rowData = *result;
1121 return rowData->plugin->IsLibraryWritable( getUri( rowData->row ) );
1122 }
1123
1124 return false;
1125}
1126
1127
1128bool LIBRARY_MANAGER_ADAPTER::CreateLibrary( const wxString& aNickname )
1129{
1130 if( LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( aNickname ); result.has_value() )
1131 {
1132 LIB_DATA* data = *result;
1133 std::map<std::string, UTF8> options = data->row->GetOptionsMap();
1134
1135 try
1136 {
1137 data->plugin->CreateLibrary( getUri( data->row ), &options );
1138 return true;
1139 }
1140 catch( ... )
1141 {
1142 return false;
1143 }
1144 }
1145
1146 return false;
1147}
1148
1149
1151{
1152 return LIBRARY_MANAGER::ExpandURI( aRow->URI(), Pgm().GetSettingsManager().Prj() );
1153}
1154
1155
1156std::optional<const LIB_DATA*> LIBRARY_MANAGER_ADAPTER::fetchIfLoaded( const wxString& aNickname ) const
1157{
1158 if( m_libraries.contains( aNickname ) && m_libraries.at( aNickname ).status.load_status == LOAD_STATUS::LOADED )
1159 return &m_libraries.at( aNickname );
1160
1161 if( globalLibs().contains( aNickname ) && globalLibs().at( aNickname ).status.load_status == LOAD_STATUS::LOADED )
1162 return &globalLibs().at( aNickname );
1163
1164 return std::nullopt;
1165}
1166
1167
1168std::optional<LIB_DATA*> LIBRARY_MANAGER_ADAPTER::fetchIfLoaded( const wxString& aNickname )
1169{
1170 if( m_libraries.contains( aNickname ) && m_libraries.at( aNickname ).status.load_status == LOAD_STATUS::LOADED )
1171 return &m_libraries.at( aNickname );
1172
1173 if( globalLibs().contains( aNickname ) && globalLibs().at( aNickname ).status.load_status == LOAD_STATUS::LOADED )
1174 return &globalLibs().at( aNickname );
1175
1176 return std::nullopt;
1177}
1178
1179
1181 LIBRARY_TABLE_SCOPE aScope, std::map<wxString,
1182 LIB_DATA>& aTarget, std::mutex& aMutex )
1183{
1184 bool present = false;
1185
1186 {
1187 std::lock_guard lock( aMutex );
1188 present = aTarget.contains( aNickname ) && aTarget.at( aNickname ).plugin;
1189 }
1190
1191 if( !present )
1192 {
1193 if( auto result = m_manager.GetRow( Type(), aNickname, aScope ) )
1194 {
1195 const LIBRARY_TABLE_ROW* row = *result;
1196 wxLogTrace( traceLibraries, "Library %s (%s) not yet loaded, will attempt...",
1197 aNickname, magic_enum::enum_name( aScope ) );
1198
1199 if( LIBRARY_RESULT<IO_BASE*> plugin = createPlugin( row ); plugin.has_value() )
1200 {
1201 std::lock_guard lock( aMutex );
1202
1203 aTarget[ row->Nickname() ].status.load_status = LOAD_STATUS::LOADING;
1204 aTarget[ row->Nickname() ].row = row;
1205 aTarget[ row->Nickname() ].plugin.reset( *plugin );
1206
1207 return &aTarget.at( aNickname );
1208 }
1209 else
1210 {
1211 return tl::unexpected( plugin.error() );
1212 }
1213 }
1214
1215 return nullptr;
1216 }
1217
1218 return &aTarget.at( aNickname );
1219}
1220
1221
1223{
1226
1227 if( !result.has_value() || *result )
1228 return result;
1229
1231
1232 if( !result.has_value() || *result )
1233 return result;
1234
1235 wxString msg = wxString::Format( _( "Library %s not found" ), aNickname );
1236 return tl::unexpected( LIBRARY_ERROR( msg ) );
1237}
const char * name
virtual bool DeleteLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr)
Delete an existing library and returns true, or if library does not exist returns false,...
Definition io_base.cpp:53
virtual bool IsLibraryWritable(const wxString &aLibraryPath)
Return true if the library at aLibraryPath is writable.
Definition io_base.cpp:60
virtual void CreateLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr)
Create a new empty library at aLibraryPath empty.
Definition io_base.cpp:46
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
wxString m_PcmLibPrefix
The interface used by the classes that actually can load IO plugins for the different parts of KiCad ...
std::optional< float > AsyncLoadProgress() const
Returns async load progress between 0.0 and 1.0, or nullopt if load is not in progress.
virtual std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib)=0
virtual std::optional< LIBRARY_ERROR > LibraryError(const wxString &aNickname) const
void ReloadLibraryEntry(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
std::optional< LIBRARY_TABLE * > ProjectTable() const
Retrieves the project library table for this adapter type, or nullopt if one doesn't exist.
LIBRARY_TABLE * GlobalTable() const
Retrieves the global library table for this adapter type.
LIBRARY_MANAGER_ADAPTER(LIBRARY_MANAGER &aManager)
Constructs a type-specific adapter into the library manager.
void CheckTableRow(LIBRARY_TABLE_ROW &aRow)
bool IsLibraryLoaded(const wxString &aNickname)
std::vector< LIBRARY_TABLE_ROW * > Rows(LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH, bool aIncludeInvalid=false) const
Like LIBRARY_MANAGER::Rows but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< LIBRARY_TABLE_ROW * > FindRowByURI(const wxString &aUri, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::FindRowByURI but filtered to the LIBRARY_TABLE_TYPE of this adapter.
virtual std::map< wxString, LIB_DATA > & globalLibs()=0
virtual std::mutex & globalLibsMutex()=0
virtual LIBRARY_TABLE_TYPE Type() const =0
The type of library table this adapter works with.
bool DeleteLibrary(const wxString &aNickname)
Deletes the given library from disk if it exists; returns true if deleted.
LIBRARY_RESULT< LIB_DATA * > loadIfNeeded(const wxString &aNickname)
Fetches a loaded library, triggering a load of that library if it isn't loaded yet.
wxString GetLibraryLoadErrors() const
Returns all library load errors as newline-separated strings for display.
std::optional< wxString > FindLibraryByURI(const wxString &aURI) const
virtual std::optional< LIB_STATUS > GetLibraryStatus(const wxString &aNickname) const =0
Returns the status of a loaded library, or nullopt if the library hasn't been loaded (yet)
LIBRARY_MANAGER & Manager() const
void abortLoad()
Aborts any async load in progress; blocks until fully done aborting.
std::optional< wxString > GetLibraryDescription(const wxString &aNickname) const
virtual LIBRARY_RESULT< IO_BASE * > createPlugin(const LIBRARY_TABLE_ROW *row)=0
Creates a concrete plugin for the given row.
void GlobalTablesChanged(std::initializer_list< LIBRARY_TABLE_TYPE > aChangedTables={})
Notify the adapter that the global library tables have changed.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::map< wxString, LIB_DATA > m_libraries
virtual IO_BASE * plugin(const LIB_DATA *aRow)=0
std::vector< wxString > GetLibraryNames() const
Returns a list of library nicknames that are available (skips any that failed to load)
virtual void ProjectChanged()
Notify the adapter that the active project has changed.
std::vector< std::future< void > > m_futures
static wxString getUri(const LIBRARY_TABLE_ROW *aRow)
LIBRARY_RESULT< LIB_DATA * > loadFromScope(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope, std::map< wxString, LIB_DATA > &aTarget, std::mutex &aMutex)
bool CreateLibrary(const wxString &aNickname)
Creates the library (i.e. saves to disk) for the given row if it exists.
virtual bool IsWritable(const wxString &aNickname) const
Return true if the given nickname exists and is not a read-only library.
std::vector< std::pair< wxString, LIB_STATUS > > GetLibraryStatuses() const
Returns a list of all library nicknames and their status (even if they failed to load)
std::atomic< size_t > m_loadCount
LIBRARY_MANAGER & m_manager
std::optional< const LIB_DATA * > fetchIfLoaded(const wxString &aNickname) const
void ReloadTables(LIBRARY_TABLE_SCOPE aScope, std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
static wxString ExpandURI(const wxString &aShortURI, const PROJECT &aProject)
std::optional< LIBRARY_MANAGER_ADAPTER * > Adapter(LIBRARY_TABLE_TYPE aType) const
std::map< wxString, std::unique_ptr< LIBRARY_TABLE > > m_childTables
Map of full URI to table object for tables that are referenced by global or project tables.
void loadNestedTables(LIBRARY_TABLE &aTable)
bool RemoveAdapter(LIBRARY_TABLE_TYPE aType, LIBRARY_MANAGER_ADAPTER *aAdapter)
void ReloadLibraryEntry(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
static bool UrisAreEquivalent(const wxString &aURI1, const wxString &aURI2)
std::mutex m_adaptersMutex
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
void RegisterAdapter(LIBRARY_TABLE_TYPE aType, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > &&aAdapter)
static wxString DefaultGlobalTablePath(LIBRARY_TABLE_TYPE aType)
static std::vector< LIBRARY_TABLE_TYPE > InvalidGlobalTables()
void createEmptyTable(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
static bool GlobalTablesValid()
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_TABLE > > m_projectTables
std::optional< LIBRARY_TABLE_ROW * > FindRowByURI(LIBRARY_TABLE_TYPE aType, const wxString &aUri, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
void LoadProjectTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the project library tables in the given list, or all tables if no list is given
static bool CreateGlobalTable(LIBRARY_TABLE_TYPE aType, bool aPopulateDefaultLibraries)
void loadTables(const wxString &aTablePath, LIBRARY_TABLE_SCOPE aScope, std::vector< LIBRARY_TABLE_TYPE > aTablesToLoad={})
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
static wxString tableFileName(LIBRARY_TABLE_TYPE aType)
std::vector< LIBRARY_TABLE_ROW * > Rows(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH, bool aIncludeInvalid=false) const
Returns a flattened list of libraries of the given type.
void LoadGlobalTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the global library tables in the given list, or all tables if no list is given
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_TABLE > > m_tables
void ProjectChanged()
Notify all adapters that the project has changed.
static bool IsTableValid(const wxString &aPath)
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > > m_adapters
std::optional< LIBRARY_TABLE_ROW * > GetRow(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
void SetNickname(const wxString &aNickname)
void SetOk(bool aOk=true)
void SetType(const wxString &aType)
void SetErrorDescription(const wxString &aDescription)
std::map< std::string, UTF8 > GetOptionsMap() const
void SetDescription(const wxString &aDescription)
static const wxString TABLE_TYPE_NAME
void SetURI(const wxString &aUri)
const wxString & URI() const
const wxString & Nickname() const
LIBRARY_TABLE_ROW & InsertRow()
Builds a new row and inserts it at the end of the table; returning a reference to the row.
LIBRARY_TABLE_SCOPE Scope() const
bool HasRow(const wxString &aNickname) const
bool HasRowWithURI(const wxString &aUri, const PROJECT &aProject, bool aSubstituted=false) const
Returns true if the given (fully-expanded) URI exists as a library in this table.
bool IsOk() const
static wxString GetStockTemplatesPath()
Gets the stock (install) templates path.
Definition paths.cpp:308
static wxString GetUserSettingsPath()
Return the user configuration path used to store KiCad's configuration files.
Definition paths.cpp:612
LIBRARY_TABLE * m_designBlockTable
std::set< LIBRARY_TABLE * > m_modified
LIBRARY_MANAGER & m_manager
std::set< LIBRARY_TABLE * > Modified() const
const PROJECT & m_project
PCM_LIB_TRAVERSER(const wxString &aBasePath, LIBRARY_MANAGER &aManager, const wxString &aPrefix)
void ensureUnique(LIBRARY_TABLE *aTable, const wxString &aBaseName, wxString &aNickname) const
LIBRARY_TABLE * m_symbolTable
wxDirTraverseResult OnDir(const wxString &dirPath) override
Handles footprint library and design block library directories, minimum nest level 3.
void addRowIfNecessary(LIBRARY_TABLE *aTable, const wxFileName &aSource, ADD_MODE aMode, int aExtensionLength)
LIBRARY_TABLE * m_fpTable
wxDirTraverseResult OnFile(const wxString &aFilePath) override
Handles symbol library files, minimum nest level 2.
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition pgm_base.cpp:793
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:132
Container for project specific data.
Definition project.h:65
T * GetAppSettings(const char *aFilename)
Return a handle to the a given settings by type.
static void ResolvePossibleSymlinks(wxFileName &aFilename)
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition common.cpp:557
The common library.
#define _(s)
Functions related to environment variables, including help functions.
static const std::string KiCadDesignBlockLibPathExtension
static const std::string SymbolLibraryTableFileName
static const std::string DesignBlockLibraryTableFileName
static const std::string FootprintLibraryTableFileName
const wxChar *const traceLibraries
Flag to enable library table and library manager tracing.
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
PROJECT & Prj()
Definition kicad.cpp:637
tl::expected< ResultType, LIBRARY_ERROR > LIBRARY_RESULT
LIBRARY_TABLE_TYPE
LIBRARY_TABLE_SCOPE
KICOMMON_API std::optional< wxString > GetVersionedEnvVarValue(const std::map< wxString, ENV_VAR_ITEM > &aMap, const wxString &aBaseName)
Attempt to retrieve the value of a versioned environment variable, such as KICAD8_TEMPLATE_DIR.
Definition env_vars.cpp:86
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
Definition env_vars.cpp:77
SETTINGS_MANAGER * GetSettingsManager()
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
wxString message
std::vector< LIBRARY_TABLE > tables
Storage for an actual loaded library (including library content owned by the plugin)
std::unique_ptr< IO_BASE > plugin
const LIBRARY_TABLE_ROW * row
The overall status of a loaded or loading library.
std::string path
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition wx_filename.h:39