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>
51#include <footprint_info_impl.h>
52#include <footprint.h>
53#include <nlohmann/json.hpp>
57#include <panel_edit_options.h>
68#include <project_pcb.h>
69#include <python_scripting.h>
70#include <string_utils.h>
71#include <thread_pool.h>
72#include <trace_helpers.h>
73#include <widgets/kistatusbar.h>
74
75#include <wx/tokenzr.h>
76
77#include "invoke_pcb_dialog.h"
79#include "pcbnew_jobs_handler.h"
80
84#include <toolbars_pcb_editor.h>
85
86#include <wx/crt.h>
87
88/* init functions defined by swig */
89
90extern "C" PyObject* PyInit__pcbnew( void );
91
92
105static wxString filterFootprints( const wxString& aFilterJson )
106{
107 using json = nlohmann::json;
108
109 try
110 {
111 json input = json::parse( aFilterJson.ToStdString() );
112
113 int pinCount = input.value( "pin_count", 0 );
114 bool zeroFilters = input.value( "zero_filters", true );
115 int maxResults = input.value( "max_results", 400 );
116
117 std::vector<std::unique_ptr<EDA_PATTERN_MATCH>> filterMatchers;
118
119 if( input.contains( "filters" ) && input["filters"].is_array() )
120 {
121 for( const auto& f : input["filters"] )
122 {
123 if( f.is_string() )
124 {
125 wxString pattern = wxString::FromUTF8( f.get<std::string>() );
126 auto matcher = std::make_unique<EDA_PATTERN_MATCH_WILDCARD_ANCHORED>();
127 matcher->SetPattern( pattern.Lower() );
128 filterMatchers.push_back( std::move( matcher ) );
129 }
130 }
131 }
132
133 bool hasFilters = ( pinCount > 0 || !filterMatchers.empty() );
134
135 if( zeroFilters && !hasFilters )
136 return wxS( "[]" );
137
138 PROJECT* project = nullptr;
139
140 if( wxTheApp )
141 {
142 wxWindow* focus = wxWindow::FindFocus();
143 wxWindow* top = focus ? wxGetTopLevelParent( focus ) : wxTheApp->GetTopWindow();
144
145 if( top )
146 {
147 if( KIWAY_HOLDER* holder = dynamic_cast<KIWAY_HOLDER*>( top ) )
148 project = &holder->Prj();
149 }
150 }
151
152 if( !project )
154
156
157 if( !adapter )
158 return wxS( "[]" );
159
160 adapter->AsyncLoad();
161 adapter->BlockUntilLoaded();
162
163 // Iterate through preloaded footprints directly instead of re-reading from disk
164 json output = json::array();
165 int count = 0;
166
167 for( const wxString& nickname : adapter->GetLibraryNames() )
168 {
169 std::vector<FOOTPRINT*> footprints = adapter->GetFootprints( nickname, true );
170
171 for( FOOTPRINT* fp : footprints )
172 {
173 if( !fp )
174 continue;
175
176 // Pin count filter
177 if( pinCount > 0 )
178 {
179 int fpPadCount = fp->GetUniquePadCount( DO_NOT_INCLUDE_NPTH );
180
181 if( fpPadCount != pinCount )
182 continue;
183 }
184
185 // Footprint filter patterns with case-insensitive matching
186 if( !filterMatchers.empty() )
187 {
188 bool matches = false;
189
190 for( const auto& matcher : filterMatchers )
191 {
192 wxString name;
193
194 // If filter contains ':', include library nickname in match string
195 if( matcher->GetPattern().Contains( wxS( ":" ) ) )
196 name = fp->GetFPID().GetLibNickname().wx_str().Lower() + wxS( ":" );
197
198 name += fp->GetFPID().GetLibItemName().wx_str().Lower();
199
200 if( matcher->Find( name ) )
201 {
202 matches = true;
203 break;
204 }
205 }
206
207 if( !matches )
208 continue;
209 }
210
211 wxString libId = fp->GetFPID().Format();
212 output.push_back( libId.ToStdString() );
213
214 if( ++count >= maxResults )
215 break;
216 }
217
218 if( count >= maxResults )
219 break;
220 }
221
222 return wxString::FromUTF8( output.dump() );
223 }
224 catch( const std::exception& e )
225 {
226 return wxS( "[]" );
227 }
228}
229
230
231namespace PCB {
232
233static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
234{
235 // Of course all are virtual overloads, implementations of the KIFACE.
236
237 IFACE( const char* aName, KIWAY::FACE_T aType ) :
238 KIFACE_BASE( aName, aType ),
240 {}
241
242 bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
243
244 void Reset() override;
245
246 void OnKifaceEnd() override;
247
248 wxWindow* CreateKiWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) override
249 {
250 switch( aClassId )
251 {
252 case FRAME_PCB_EDITOR:
253 {
254 auto frame = new PCB_EDIT_FRAME( aKiway, aParent );
255
256 // give the scripting helpers access to our frame
258
259 if( Kiface().IsSingle() )
260 {
261 // only run this under single_top, not under a project manager.
262 frame->CreateServer( KICAD_PCB_PORT_SERVICE_NUMBER );
263 }
264
265 return frame;
266 }
267
269 return new FOOTPRINT_EDIT_FRAME( aKiway, aParent );
270
272 return new FOOTPRINT_VIEWER_FRAME( aKiway, aParent );
273
275 return new FOOTPRINT_CHOOSER_FRAME( aKiway, aParent );
276
278 return new FOOTPRINT_WIZARD_FRAME( aKiway, aParent, FRAME_T( aClassId ) );
279
281 return FOOTPRINT_PREVIEW_PANEL::New( aKiway, aParent, this );
282
284 {
285 DIALOG_CONFIGURE_PATHS dlg( aParent );
286
287 // The dialog's constructor probably failed to set its Kiway because the
288 // dynamic_cast fails when aParent was allocated by a separate compilation
289 // module. So set it directly.
290 dlg.SetKiway( &dlg, aKiway );
291
292 // Use QuasiModal so that HTML help window will work
293 if( dlg.ShowQuasiModal() == wxID_OK )
295
296 // Dialog has completed; nothing to return.
297 return nullptr;
298 }
299
301 InvokePcbLibTableEditor( aKiway, aParent );
302 // Dialog has completed; nothing to return.
303 return nullptr;
304
306 return new PANEL_DISPLAY_OPTIONS( aParent, GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" ) );
307
308 case PANEL_FP_GRIDS:
309 {
310 FOOTPRINT_EDITOR_SETTINGS* cfg = GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" );
311 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
312
313 if( !frame )
314 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
315
316 if( !frame )
317 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
318
319 if( frame )
320 SetUserUnits( frame->GetUserUnits() );
321
322 return new PANEL_GRID_SETTINGS( aParent, this, frame, cfg, FRAME_FOOTPRINT_EDITOR );
323 }
324
328
330 {
331 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
332
333 if( !frame )
334 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
336 if( !frame )
337 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
339 if( frame )
342 return new PANEL_EDIT_OPTIONS( aParent, this, frame, true );
343 }
344
346 {
347 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
348
349 if( !frame )
350 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
351
352 if( !frame )
353 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
354
355 if( frame )
356 SetUserUnits( frame->GetUserUnits() );
357
358 return new PANEL_FP_EDITOR_FIELD_DEFAULTS( aParent );
359 }
360
362 {
363 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
364
365 if( !frame )
366 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
367
368 if( !frame )
369 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
370
371 if( frame )
372 SetUserUnits( frame->GetUserUnits() );
373
374 return new PANEL_FP_EDITOR_GRAPHICS_DEFAULTS( aParent, this );
375 }
376
378 return new class PANEL_FP_USER_LAYER_NAMES( aParent );
379
381 {
382 APP_SETTINGS_BASE* cfg = GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" );
383 TOOLBAR_SETTINGS* tb = GetToolbarSettings<FOOTPRINT_EDIT_TOOLBAR_SETTINGS>( "fpedit-toolbars" );
384
385 std::vector<TOOL_ACTION*> actions;
386 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
387
388 for( TOOL_ACTION* action : ACTION_MANAGER::GetActionList() )
389 actions.push_back( action );
390
391 for( ACTION_TOOLBAR_CONTROL* control : ACTION_TOOLBAR::GetCustomControlList( FRAME_FOOTPRINT_EDITOR ) )
392 controls.push_back( control );
393
394 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, actions, controls );
395 }
396
397 case PANEL_FP_COLORS:
398 return new PANEL_FP_EDITOR_COLOR_SETTINGS( aParent );
399
401 return new PANEL_DISPLAY_OPTIONS( aParent, GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" ) );
402
403 case PANEL_PCB_GRIDS:
404 {
405 PCBNEW_SETTINGS* cfg = GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
406 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_PCB_EDITOR, false );
407
408 if( !frame )
409 frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
410
411 if( !frame )
412 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
413
414 if( frame )
415 SetUserUnits( frame->GetUserUnits() );
416
417 return new PANEL_GRID_SETTINGS( aParent, this, frame, cfg, FRAME_PCB_EDITOR );
418 }
419
421 return new PANEL_PCBNEW_DISPLAY_ORIGIN( aParent, GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" ),
423
425 {
426 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_PCB_EDITOR, false );
427
428 if( !frame )
429 frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
430
431 if( !frame )
432 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
433
434 if( frame )
435 SetUserUnits( frame->GetUserUnits() );
436
437 return new PANEL_EDIT_OPTIONS( aParent, this, frame, false );
438 }
439
440 case PANEL_PCB_COLORS:
441 {
442 BOARD* board = nullptr;
443 EDA_BASE_FRAME* boardProvider = aKiway->Player( FRAME_PCB_EDITOR, false );
444
445 if( boardProvider )
446 board = static_cast<PCB_EDIT_FRAME*>( boardProvider )->GetBoard();
447
448 return new PANEL_PCBNEW_COLOR_SETTINGS( aParent, board );
449 }
450
452 {
453 APP_SETTINGS_BASE* cfg = GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
454 TOOLBAR_SETTINGS* tb = GetToolbarSettings<PCB_EDIT_TOOLBAR_SETTINGS>( "pcbnew-toolbars" );
455
456 std::vector<TOOL_ACTION*> actions;
457 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
458
459 for( TOOL_ACTION* action : ACTION_MANAGER::GetActionList() )
460 actions.push_back( action );
461
462 for( ACTION_TOOLBAR_CONTROL* control : ACTION_TOOLBAR::GetCustomControlList( FRAME_PCB_EDITOR ) )
463 controls.push_back( control );
464
465 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, actions, controls );
466 }
467
469 return new PANEL_PCBNEW_ACTION_PLUGINS( aParent );
470
472 return new PANEL_3D_DISPLAY_OPTIONS( aParent );
473
474 case PANEL_3DV_OPENGL:
475 return new PANEL_3D_OPENGL_OPTIONS( aParent );
476
478 return new PANEL_3D_RAYTRACING_OPTIONS( aParent );
479
481 {
482 APP_SETTINGS_BASE* cfg = GetAppSettings<EDA_3D_VIEWER_SETTINGS>( "3d_viewer" );
483 TOOLBAR_SETTINGS* tb = GetToolbarSettings<EDA_3D_VIEWER_TOOLBAR_SETTINGS>( "3d_viewer-toolbars" );
484
485 std::vector<TOOL_ACTION*> actions;
486 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
487
488 for( TOOL_ACTION* action : ACTION_MANAGER::GetActionList() )
489 actions.push_back( action );
490
491 for( ACTION_TOOLBAR_CONTROL* control : ACTION_TOOLBAR::GetCustomControlList( FRAME_PCB_DISPLAY3D ) )
492 controls.push_back( control );
493
494 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, actions, controls );
495 }
496
497 default:
498 return nullptr;
499 }
500 }
501
512 void* IfaceOrAddress( int aDataId ) override
513 {
514 switch( aDataId )
515 {
517 {
518 // This is the mechanism by which FOOTPRINT_SELECT_WIDGET can get access to the adapter
519 // without directly linking to pcbnew or pcbcommon, going through PROJECT::FootprintLibAdapter
520 PROJECT* project = nullptr;
521
522 if( wxTheApp )
523 {
524 wxWindow* focus = wxWindow::FindFocus();
525 wxWindow* top = focus ? wxGetTopLevelParent( focus ) : wxTheApp->GetTopWindow();
526
527 if( top )
528 {
529 if( KIWAY_HOLDER* holder = dynamic_cast<KIWAY_HOLDER*>( top ) )
530 project = &holder->Prj();
531 }
532 }
533
534 if( !project )
536
538 }
539
541 {
542 // Return function pointer for filtering footprints
543 // Signature: wxString (*)(const wxString& aFilterJson)
544 return reinterpret_cast<void*>( &filterFootprints );
545 }
546
548 return reinterpret_cast<void*>( PyInit__pcbnew );
549
550 default:
551 return nullptr;
552 }
553 }
554
560 void SaveFileAs( const wxString& aProjectBasePath, const wxString& aSrcProjectName,
561 const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
562 const wxString& aSrcFilePath, wxString& aErrors ) override;
563
564 int HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter ) override;
565
566 bool HandleJobConfig( JOB* aJob, wxWindow* aParent ) override;
567
568 void PreloadLibraries( KIWAY* aKiway ) override;
569 void ProjectChanged() override;
570 void CancelPreload( bool aBlock = true ) override;
571
572private:
573 std::unique_ptr<PCBNEW_JOBS_HANDLER> m_jobHandler;
574 std::shared_ptr<BACKGROUND_JOB> m_libraryPreloadBackgroundJob;
575 std::future<void> m_libraryPreloadReturn;
577 std::atomic_bool m_libraryPreloadAbort;
578
579} kiface( "pcbnew", KIWAY::FACE_PCB );
580
581} // namespace
582
583
584using namespace PCB;
585
586
588
589
590// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h.
591// KIFACE_GETTER will not have name mangling due to declaration in kiway.h.
592KIFACE_API KIFACE* KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram )
593{
594 return &kiface;
595}
596
597
598bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
599{
600 // This is process-level-initialization, not project-level-initialization of the DSO.
601 // Do nothing in here pertinent to a project!
603
604 SETTINGS_MANAGER& mgr = aProgram->GetSettingsManager();
605
608
609 // We intentionally register KifaceSettings after FOOTPRINT_EDITOR_SETTINGS and EDA_3D_VIEWER_SETTINGS
610 // In legacy configs, many settings were in a single editor config and the migration routine
611 // for the main editor file will try and call into the now separate settings stores
612 // to move the settings into them
614
615 // Register the footprint editor settings as well because they share a KiFACE and need to be
616 // loaded prior to use to avoid threading deadlocks
618
619 start_common( aCtlBits );
620
621 m_jobHandler = std::make_unique<PCBNEW_JOBS_HANDLER>( aKiway );
622
624 {
625 m_jobHandler->SetReporter( &CLI_REPORTER::GetInstance() );
626 m_jobHandler->SetProgressReporter( &CLI_PROGRESS_REPORTER::GetInstance() );
627 }
628
629 return true;
630}
631
632
634{
635}
636
637
639{
640 end_common();
641}
642
643
644void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aSrcProjectName,
645 const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
646 const wxString& aSrcFilePath, wxString& aErrors )
647{
648 wxFileName destFile( aSrcFilePath );
649 wxString destPath = destFile.GetPathWithSep();
650 wxUniChar pathSep = wxFileName::GetPathSeparator();
651 wxString ext = destFile.GetExt();
652
653 if( destPath.StartsWith( aProjectBasePath + pathSep ) )
654 destPath.Replace( aProjectBasePath, aNewProjectBasePath, false );
655
656 wxString srcProjectFootprintLib = pathSep + aSrcProjectName + wxT( ".pretty" ) + pathSep;
657 wxString newProjectFootprintLib = pathSep + aNewProjectName + wxT( ".pretty" ) + pathSep;
658
659 destPath.Replace( srcProjectFootprintLib, newProjectFootprintLib, true );
660
661 destFile.SetPath( destPath );
662
665 {
666 if( destFile.GetName() == aSrcProjectName )
667 destFile.SetName( aNewProjectName );
668
669 CopySexprFile( aSrcFilePath, destFile.GetFullPath(),
670 [&]( const std::string& token, wxString& value )
671 {
672 if( token == "sheetfile" )
673 {
674 for( const wxString& extension : { wxT( ".sch" ), wxT( ".kicad_sch" ) } )
675 {
676 if( value == aSrcProjectName + extension )
677 {
678 value = aNewProjectName + extension;
679 return true;
680 }
681 else if( value == aProjectBasePath + "/" + aSrcProjectName + extension )
682 {
683 value = aNewProjectBasePath + "/" + aNewProjectName + extension;
684 return true;
685 }
686 else if( value.StartsWith( aProjectBasePath ) )
687 {
688 value.Replace( aProjectBasePath, aNewProjectBasePath, false );
689 return true;
690 }
691 }
692 }
693
694 return false;
695 },
696 aErrors );
697 }
698 else if( ext == FILEEXT::LegacyPcbFileExtension )
699 {
700 if( destFile.GetName() == aSrcProjectName )
701 destFile.SetName( aNewProjectName );
702
703 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
704 }
707 {
708 // Footprints are not project-specific. Keep their source names.
709 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
710 }
712 {
713 // TODO
714 }
715 else if( ext == wxT( "rpt" ) )
716 {
717 // DRC must be the "gold standard". Since we can't guarantee that there aren't
718 // any non-deterministic cases in the save-as algorithm, we don't want to certify
719 // the result with the source's DRC report. Therefore copy it under the old
720 // name.
721 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
722 }
723 else if( destFile.GetName() == FILEEXT::FootprintLibraryTableFileName )
724 {
725 wxFileName libTableFn( aSrcFilePath );
726 LIBRARY_TABLE libTable( libTableFn, LIBRARY_TABLE_SCOPE::PROJECT );
727 libTable.SetPath( destFile.GetFullPath() );
728 libTable.SetType( LIBRARY_TABLE_TYPE::FOOTPRINT );
729
730 for( LIBRARY_TABLE_ROW& row : libTable.Rows() )
731 {
732 wxString uri = row.URI();
733
734 uri.Replace( wxT( "/" ) + aSrcProjectName + wxT( ".pretty" ),
735 wxT( "/" ) + aNewProjectName + wxT( ".pretty" ) );
736
737 row.SetURI( uri );
738 }
739
740 libTable.Save().map_error(
741 [&]( const LIBRARY_ERROR& aError )
742 {
743 wxString msg;
744
745 if( !aErrors.empty() )
746 aErrors += wxT( "\n" );
747
748 msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() );
749 aErrors += msg;
750 } );
751 }
752 else
753 {
754 wxFAIL_MSG( wxT( "Unexpected filetype for Pcbnew::SaveFileAs()" ) );
755 }
756}
757
758
759int IFACE::HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter )
760{
761 return m_jobHandler->RunJob( aJob, aReporter, aProgressReporter );
762}
763
764
765bool IFACE::HandleJobConfig( JOB* aJob, wxWindow* aParent )
766{
767 return m_jobHandler->HandleJobConfig( aJob, aParent );
768}
769
770
772{
773 constexpr static int interval = 150;
774 constexpr static int timeLimit = 120000;
775
776 wxCHECK( aKiway, /* void */ );
777
778 // Use compare_exchange to atomically check and set the flag to prevent race conditions
779 // when PreloadLibraries is called multiple times concurrently (e.g., from project manager
780 // and pcb editor both scheduling via CallAfter)
781 bool expected = false;
782
783 if( !m_libraryPreloadInProgress.compare_exchange_strong( expected, true ) )
784 return;
785
787
789 Pgm().GetBackgroundJobMonitor().Create( _( "Loading Footprint Libraries" ) );
790
791 auto preload =
792 [this, aKiway]() -> void
793 {
794 std::shared_ptr<BACKGROUND_JOB_REPORTER> reporter =
796
798
799 int elapsed = 0;
800 bool aborted = false;
801
802 reporter->Report( _( "Loading Footprint Libraries" ) );
803 adapter->AsyncLoad();
804
805 while( true )
806 {
807 if( m_libraryPreloadAbort.load() )
808 {
809 aborted = true;
810 break;
811 }
812
813 std::this_thread::sleep_for( std::chrono::milliseconds( interval ) );
814
815 if( std::optional<float> loadStatus = adapter->AsyncLoadProgress() )
816 {
817 float progress = *loadStatus;
818 reporter->SetCurrentProgress( progress );
819
820 if( progress >= 1 )
821 break;
822 }
823 else
824 {
825 reporter->SetCurrentProgress( 1 );
826 break;
827 }
828
829 elapsed += interval;
830
831 if( elapsed > timeLimit )
832 break;
833 }
834
835 adapter->BlockUntilLoaded();
836
837 // Check again after blocking - abort may have been requested while we were waiting
838 if( m_libraryPreloadAbort.load() )
839 aborted = true;
840
841 // If aborted, skip operations that use the adapter since the project may have changed
842 // and the adapter's project reference could be stale. This prevents use-after-free
843 // crashes when switching projects during library preload.
844 if( !aborted )
845 {
846 // Collect and report library load errors from adapter
847 wxString errors = adapter->GetLibraryLoadErrors();
848
849 wxLogTrace( traceLibraries,
850 "pcbnew PreloadLibraries: adapter errors.IsEmpty()=%d, length=%zu",
851 errors.IsEmpty(), errors.length() );
852
853 if( !errors.IsEmpty() )
854 {
855 std::vector<LOAD_MESSAGE> messages =
857
858 wxLogTrace( traceLibraries, " -> adapter: collected %zu messages",
859 messages.size() );
860
861 if( !messages.empty() )
862 Pgm().AddLibraryLoadMessages( messages );
863 }
864 else
865 {
866 wxLogTrace( traceLibraries, " -> no errors from footprint adapter" );
867 }
868 }
869 else
870 {
871 wxLogTrace( traceLibraries, "pcbnew PreloadLibraries: aborted, skipping footprint processing" );
872 }
873
874 m_libraryPreloadAbort.store( false );
877 m_libraryPreloadInProgress.store( false );
878
879 // Only send reload notifications if we weren't aborted
880 if( !aborted )
881 {
882 std::string payload = "";
883 aKiway->ExpressMail( FRAME_PCB_EDITOR, MAIL_RELOAD_LIB, payload, nullptr, true );
884 aKiway->ExpressMail( FRAME_FOOTPRINT_EDITOR, MAIL_RELOAD_LIB, payload, nullptr, true );
885 aKiway->ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload, nullptr, true );
886 }
887 };
888
890 m_libraryPreloadReturn = tp.submit_task( preload );
891}
892
893
895{
896 if( m_libraryPreloadInProgress.load() )
897 m_libraryPreloadAbort.store( true );
898}
899
900
901void IFACE::CancelPreload( bool aBlock )
902{
903 if( m_libraryPreloadInProgress.load() )
904 {
905 m_libraryPreloadAbort.store( true );
906
907 if( aBlock )
909 }
910}
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:183
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:294
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:403
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:507
FACE_T
Known KIFACE implementations.
Definition kiway.h:300
@ FACE_PCB
pcbnew DSO
Definition kiway.h:302
virtual void CommonSettingsChanged(int aFlags=0)
Call CommonSettingsChanged() on all KIWAY_PLAYERs.
Definition kiway.cpp:600
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition kiway.cpp:200
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:110
virtual BACKGROUND_JOBS_MONITOR & GetBackgroundJobMonitor() const
Definition pgm_base.h:138
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.
Definition pgm_base.cpp:988
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:132
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:164
#define KIFACE_GETTER
Definition kiway.h:110
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:105
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition pcbnew.cpp:587
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:155
std::atomic_bool m_libraryPreloadInProgress
Definition pcbnew.cpp:576
bool OnKifaceStart(PGM_BASE *aProgram, int aCtlBits, KIWAY *aKiway) override
Typically start_common() is called from here.
Definition pcbnew.cpp:598
void PreloadLibraries(KIWAY *aKiway) override
Definition pcbnew.cpp:771
void ProjectChanged() override
Definition pcbnew.cpp:894
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:644
void CancelPreload(bool aBlock=true) override
Definition pcbnew.cpp:901
std::shared_ptr< BACKGROUND_JOB > m_libraryPreloadBackgroundJob
Definition pcbnew.cpp:574
void * IfaceOrAddress(int aDataId) override
Return a pointer to the requested object.
Definition pcbnew.cpp:512
void Reset() override
Reloads global state.
Definition pcbnew.cpp:633
wxWindow * CreateKiWindow(wxWindow *aParent, int aClassId, KIWAY *aKiway, int aCtlBits=0) override
Create a wxWindow for the current project.
Definition pcbnew.cpp:248
IFACE(const char *aName, KIWAY::FACE_T aType)
Definition pcbnew.cpp:237
std::atomic_bool m_libraryPreloadAbort
Definition pcbnew.cpp:577
int HandleJob(JOB *aJob, REPORTER *aReporter, PROGRESS_REPORTER *aProgressReporter) override
Definition pcbnew.cpp:759
std::unique_ptr< PCBNEW_JOBS_HANDLER > m_jobHandler
Definition pcbnew.cpp:573
bool HandleJobConfig(JOB *aJob, wxWindow *aParent) override
Definition pcbnew.cpp:765
void OnKifaceEnd() override
Called just once just before the DSO is to be unloaded.
Definition pcbnew.cpp:638
std::future< void > m_libraryPreloadReturn
Definition pcbnew.cpp:575
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.