KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbnew.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) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
27#include <pgm_base.h>
28#include <eda_pattern_match.h>
31#include <confirm.h>
32#include <kiface_base.h>
33#include <kiface_ids.h>
34#include <kiway_holder.h>
35#include <pcb_edit_frame.h>
36#include <eda_dde.h>
37#include <macros.h>
38#include <wx/snglinst.h>
39#include <gestfich.h>
40#include <paths.h>
41#include <pcbnew_settings.h>
42#include <footprint.h>
52#include <footprint_info_impl.h>
53#include <footprint.h>
54#include <nlohmann/json.hpp>
58#include <panel_edit_options.h>
69#include <project_pcb.h>
70#include <python_scripting.h>
71#include <string_utils.h>
72#include <thread_pool.h>
73#include <trace_helpers.h>
74#include <widgets/kistatusbar.h>
75
76#include <wx/tokenzr.h>
77
78#include "invoke_pcb_dialog.h"
80#include "pcbnew_jobs_handler.h"
81
85#include <toolbars_pcb_editor.h>
86
87#include <wx/crt.h>
88
89/* init functions defined by swig */
90
91extern "C" PyObject* PyInit__pcbnew( void );
92
93
106static wxString filterFootprints( const wxString& aFilterJson )
107{
108 using json = nlohmann::json;
109
110 try
111 {
112 json input = json::parse( aFilterJson.ToStdString() );
113
114 int pinCount = input.value( "pin_count", 0 );
115 bool zeroFilters = input.value( "zero_filters", true );
116 int maxResults = input.value( "max_results", 400 );
117
118 std::vector<std::unique_ptr<EDA_PATTERN_MATCH>> filterMatchers;
119
120 if( input.contains( "filters" ) && input["filters"].is_array() )
121 {
122 for( const auto& f : input["filters"] )
123 {
124 if( f.is_string() )
125 {
126 wxString pattern = wxString::FromUTF8( f.get<std::string>() );
127 auto matcher = std::make_unique<EDA_PATTERN_MATCH_WILDCARD_ANCHORED>();
128 matcher->SetPattern( pattern.Lower() );
129 filterMatchers.push_back( std::move( matcher ) );
130 }
131 }
132 }
133
134 bool hasFilters = ( pinCount > 0 || !filterMatchers.empty() );
135
136 if( zeroFilters && !hasFilters )
137 return wxS( "[]" );
138
139 PROJECT* project = nullptr;
140
141 if( wxTheApp )
142 {
143 wxWindow* focus = wxWindow::FindFocus();
144 wxWindow* top = focus ? wxGetTopLevelParent( focus ) : wxTheApp->GetTopWindow();
145
146 if( top )
147 {
148 if( KIWAY_HOLDER* holder = dynamic_cast<KIWAY_HOLDER*>( top ) )
149 project = &holder->Prj();
150 }
151 }
152
153 if( !project )
155
157
158 if( !adapter )
159 return wxS( "[]" );
160
161 adapter->AsyncLoad();
162 adapter->BlockUntilLoaded();
163
164 // Iterate through preloaded footprints directly instead of re-reading from disk
165 json output = json::array();
166 int count = 0;
167
168 for( const wxString& nickname : adapter->GetLibraryNames() )
169 {
170 std::vector<FOOTPRINT*> footprints = adapter->GetFootprints( nickname, true );
171
172 for( FOOTPRINT* fp : footprints )
173 {
174 if( !fp )
175 continue;
176
177 // Pin count filter
178 if( pinCount > 0 )
179 {
180 int fpPadCount = fp->GetUniquePadCount( DO_NOT_INCLUDE_NPTH );
181
182 if( fpPadCount != pinCount )
183 continue;
184 }
185
186 // Footprint filter patterns with case-insensitive matching
187 if( !filterMatchers.empty() )
188 {
189 bool matches = false;
190
191 for( const auto& matcher : filterMatchers )
192 {
193 wxString name;
194
195 // If filter contains ':', include library nickname in match string
196 if( matcher->GetPattern().Contains( wxS( ":" ) ) )
197 name = fp->GetFPID().GetLibNickname().wx_str().Lower() + wxS( ":" );
198
199 name += fp->GetFPID().GetLibItemName().wx_str().Lower();
200
201 if( matcher->Find( name ) )
202 {
203 matches = true;
204 break;
205 }
206 }
207
208 if( !matches )
209 continue;
210 }
211
212 wxString libId = fp->GetFPID().Format();
213 output.push_back( libId.ToStdString() );
214
215 if( ++count >= maxResults )
216 break;
217 }
218
219 if( count >= maxResults )
220 break;
221 }
222
223 return wxString::FromUTF8( output.dump() );
224 }
225 catch( const std::exception& e )
226 {
227 return wxS( "[]" );
228 }
229}
230
231
232namespace PCB {
233
234static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
235{
236 // Of course all are virtual overloads, implementations of the KIFACE.
237
238 IFACE( const char* aName, KIWAY::FACE_T aType ) :
239 KIFACE_BASE( aName, aType ),
241 {}
242
243 bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
244
245 void Reset() override;
246
247 void OnKifaceEnd() override;
248
249 wxWindow* CreateKiWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) override
250 {
251 switch( aClassId )
252 {
253 case FRAME_PCB_EDITOR:
254 {
255 auto frame = new PCB_EDIT_FRAME( aKiway, aParent );
256
257 // give the scripting helpers access to our frame
259
260 if( Kiface().IsSingle() )
261 {
262 // only run this under single_top, not under a project manager.
263 frame->CreateServer( KICAD_PCB_PORT_SERVICE_NUMBER );
264 }
265
266 return frame;
267 }
268
270 return new FOOTPRINT_EDIT_FRAME( aKiway, aParent );
271
273 return new FOOTPRINT_VIEWER_FRAME( aKiway, aParent );
274
276 return new FOOTPRINT_CHOOSER_FRAME( aKiway, aParent );
279 return new FOOTPRINT_WIZARD_FRAME( aKiway, aParent, FRAME_T( aClassId ) );
280
282 return FOOTPRINT_PREVIEW_PANEL::New( aKiway, aParent, this );
283
285 {
286 DIALOG_CONFIGURE_PATHS dlg( aParent );
287
288 // The dialog's constructor probably failed to set its Kiway because the
289 // dynamic_cast fails when aParent was allocated by a separate compilation
290 // module. So set it directly.
291 dlg.SetKiway( &dlg, aKiway );
292
293 // Use QuasiModal so that HTML help window will work
294 if( dlg.ShowQuasiModal() == wxID_OK )
296
297 // Dialog has completed; nothing to return.
298 return nullptr;
299 }
300
302 InvokePcbLibTableEditor( aKiway, aParent );
303 // Dialog has completed; nothing to return.
304 return nullptr;
305
307 return new PANEL_DISPLAY_OPTIONS( aParent, GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" ) );
308
309 case PANEL_FP_GRIDS:
310 {
311 FOOTPRINT_EDITOR_SETTINGS* cfg = GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" );
312 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
313
314 if( !frame )
315 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
316
317 if( !frame )
318 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
319
320 if( frame )
321 SetUserUnits( frame->GetUserUnits() );
322
323 return new PANEL_GRID_SETTINGS( aParent, this, frame, cfg, FRAME_FOOTPRINT_EDITOR );
324 }
332 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
334 if( !frame )
335 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
336
337 if( !frame )
338 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
340 if( frame )
343 return new PANEL_EDIT_OPTIONS( aParent, this, frame, true );
344 }
345
347 {
348 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
349
350 if( !frame )
351 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
352
353 if( !frame )
354 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
355
356 if( frame )
357 SetUserUnits( frame->GetUserUnits() );
358
359 return new PANEL_FP_EDITOR_FIELD_DEFAULTS( aParent );
360 }
361
363 {
364 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
365
366 if( !frame )
367 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
368
369 if( !frame )
370 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
371
372 if( frame )
373 SetUserUnits( frame->GetUserUnits() );
374
375 return new PANEL_FP_EDITOR_GRAPHICS_DEFAULTS( aParent, this );
376 }
377
379 return new class PANEL_FP_USER_LAYER_NAMES( aParent );
380
382 {
383 APP_SETTINGS_BASE* cfg = GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" );
384 TOOLBAR_SETTINGS* tb = GetToolbarSettings<FOOTPRINT_EDIT_TOOLBAR_SETTINGS>( "fpedit-toolbars" );
385
386 std::vector<TOOL_ACTION*> actions;
387 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
388
389 for( TOOL_ACTION* action : ACTION_MANAGER::GetActionList() )
390 actions.push_back( action );
391
392 for( ACTION_TOOLBAR_CONTROL* control : ACTION_TOOLBAR::GetCustomControlList( FRAME_FOOTPRINT_EDITOR ) )
393 controls.push_back( control );
394
395 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, actions, controls );
396 }
397
398 case PANEL_FP_COLORS:
399 return new PANEL_FP_EDITOR_COLOR_SETTINGS( aParent );
400
402 return new PANEL_DISPLAY_OPTIONS( aParent, GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" ) );
403
404 case PANEL_PCB_GRIDS:
405 {
406 PCBNEW_SETTINGS* cfg = GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
407 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_PCB_EDITOR, false );
408
409 if( !frame )
410 frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
411
412 if( !frame )
413 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
414
415 if( frame )
416 SetUserUnits( frame->GetUserUnits() );
417
418 return new PANEL_GRID_SETTINGS( aParent, this, frame, cfg, FRAME_PCB_EDITOR );
419 }
420
422 return new PANEL_PCBNEW_DISPLAY_ORIGIN( aParent, GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" ),
424
426 {
427 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_PCB_EDITOR, false );
428
429 if( !frame )
430 frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
431
432 if( !frame )
433 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
434
435 if( frame )
436 SetUserUnits( frame->GetUserUnits() );
437
438 return new PANEL_EDIT_OPTIONS( aParent, this, frame, false );
439 }
440
441 case PANEL_PCB_COLORS:
442 {
443 BOARD* board = nullptr;
444 EDA_BASE_FRAME* boardProvider = aKiway->Player( FRAME_PCB_EDITOR, false );
445
446 if( boardProvider )
447 board = static_cast<PCB_EDIT_FRAME*>( boardProvider )->GetBoard();
448
449 return new PANEL_PCBNEW_COLOR_SETTINGS( aParent, board );
450 }
451
453 {
454 APP_SETTINGS_BASE* cfg = GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
455 TOOLBAR_SETTINGS* tb = GetToolbarSettings<PCB_EDIT_TOOLBAR_SETTINGS>( "pcbnew-toolbars" );
456
457 std::vector<TOOL_ACTION*> actions;
458 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
459
460 for( TOOL_ACTION* action : ACTION_MANAGER::GetActionList() )
461 actions.push_back( action );
462
463 for( ACTION_TOOLBAR_CONTROL* control : ACTION_TOOLBAR::GetCustomControlList( FRAME_PCB_EDITOR ) )
464 controls.push_back( control );
465
466 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, actions, controls );
467 }
468
470 return new PANEL_PCBNEW_ACTION_PLUGINS( aParent );
471
473 return new PANEL_3D_DISPLAY_OPTIONS( aParent );
474
475 case PANEL_3DV_OPENGL:
476 return new PANEL_3D_OPENGL_OPTIONS( aParent );
477
479 return new PANEL_3D_RAYTRACING_OPTIONS( aParent );
480
482 {
483 APP_SETTINGS_BASE* cfg = GetAppSettings<EDA_3D_VIEWER_SETTINGS>( "3d_viewer" );
484 TOOLBAR_SETTINGS* tb = GetToolbarSettings<EDA_3D_VIEWER_TOOLBAR_SETTINGS>( "3d_viewer-toolbars" );
485
486 std::vector<TOOL_ACTION*> actions;
487 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
488
489 for( TOOL_ACTION* action : ACTION_MANAGER::GetActionList() )
490 actions.push_back( action );
491
492 for( ACTION_TOOLBAR_CONTROL* control : ACTION_TOOLBAR::GetCustomControlList( FRAME_PCB_DISPLAY3D ) )
493 controls.push_back( control );
494
495 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, actions, controls );
496 }
497
498 default:
499 return nullptr;
500 }
501 }
502
513 void* IfaceOrAddress( int aDataId ) override
514 {
515 switch( aDataId )
516 {
518 {
519 // This is the mechanism by which FOOTPRINT_SELECT_WIDGET can get access to the adapter
520 // without directly linking to pcbnew or pcbcommon, going through PROJECT::FootprintLibAdapter
521 PROJECT* project = nullptr;
522
523 if( wxTheApp )
524 {
525 wxWindow* focus = wxWindow::FindFocus();
526 wxWindow* top = focus ? wxGetTopLevelParent( focus ) : wxTheApp->GetTopWindow();
527
528 if( top )
529 {
530 if( KIWAY_HOLDER* holder = dynamic_cast<KIWAY_HOLDER*>( top ) )
531 project = &holder->Prj();
532 }
533 }
534
535 if( !project )
537
539 }
540
542 {
543 // Return function pointer for filtering footprints
544 // Signature: wxString (*)(const wxString& aFilterJson)
545 return reinterpret_cast<void*>( &filterFootprints );
546 }
547
549 return reinterpret_cast<void*>( PyInit__pcbnew );
550
551 default:
552 return nullptr;
553 }
554 }
555
561 void SaveFileAs( const wxString& aProjectBasePath, const wxString& aSrcProjectName,
562 const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
563 const wxString& aSrcFilePath, wxString& aErrors ) override;
564
565 int HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter ) override;
566
567 bool HandleJobConfig( JOB* aJob, wxWindow* aParent ) override;
568
569 void PreloadLibraries( KIWAY* aKiway ) override;
570 void ProjectChanged() override;
571 void CancelPreload( bool aBlock = true ) override;
572
573private:
574 std::unique_ptr<PCBNEW_JOBS_HANDLER> m_jobHandler;
575 std::shared_ptr<BACKGROUND_JOB> m_libraryPreloadBackgroundJob;
576 std::future<void> m_libraryPreloadReturn;
578 std::atomic_bool m_libraryPreloadAbort;
579
580} kiface( "pcbnew", KIWAY::FACE_PCB );
581
582} // namespace
583
584
585using namespace PCB;
586
587
589
590
591// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h.
592// KIFACE_GETTER will not have name mangling due to declaration in kiway.h.
593KIFACE_API KIFACE* KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram )
594{
595 return &kiface;
596}
597
598
599bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
600{
601 // This is process-level-initialization, not project-level-initialization of the DSO.
602 // Do nothing in here pertinent to a project!
604
605 SETTINGS_MANAGER& mgr = aProgram->GetSettingsManager();
606
609
610 // We intentionally register KifaceSettings after FOOTPRINT_EDITOR_SETTINGS and EDA_3D_VIEWER_SETTINGS
611 // In legacy configs, many settings were in a single editor config and the migration routine
612 // for the main editor file will try and call into the now separate settings stores
613 // to move the settings into them
615
616 // Register the footprint editor settings as well because they share a KiFACE and need to be
617 // loaded prior to use to avoid threading deadlocks
619
620 start_common( aCtlBits );
621
622 m_jobHandler = std::make_unique<PCBNEW_JOBS_HANDLER>( aKiway );
623
625 {
626 m_jobHandler->SetReporter( &CLI_REPORTER::GetInstance() );
627 m_jobHandler->SetProgressReporter( &CLI_PROGRESS_REPORTER::GetInstance() );
628 }
629
630 return true;
631}
632
633
635{
636}
637
638
640{
641 end_common();
642}
643
644
645void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aSrcProjectName,
646 const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
647 const wxString& aSrcFilePath, wxString& aErrors )
648{
649 wxFileName destFile( aSrcFilePath );
650 wxString destPath = destFile.GetPathWithSep();
651 wxUniChar pathSep = wxFileName::GetPathSeparator();
652 wxString ext = destFile.GetExt();
653
654 if( destPath.StartsWith( aProjectBasePath + pathSep ) )
655 destPath.Replace( aProjectBasePath, aNewProjectBasePath, false );
656
657 wxString srcProjectFootprintLib = pathSep + aSrcProjectName + wxT( ".pretty" ) + pathSep;
658 wxString newProjectFootprintLib = pathSep + aNewProjectName + wxT( ".pretty" ) + pathSep;
659
660 destPath.Replace( srcProjectFootprintLib, newProjectFootprintLib, true );
661
662 destFile.SetPath( destPath );
663
666 {
667 if( destFile.GetName() == aSrcProjectName )
668 destFile.SetName( aNewProjectName );
669
670 CopySexprFile( aSrcFilePath, destFile.GetFullPath(),
671 [&]( const std::string& token, wxString& value )
672 {
673 if( token == "sheetfile" )
674 {
675 for( const wxString extension : { wxT( ".sch" ), wxT( ".kicad_sch" ) } )
676 {
677 if( value == aSrcProjectName + extension )
678 {
679 value = aNewProjectName + extension;
680 return true;
681 }
682 else if( value == aProjectBasePath + "/" + aSrcProjectName + extension )
683 {
684 value = aNewProjectBasePath + "/" + aNewProjectName + extension;
685 return true;
686 }
687 else if( value.StartsWith( aProjectBasePath ) )
688 {
689 value.Replace( aProjectBasePath, aNewProjectBasePath, false );
690 return true;
691 }
692 }
693 }
694
695 return false;
696 },
697 aErrors );
698 }
699 else if( ext == FILEEXT::LegacyPcbFileExtension )
700 {
701 if( destFile.GetName() == aSrcProjectName )
702 destFile.SetName( aNewProjectName );
703
704 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
705 }
708 {
709 // Footprints are not project-specific. Keep their source names.
710 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
711 }
713 {
714 // TODO
715 }
716 else if( ext == wxT( "rpt" ) )
717 {
718 // DRC must be the "gold standard". Since we can't guarantee that there aren't
719 // any non-deterministic cases in the save-as algorithm, we don't want to certify
720 // the result with the source's DRC report. Therefore copy it under the old
721 // name.
722 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
723 }
724 else if( destFile.GetName() == FILEEXT::FootprintLibraryTableFileName )
725 {
726 wxFileName libTableFn( aSrcFilePath );
727 LIBRARY_TABLE libTable( libTableFn, LIBRARY_TABLE_SCOPE::PROJECT );
728 libTable.SetPath( destFile.GetFullPath() );
729 libTable.SetType( LIBRARY_TABLE_TYPE::FOOTPRINT );
730
731 for( LIBRARY_TABLE_ROW& row : libTable.Rows() )
732 {
733 wxString uri = row.URI();
734
735 uri.Replace( wxT( "/" ) + aSrcProjectName + wxT( ".pretty" ),
736 wxT( "/" ) + aNewProjectName + wxT( ".pretty" ) );
737
738 row.SetURI( uri );
739 }
740
741 libTable.Save().map_error(
742 [&]( const LIBRARY_ERROR& aError )
743 {
744 wxString msg;
745
746 if( !aErrors.empty() )
747 aErrors += wxT( "\n" );
748
749 msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() );
750 aErrors += msg;
751 } );
752 }
753 else
754 {
755 wxFAIL_MSG( wxT( "Unexpected filetype for Pcbnew::SaveFileAs()" ) );
756 }
757}
758
759
760int IFACE::HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter )
761{
762 return m_jobHandler->RunJob( aJob, aReporter, aProgressReporter );
763}
764
765
766bool IFACE::HandleJobConfig( JOB* aJob, wxWindow* aParent )
767{
768 return m_jobHandler->HandleJobConfig( aJob, aParent );
769}
770
771
773{
774 constexpr static int interval = 150;
775 constexpr static int timeLimit = 120000;
776
777 wxCHECK( aKiway, /* void */ );
778
779 // Use compare_exchange to atomically check and set the flag to prevent race conditions
780 // when PreloadLibraries is called multiple times concurrently (e.g., from project manager
781 // and pcb editor both scheduling via CallAfter)
782 bool expected = false;
783
784 if( !m_libraryPreloadInProgress.compare_exchange_strong( expected, true ) )
785 return;
786
788
790 Pgm().GetBackgroundJobMonitor().Create( _( "Loading Footprint Libraries" ) );
791
792 auto preload =
793 [this, aKiway]() -> void
794 {
795 std::shared_ptr<BACKGROUND_JOB_REPORTER> reporter =
797
799
800 int elapsed = 0;
801 bool aborted = false;
802
803 reporter->Report( _( "Loading Footprint Libraries" ) );
804 adapter->AsyncLoad();
805
806 while( true )
807 {
808 if( m_libraryPreloadAbort.load() )
809 {
810 aborted = true;
811 break;
812 }
813
814 std::this_thread::sleep_for( std::chrono::milliseconds( interval ) );
815
816 if( std::optional<float> loadStatus = adapter->AsyncLoadProgress() )
817 {
818 float progress = *loadStatus;
819 reporter->SetCurrentProgress( progress );
820
821 if( progress >= 1 )
822 break;
823 }
824 else
825 {
826 reporter->SetCurrentProgress( 1 );
827 break;
828 }
829
830 elapsed += interval;
831
832 if( elapsed > timeLimit )
833 break;
834 }
835
836 adapter->BlockUntilLoaded();
837
838 // Check again after blocking - abort may have been requested while we were waiting
839 if( m_libraryPreloadAbort.load() )
840 aborted = true;
841
842 // If aborted, skip operations that use the adapter since the project may have changed
843 // and the adapter's project reference could be stale. This prevents use-after-free
844 // crashes when switching projects during library preload.
845 if( !aborted )
846 {
847 // Collect and report library load errors from adapter
848 wxString errors = adapter->GetLibraryLoadErrors();
849
850 wxLogTrace( traceLibraries,
851 "pcbnew PreloadLibraries: adapter errors.IsEmpty()=%d, length=%zu",
852 errors.IsEmpty(), errors.length() );
853
854 if( !errors.IsEmpty() )
855 {
856 std::vector<LOAD_MESSAGE> messages =
858
859 wxLogTrace( traceLibraries, " -> adapter: collected %zu messages",
860 messages.size() );
861
862 if( !messages.empty() )
863 Pgm().AddLibraryLoadMessages( messages );
864 }
865 else
866 {
867 wxLogTrace( traceLibraries, " -> no errors from footprint adapter" );
868 }
869 }
870 else
871 {
872 wxLogTrace( traceLibraries, "pcbnew PreloadLibraries: aborted, skipping footprint processing" );
873 }
874
875 m_libraryPreloadAbort.store( false );
878 m_libraryPreloadInProgress.store( false );
879
880 // Only send reload notifications if we weren't aborted
881 if( !aborted )
882 {
883 std::string payload = "";
884 aKiway->ExpressMail( FRAME_PCB_EDITOR, MAIL_RELOAD_LIB, payload, nullptr, true );
885 aKiway->ExpressMail( FRAME_FOOTPRINT_EDITOR, MAIL_RELOAD_LIB, payload, nullptr, true );
886 aKiway->ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload, nullptr, true );
887 }
888 };
889
891 m_libraryPreloadReturn = tp.submit_task( preload );
892}
893
894
896{
897 if( m_libraryPreloadInProgress.load() )
898 m_libraryPreloadAbort.store( true );
899}
900
901
902void IFACE::CancelPreload( bool aBlock )
903{
904 if( m_libraryPreloadInProgress.load() )
905 {
906 m_libraryPreloadAbort.store( true );
907
908 if( aBlock )
910 }
911}
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
static std::list< TOOL_ACTION * > & GetActionList()
Return list of TOOL_ACTIONs.
static std::list< ACTION_TOOLBAR_CONTROL * > GetCustomControlList(FRAME_T aContext)
Get the list of custom controls that could be used on a particular frame type.
std::shared_ptr< BACKGROUND_JOB > Create(const wxString &aName)
Creates a background job with the given name.
void Remove(std::shared_ptr< BACKGROUND_JOB > job)
Removes the given background job from any lists and frees it.
static CLI_PROGRESS_REPORTER & GetInstance()
static CLI_REPORTER & GetInstance()
Definition reporter.cpp:134
The base frame for deriving all KiCad main window classes.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
std::vector< FOOTPRINT * > GetFootprints(const wxString &aNickname, bool aBestEfforts=false)
Retrieves a list of footprints contained in a given loaded library.
static FOOTPRINT_PREVIEW_PANEL * New(KIWAY *aKiway, wxWindow *aParent, UNITS_PROVIDER *aUnitsProvider)
Component library viewer main window.
An simple container class that lets us dispatch output jobs to kifaces.
Definition job.h:184
A KIFACE implementation.
Definition kiface_base.h:39
KIFACE_BASE(const char *aKifaceName, KIWAY::FACE_T aId)
Definition kiface_base.h:67
void InitSettings(APP_SETTINGS_BASE *aSettings)
Definition kiface_base.h:97
void end_common()
Common things to do for a top program module, during OnKifaceEnd();.
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:95
bool start_common(int aCtlBits)
Common things to do for a top program module, during OnKifaceStart().
int m_start_flags
flags provided in OnKifaceStart()
bool IsSingle() const
Is this KIFACE running under single_top?
A mix in class which holds the location of a wxWindow's KIWAY.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:295
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:407
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr, bool aFromOtherThread=false)
Send aPayload to aDestination from aSource.
Definition kiway.cpp:505
FACE_T
Known KIFACE implementations.
Definition kiway.h:301
@ FACE_PCB
pcbnew DSO
Definition kiway.h:303
virtual void CommonSettingsChanged(int aFlags=0)
Call CommonSettingsChanged() on all KIWAY_PLAYERs.
Definition kiway.cpp:599
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition kiway.cpp:207
std::optional< float > AsyncLoadProgress() const
Returns async load progress between 0.0 and 1.0, or nullopt if load is not in progress.
wxString GetLibraryLoadErrors() const
Returns all library load errors as newline-separated strings for display.
std::vector< wxString > GetLibraryNames() const
Returns a list of library nicknames that are available (skips any that failed to load)
void AsyncLoad()
Loads all available libraries for this adapter type in the background.
The main frame for Pcbnew.
Container for data for KiCad programs.
Definition pgm_base.h:109
virtual BACKGROUND_JOBS_MONITOR & GetBackgroundJobMonitor() const
Definition pgm_base.h:137
void ClearLibraryLoadMessages()
Clear library load messages from all registered status bars.
void AddLibraryLoadMessages(const std::vector< LOAD_MESSAGE > &aMessages)
Add library load messages to all registered status bars.
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:131
A progress reporter interface for use in multi-threaded environments.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
Container for project specific data.
Definition project.h:65
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
T * RegisterSettings(T *aSettings, bool aLoadNow=true)
Take ownership of the pointer passed in.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
UNITS_PROVIDER(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits)
EDA_UNITS GetUserUnits() const
void SetUserUnits(EDA_UNITS aUnits)
This file is part of the common library.
#define _(s)
DDE server & client.
#define KICAD_PCB_PORT_SERVICE_NUMBER
Pcbnew listens on this port for commands from Eeschema.
Definition eda_dde.h:40
Abstract pattern-matching tool and implementations.
EDA_UNITS
Definition eda_units.h:48
@ DO_NOT_INCLUDE_NPTH
Definition footprint.h:73
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition frame_type.h:33
@ PANEL_PCB_GRIDS
Definition frame_type.h:98
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ PANEL_3DV_TOOLBARS
Definition frame_type.h:108
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:45
@ PANEL_3DV_OPENGL
Definition frame_type.h:106
@ PANEL_FP_DEFAULT_GRAPHICS_VALUES
Definition frame_type.h:93
@ PANEL_PCB_TOOLBARS
Definition frame_type.h:101
@ PANEL_PCB_ORIGINS_AXES
Definition frame_type.h:103
@ FRAME_FOOTPRINT_WIZARD
Definition frame_type.h:46
@ PANEL_PCB_EDIT_OPTIONS
Definition frame_type.h:99
@ PANEL_FP_DISPLAY_OPTIONS
Definition frame_type.h:87
@ PANEL_PCB_COLORS
Definition frame_type.h:100
@ PANEL_FP_USER_LAYER_NAMES
Definition frame_type.h:94
@ PANEL_3DV_RAYTRACING
Definition frame_type.h:107
@ DIALOG_PCB_LIBRARY_TABLE
Definition frame_type.h:126
@ FRAME_FOOTPRINT_PREVIEW
Definition frame_type.h:48
@ FRAME_FOOTPRINT_CHOOSER
Definition frame_type.h:44
@ PANEL_FP_GRIDS
Definition frame_type.h:88
@ PANEL_FP_ORIGINS_AXES
Definition frame_type.h:95
@ PANEL_PCB_DISPLAY_OPTS
Definition frame_type.h:97
@ DIALOG_CONFIGUREPATHS
Definition frame_type.h:123
@ PANEL_FP_COLORS
Definition frame_type.h:90
@ PANEL_FP_DEFAULT_FIELDS
Definition frame_type.h:92
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:43
@ FRAME_PCB_DISPLAY3D
Definition frame_type.h:47
@ PANEL_FP_EDIT_OPTIONS
Definition frame_type.h:89
@ PANEL_FP_TOOLBARS
Definition frame_type.h:91
@ PANEL_PCB_ACTION_PLUGINS
Definition frame_type.h:102
@ PANEL_3DV_DISPLAY_OPTIONS
Definition frame_type.h:105
@ FRAME_CVPCB
Definition frame_type.h:52
nlohmann::json json
Definition gerbview.cpp:50
void CopySexprFile(const wxString &aSrcPath, const wxString &aDestPath, std::function< bool(const std::string &token, wxString &value)> aCallback, wxString &aErrors)
Definition gestfich.cpp:320
void KiCopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
Definition gestfich.cpp:293
static const std::string LegacyPcbFileExtension
static const std::string FootprintLibraryTableFileName
static const std::string BackupFileSuffix
static const std::string LegacyFootprintLibPathExtension
static const std::string FootprintAssignmentFileExtension
static const std::string KiCadFootprintFileExtension
static const std::string KiCadPcbFileExtension
const wxChar *const traceLibraries
Flag to enable library table and library manager tracing.
#define KIFACE_API
@ KIFACE_SCRIPTING_LEGACY
Definition kiface_ids.h:43
@ KIFACE_FOOTPRINT_LIBRARY_ADAPTER
Definition kiface_ids.h:34
@ KIFACE_FILTER_FOOTPRINTS
Function pointer type: wxString (*)(const wxString& aFilterJson) Input JSON: {"pin_count": N,...
Definition kiface_ids.h:39
#define KFCTL_CLI
Running as CLI app.
Definition kiway.h:165
#define KIFACE_GETTER
Definition kiway.h:111
This file contains miscellaneous commonly used macros and functions.
@ MAIL_RELOAD_LIB
Definition mail_type.h:57
PCB::IFACE KIFACE_BASE, UNITS_PROVIDER kiface("pcbnew", KIWAY::FACE_PCB)
void InvokePcbLibTableEditor(KIWAY *aKiway, wxWindow *aCaller)
Function InvokePcbLibTableEditor shows the modal DIALOG_FP_LIB_TABLE for purposes of editing the glob...
PyObject * PyInit__pcbnew(void)
static wxString filterFootprints(const wxString &aFilterJson)
Filter footprints based on criteria passed as JSON.
Definition pcbnew.cpp:106
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition pcbnew.cpp:588
void ScriptingSetPcbEditFrame(PCB_EDIT_FRAME *aPcbEditFrame)
BOARD * GetBoard()
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
@ RPT_SEVERITY_ERROR
T * GetToolbarSettings(const wxString &aFilename)
T * GetAppSettings(const char *aFilename)
std::vector< LOAD_MESSAGE > ExtractLibraryLoadErrors(const wxString &aErrorString, int aSeverity)
Parse library load error messages, extracting user-facing information while stripping internal code l...
bool OnKifaceStart(PGM_BASE *aProgram, int aCtlBits, KIWAY *aKiway) override
Typically start_common() is called from here.
Implement a participant in the KIWAY alchemy.
Definition kiway.h:156
std::atomic_bool m_libraryPreloadInProgress
Definition pcbnew.cpp:577
bool OnKifaceStart(PGM_BASE *aProgram, int aCtlBits, KIWAY *aKiway) override
Typically start_common() is called from here.
Definition pcbnew.cpp:599
void PreloadLibraries(KIWAY *aKiway) override
Definition pcbnew.cpp:772
void ProjectChanged() override
Definition pcbnew.cpp:895
void SaveFileAs(const wxString &aProjectBasePath, const wxString &aSrcProjectName, const wxString &aNewProjectBasePath, const wxString &aNewProjectName, const wxString &aSrcFilePath, wxString &aErrors) override
Saving a file under a different name is delegated to the various KIFACEs because the project doesn't ...
Definition pcbnew.cpp:645
void CancelPreload(bool aBlock=true) override
Definition pcbnew.cpp:902
std::shared_ptr< BACKGROUND_JOB > m_libraryPreloadBackgroundJob
Definition pcbnew.cpp:575
void * IfaceOrAddress(int aDataId) override
Return a pointer to the requested object.
Definition pcbnew.cpp:513
void Reset() override
Reloads global state.
Definition pcbnew.cpp:634
wxWindow * CreateKiWindow(wxWindow *aParent, int aClassId, KIWAY *aKiway, int aCtlBits=0) override
Create a wxWindow for the current project.
Definition pcbnew.cpp:249
IFACE(const char *aName, KIWAY::FACE_T aType)
Definition pcbnew.cpp:238
std::atomic_bool m_libraryPreloadAbort
Definition pcbnew.cpp:578
int HandleJob(JOB *aJob, REPORTER *aReporter, PROGRESS_REPORTER *aProgressReporter) override
Definition pcbnew.cpp:760
std::unique_ptr< PCBNEW_JOBS_HANDLER > m_jobHandler
Definition pcbnew.cpp:574
bool HandleJobConfig(JOB *aJob, wxWindow *aParent) override
Definition pcbnew.cpp:766
void OnKifaceEnd() override
Called just once just before the DSO is to be unloaded.
Definition pcbnew.cpp:639
std::future< void > m_libraryPreloadReturn
Definition pcbnew.cpp:576
KIBIS top(path, &reporter)
VECTOR3I expected(15, 30, 45)
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
static thread_pool * tp
BS::priority_thread_pool thread_pool
Definition thread_pool.h:31
#define ENVVARS_CHANGED
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.