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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <pgm_base.h>
23#include <eda_pattern_match.h>
26#include <confirm.h>
29#include <api/api_handler_pcb.h>
30#include <api/api_server.h>
31#include <api/api_utils.h>
35#include <kiface_base.h>
36#include <kiface_ids.h>
37#include <kiway_holder.h>
38#include <pcb_edit_frame.h>
39#include <macros.h>
40#include <gestfich.h>
41#include <paths.h>
42#include <pcbnew_settings.h>
43#include <footprint.h>
53#include <footprint_info_impl.h>
54#include <footprint.h>
55#include <board.h>
56#include <board_loader.h>
57#include <lib_id.h>
58#include <nlohmann/json.hpp>
62#include <panel_edit_options.h>
74#include <project_pcb.h>
75#include <string_utils.h>
76#include <thread_pool.h>
77#include <trace_helpers.h>
78#include <widgets/kistatusbar.h>
79
80#include <wx/tokenzr.h>
81
83#include <invoke_pcb_dialog.h>
85#include "pcbnew_jobs_handler.h"
87#include <reporter.h>
88#include "git/kigit_pcb_merge.h"
89#include "git/kigit_fp_merge.h"
91
94#if defined( KICAD_NATIVE_MODEL_PREVIEW ) && defined( __WXGTK3__ )
96#endif
98#include <toolbars_pcb_editor.h>
99
100#include <wx/crt.h>
101
102
108{
109 PROJECT* project = nullptr;
110
111 if( wxTheApp )
112 {
113 wxWindow* focus = wxWindow::FindFocus();
114 wxWindow* top = focus ? wxGetTopLevelParent( focus ) : wxTheApp->GetTopWindow();
115
116 if( top )
117 {
118 if( KIWAY_HOLDER* holder = dynamic_cast<KIWAY_HOLDER*>( top ) )
119 project = &holder->Prj();
120 }
121 }
122
123 if( !project )
125
126 return project;
127}
128
129
144static wxString filterFootprints( const wxString& aFilterJson )
145{
146 using json = nlohmann::json;
147
149 result.m_Success = false;
150
151 try
152 {
153 json input = json::parse( aFilterJson.utf8_string() );
154
155 unsigned pinCount = input.value( "pin_count", 0 );
156 bool zeroFilters = input.value( "zero_filters", true );
157 int maxResults = input.value( "max_results", 400 );
158
159 std::vector<std::unique_ptr<EDA_PATTERN_MATCH>> filterMatchers;
160
161 if( input.contains( "filters" ) && input["filters"].is_array() )
162 {
163 for( const auto& f : input["filters"] )
164 {
165 if( f.is_string() )
166 {
167 wxString pattern = wxString::FromUTF8( f.get<std::string>() );
168 auto matcher = std::make_unique<EDA_PATTERN_MATCH_WILDCARD_ANCHORED>();
169 matcher->SetPattern( pattern.Lower() );
170 filterMatchers.push_back( std::move( matcher ) );
171 }
172 }
173 }
174
175 bool hasFilters = ( pinCount > 0 || !filterMatchers.empty() );
176
177 // A query that can only match nothing is a successful empty result, not a failure.
178 if( zeroFilters && !hasFilters )
179 {
180 result.m_Success = true;
181 return result.ToJsonStr();
182 }
183
185
186 if( !adapter )
187 return result.ToJsonStr();
188
189 adapter->AsyncLoad();
190 adapter->BlockUntilLoaded();
191
192 for( const wxString& nickname : adapter->GetLibraryNames() )
193 {
194 std::vector<FOOTPRINT*> footprints = adapter->GetFootprints( nickname, true );
195
196 for( FOOTPRINT* fp : footprints )
197 {
198 if( !fp )
199 continue;
200
201 // Pin count filter
202 if( pinCount > 0 )
203 {
204 unsigned fpPadCount = fp->GetNumberedPadCount();
205
206 if( fpPadCount != pinCount )
207 continue;
208 }
209
210 // Footprint filter patterns with case-insensitive matching
211 if( !filterMatchers.empty() )
212 {
213 bool matches = false;
214
215 for( const auto& matcher : filterMatchers )
216 {
217 wxString name;
218
219 // If filter contains ':', include library nickname in match string
220 if( matcher->GetPattern().Contains( wxS( ":" ) ) )
221 name = fp->GetFPID().GetLibNickname().wx_str().Lower() + wxS( ":" );
222
223 name += fp->GetFPID().GetLibItemName().wx_str().Lower();
224
225 if( matcher->Find( name ) )
226 {
227 matches = true;
228 break;
229 }
230 }
231
232 if( !matches )
233 continue;
234 }
235
236 // The list is full already, so this match means the result set is
237 // truncated; the list itself keeps its maxResults entries.
238 if( maxResults > 0 && static_cast<int>( result.m_MatchingNames.size() ) >= maxResults )
239 {
240 result.m_IsLimited = true;
241 break;
242 }
243
244 wxString libId = fp->GetFPID().Format();
245 result.m_MatchingNames.emplace_back( libId );
246 }
247
248 if( result.m_IsLimited )
249 break;
250 }
251
252 result.m_Success = true;
253
254 return result.ToJsonStr();
255 }
256 catch( const std::exception& )
257 {
258 // A failure carries no matches, even if the scan had already collected some.
259 result.m_MatchingNames.clear();
260 result.m_Success = false;
261 return result.ToJsonStr();
262 }
263}
264
265
270{
272
273 if( adapter )
274 {
275 adapter->AsyncLoad();
276 return true;
277 }
278
279 return false;
280}
281
282
284 * Return how far a background load has got.
285 *
286 * Never blocks: callers can poll this while showing a loading indication, and only run
287 * #filterFootprints() (which does wait for the load) after it returns 1.0.
288 */
290{
292
293 if( !adapter )
294 return 1.0f;
295
296 // Nothing to report means there is nothing to wait for.
297 if( std::optional<float> progress = adapter->AsyncLoadProgress() )
298 return *progress;
299
300 return 1.0f;
301}
302
303
304namespace PCB {
305
306// Non-job kiface exports for diff/merge (returned by IfaceOrAddress). Defined
307// after the kiface instance so they can route into its jobs handler.
308static int pcbnewMergeExport( int aKind, const wxString& aAncestor, const wxString& aOurs,
309 const wxString& aTheirs, const wxString& aOutput, bool aInteractive,
310 bool aSingleFile, REPORTER* aReporter );
311static int pcbnewOpenDiffDialogExport( int aKind, const wxString& aFileA, const wxString& aFileB,
312 const wxString& aLabelA, const wxString& aLabelB,
313 wxWindow* aParent, REPORTER* aReporter );
314static KICAD_DIFF::DIFF_CANVAS_CONTEXT*
315pcbnewAttachDiffCanvasesExport( int aKind, const wxString& aFileA, const wxString& aFileB, WIDGET_DIFF_CANVAS* aBefore,
316 WIDGET_DIFF_CANVAS* aAfter, KICAD_DIFF::DOCUMENT_DIFF* aDiff, REPORTER* aReporter );
317
318
319static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
320{
321 // Of course all are virtual overloads, implementations of the KIFACE.
322
323 IFACE( const char* aName, KIWAY::FACE_T aType ) :
324 KIFACE_BASE( aName, aType ),
326 {}
327
328 bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
329
330 void Reset() override;
331
332 void OnKifaceEnd() override;
333
334 wxWindow* CreateKiWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) override
335 {
336 switch( aClassId )
337 {
338 case FRAME_PCB_EDITOR:
339 {
340 auto frame = new PCB_EDIT_FRAME( aKiway, aParent );
341
342 if( Kiface().IsSingle() )
343 {
344 // only run this under single_top, not under a project manager.
348
349 return frame;
350 }
351
353 return new FOOTPRINT_EDIT_FRAME( aKiway, aParent );
356 return new FOOTPRINT_VIEWER_FRAME( aKiway, aParent );
357
359 return new FOOTPRINT_CHOOSER_FRAME( aKiway, aParent );
362 return new FOOTPRINT_WIZARD_FRAME( aKiway, aParent, FRAME_T( aClassId ) );
363
365 return FOOTPRINT_PREVIEW_PANEL::New( aKiway, aParent, this );
368 {
369 DIALOG_CONFIGURE_PATHS dlg( aParent );
371 // The dialog's constructor probably failed to set its Kiway because the
372 // dynamic_cast fails when aParent was allocated by a separate compilation
373 // module. So set it directly.
374 dlg.SetKiway( &dlg, aKiway );
375
376 // Use QuasiModal so that HTML help window will work
377 if( dlg.ShowQuasiModal() == wxID_OK )
380 // Dialog has completed; nothing to return.
381 return nullptr;
382 }
383
385 InvokePcbLibTableEditor( aKiway, aParent );
386 // Dialog has completed; nothing to return.
387 return nullptr;
390 return new PANEL_DISPLAY_OPTIONS( aParent, GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" ) );
393 {
395 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
397 if( !frame )
398 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
400 if( !frame )
401 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
402
403 if( frame )
404 SetUserUnits( frame->GetUserUnits() );
405
406 return new PANEL_GRID_SETTINGS( aParent, this, frame, cfg, FRAME_FOOTPRINT_EDITOR );
407 }
408
413
415 return new PANEL_PCBNEW_DISPLAY_ORIGIN( aParent, GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" ),
417
419 {
420 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
421
422 if( !frame )
423 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
424
425 if( !frame )
426 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
427
428 if( frame )
429 SetUserUnits( frame->GetUserUnits() );
430
431 return new PANEL_EDIT_OPTIONS( aParent, this, frame, true );
432 }
433
435 {
436 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
437
438 if( !frame )
439 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
440
441 if( !frame )
442 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
443
444 if( frame )
445 SetUserUnits( frame->GetUserUnits() );
446
447 return new PANEL_FP_EDITOR_FIELD_DEFAULTS( aParent );
448 }
449
451 {
452 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
453
454 if( !frame )
455 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
456
457 if( !frame )
458 frame = aKiway->Player( FRAME_PCB_EDITOR, false );
459
460 if( frame )
461 SetUserUnits( frame->GetUserUnits() );
462
463 return new PANEL_FP_EDITOR_GRAPHICS_DEFAULTS( aParent, this );
464 }
465
467 return new class PANEL_FP_USER_LAYER_NAMES( aParent );
468
470 {
471 APP_SETTINGS_BASE* cfg = GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" );
472 TOOLBAR_SETTINGS* tb = GetToolbarSettings<FOOTPRINT_EDIT_TOOLBAR_SETTINGS>( "fpedit-toolbars" );
473
474 std::vector<TOOL_ACTION*> actions;
475 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
476
477 for( TOOL_ACTION* action : ACTION_MANAGER::GetActionList() )
478 actions.push_back( action );
479
480 for( ACTION_TOOLBAR_CONTROL* control : ACTION_TOOLBAR::GetCustomControlList( FRAME_FOOTPRINT_EDITOR ) )
481 controls.push_back( control );
482
483 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, FRAME_FOOTPRINT_EDITOR, actions, controls );
484 }
485
486 case PANEL_FP_COLORS:
487 return new PANEL_FP_EDITOR_COLOR_SETTINGS( aParent );
488
490 return new PANEL_DISPLAY_OPTIONS( aParent, GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" ) );
491
492 case PANEL_PCB_GRIDS:
493 {
494 PCBNEW_SETTINGS* cfg = GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
495 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_PCB_EDITOR, false );
496
497 if( !frame )
498 frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
499
500 if( !frame )
501 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
502
503 if( frame )
504 SetUserUnits( frame->GetUserUnits() );
505
506 return new PANEL_GRID_SETTINGS( aParent, this, frame, cfg, FRAME_PCB_EDITOR );
507 }
508
512
514 return new PANEL_PCBNEW_DISPLAY_ORIGIN( aParent, GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" ),
516
518 {
519 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_PCB_EDITOR, false );
520
521 if( !frame )
522 frame = aKiway->Player( FRAME_FOOTPRINT_EDITOR, false );
523
524 if( !frame )
525 frame = aKiway->Player( FRAME_FOOTPRINT_VIEWER, false );
526
527 if( frame )
528 SetUserUnits( frame->GetUserUnits() );
529
530 return new PANEL_EDIT_OPTIONS( aParent, this, frame, false );
531 }
532
533 case PANEL_PCB_COLORS:
534 {
535 BOARD* board = nullptr;
536 EDA_BASE_FRAME* boardProvider = aKiway->Player( FRAME_PCB_EDITOR, false );
537
538 if( boardProvider )
539 board = static_cast<PCB_EDIT_FRAME*>( boardProvider )->GetBoard();
540
541 return new PANEL_PCBNEW_COLOR_SETTINGS( aParent, board );
542 }
543
545 {
546 APP_SETTINGS_BASE* cfg = GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
547 TOOLBAR_SETTINGS* tb = GetToolbarSettings<PCB_EDIT_TOOLBAR_SETTINGS>( "pcbnew-toolbars" );
548
549 std::vector<TOOL_ACTION*> actions;
550 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
551
552 for( TOOL_ACTION* action : ACTION_MANAGER::GetActionList() )
553 actions.push_back( action );
554
555 for( ACTION_TOOLBAR_CONTROL* control : ACTION_TOOLBAR::GetCustomControlList( FRAME_PCB_EDITOR ) )
556 controls.push_back( control );
557
558 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, FRAME_PCB_EDITOR, actions, controls );
559 }
560
562 return new PANEL_PCBNEW_ACTION_PLUGINS( aParent );
563
565 return new PANEL_3D_DISPLAY_OPTIONS( aParent );
566
567 case PANEL_3DV_OPENGL:
568 return new PANEL_3D_OPENGL_OPTIONS( aParent );
569
571 return new PANEL_3D_RAYTRACING_OPTIONS( aParent );
572
574 {
575 APP_SETTINGS_BASE* cfg = GetAppSettings<EDA_3D_VIEWER_SETTINGS>( "3d_viewer" );
576 TOOLBAR_SETTINGS* tb = GetToolbarSettings<EDA_3D_VIEWER_TOOLBAR_SETTINGS>( "3d_viewer-toolbars" );
577
578 std::vector<TOOL_ACTION*> actions;
579 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
580
581 for( TOOL_ACTION* action : ACTION_MANAGER::GetActionList() )
582 actions.push_back( action );
583
584 for( ACTION_TOOLBAR_CONTROL* control : ACTION_TOOLBAR::GetCustomControlList( FRAME_PCB_DISPLAY3D ) )
585 controls.push_back( control );
586
587 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, FRAME_PCB_DISPLAY3D, actions, controls );
588 }
589
590 default:
591 return nullptr;
592 }
593 }
594
605 void* IfaceOrAddress( int aDataId ) override
606 {
607 switch( aDataId )
608 {
610 {
611 // This is the mechanism by which FOOTPRINT_SELECT_WIDGET can get access to the adapter
612 // without directly linking to pcbnew or pcbcommon, going through PROJECT::FootprintLibAdapter
613 PROJECT* project = nullptr;
614
615 if( wxTheApp )
616 {
617 wxWindow* focus = wxWindow::FindFocus();
618 wxWindow* top = focus ? wxGetTopLevelParent( focus ) : wxTheApp->GetTopWindow();
619
620 if( top )
621 {
622 if( KIWAY_HOLDER* holder = dynamic_cast<KIWAY_HOLDER*>( top ) )
623 project = &holder->Prj();
624 }
625 }
626
627 if( !project )
629
631 }
632
634 {
635 // Return function pointer for filtering footprints
636 // Signature: wxString (*)(const wxString& aFilterJson)
637 return reinterpret_cast<void*>( &filterFootprints );
638 }
639
641 {
642 // Start the background load of the libraries filtered by filterFootprints
643 // Signature: void (*)()
644 return reinterpret_cast<void*>( &startFootprintLibraryLoad );
645 }
646
648 {
649 // Report how far the load started by startFootprintMatchLoad() has got
650 // Signature: float (*)()
651 return reinterpret_cast<void*>( &footprintLibraryLoadProgress );
652 }
653
655 return reinterpret_cast<void*>( &pcbnewMergeExport );
656
658 return reinterpret_cast<void*>( &pcbnewOpenDiffDialogExport );
659
660 case KIFACE_ATTACH_DIFF_CANVASES: return reinterpret_cast<void*>( &pcbnewAttachDiffCanvasesExport );
661
662 default:
663 return nullptr;
664 }
665 }
666
668 PCBNEW_JOBS_HANDLER* JobHandler() const { return m_jobHandler.get(); }
669
675 void SaveFileAs( const wxString& aProjectBasePath, const wxString& aSrcProjectName,
676 const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
677 const wxString& aSrcFilePath, wxString& aErrors ) override;
678
679 int HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter ) override;
680
681 bool HandleJobConfig( JOB* aJob, wxWindow* aParent ) override;
682
683 bool HandleApiOpenDocument( const DOCUMENT_SPEC& aSpec,
684 KICAD_API_SERVER* aServer,
685 wxString* aError ) override;
686
687 bool HandleApiCloseDocument( const DOCUMENT_SPEC& aSpec,
688 KICAD_API_SERVER* aServer,
689 wxString* aError ) override;
690
691 bool handleOpenPcb( const wxString& aPath, KICAD_API_SERVER* aServer, wxString* aError );
692
693 bool handleCreatePcb( const wxString& aPath, KICAD_API_SERVER* aServer, wxString* aError );
694
695 bool handleOpenFootprint( const wxString& aProjectPath, const wxString& aLibIdStr, KICAD_API_SERVER* aServer,
696 wxString* aError );
697
698 void PreloadLibraries( KIWAY* aKiway ) override;
699 void ProjectChanged() override;
700 void CancelPreload( bool aBlock = true ) override;
701 void RegisterLibraryHandlers( KICAD_API_SERVER* aServer ) override;
702 bool LoadAllLibraries() override;
703
704
705private:
706 std::unique_ptr<PCBNEW_JOBS_HANDLER> m_jobHandler;
707 std::shared_ptr<BACKGROUND_JOB> m_libraryPreloadBackgroundJob;
708 std::future<void> m_libraryPreloadReturn;
710 std::atomic_bool m_libraryPreloadAbort;
711
712 void closeBoard( KICAD_API_SERVER* aServer );
713 void closeFootprint( KICAD_API_SERVER* aServer );
714
715 KIWAY* m_kiway = nullptr;
716 std::shared_ptr<HEADLESS_PCB_CONTEXT> m_openContext;
717 std::unique_ptr<API_HANDLER_PCB> m_openHandler;
718 std::shared_ptr<HEADLESS_FOOTPRINT_CONTEXT> m_openFpContext;
719 std::unique_ptr<API_HANDLER_FOOTPRINT> m_openFpHandler;
720 std::unique_ptr<API_HANDLER_FP_LIBRARIES> m_apiHandlerFpLibs;
721
722} kiface( "pcbnew", KIWAY::FACE_PCB );
723
724
725int pcbnewMergeExport( int aKind, const wxString& aAncestor, const wxString& aOurs,
726 const wxString& aTheirs, const wxString& aOutput, bool aInteractive,
727 bool aSingleFile, REPORTER* aReporter )
728{
729 return kiface.JobHandler()->RunMerge( static_cast<KICAD_DIFF::DOC_KIND>( aKind ), aAncestor,
730 aOurs, aTheirs, aOutput, aInteractive, aSingleFile,
731 aReporter );
732}
733
734
735int pcbnewOpenDiffDialogExport( int aKind, const wxString& aFileA, const wxString& aFileB,
736 const wxString& aLabelA, const wxString& aLabelB,
737 wxWindow* aParent, REPORTER* aReporter )
738{
739 return kiface.JobHandler()->OpenDiffDialog( static_cast<KICAD_DIFF::DOC_KIND>( aKind ), aFileA,
740 aFileB, aLabelA, aLabelB, aParent, aReporter );
741}
742
743
745 const wxString& aFileB, WIDGET_DIFF_CANVAS* aBefore,
746 WIDGET_DIFF_CANVAS* aAfter,
747 KICAD_DIFF::DOCUMENT_DIFF* aDiff, REPORTER* aReporter )
748{
749 return kiface.JobHandler()->AttachDiffCanvases( static_cast<KICAD_DIFF::DOC_KIND>( aKind ), aFileA, aFileB, aBefore,
750 aAfter, *aDiff, aReporter );
751}
752
753} // namespace
754
755
756using namespace PCB;
757
758
760
761
762// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h.
763// KIFACE_GETTER will not have name mangling due to declaration in kiway.h.
764KIFACE_API KIFACE* KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram )
765{
766 return &kiface;
767}
768
769
770bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
771{
772 // This is process-level-initialization, not project-level-initialization of the DSO.
773 // Do nothing in here pertinent to a project!
775
776 SETTINGS_MANAGER& mgr = aProgram->GetSettingsManager();
777
780
781 // We intentionally register KifaceSettings after FOOTPRINT_EDITOR_SETTINGS and EDA_3D_VIEWER_SETTINGS
782 // In legacy configs, many settings were in a single editor config and the migration routine
783 // for the main editor file will try and call into the now separate settings stores
784 // to move the settings into them
786
787 // Register the footprint editor settings as well because they share a KiFACE and need to be
788 // loaded prior to use to avoid threading deadlocks
790
791 start_common( aCtlBits );
792
793 m_kiway = aKiway;
794
795 m_jobHandler = std::make_unique<PCBNEW_JOBS_HANDLER>( aKiway );
796
798 {
799 m_jobHandler->SetReporter( &CLI_REPORTER::GetInstance() );
800 m_jobHandler->SetProgressReporter( &CLI_PROGRESS_REPORTER::GetInstance() );
801 }
802
803 // Register the PCB and footprint merge drivers with libgit2 so
804 // .gitattributes entries `merge=kicad-pcb` and `merge=kicad-fp` route
805 // through our 3-way merge pipeline. git_merge_driver_register is not
806 // thread-safe; this runs once at kiface init before any background work
807 // spawns. The registry is idempotent so re-loads of the kiface are safe.
810
811 if( Pgm().ApiServerOrNull() )
812 {
813 m_apiHandlerFpLibs = std::make_unique<API_HANDLER_FP_LIBRARIES>();
815 }
816
817 return true;
818}
819
820
822{
823 closeBoard( nullptr );
824 closeFootprint( nullptr );
825}
826
827
829{
830 CancelPreload( true );
831
832#if defined( KICAD_NATIVE_MODEL_PREVIEW ) && defined( __WXGTK3__ )
833 ShutdownNativeModelFilePickerGtk();
834#endif
835
837 {
838 if( Pgm().ApiServerOrNull() )
840
841 m_apiHandlerFpLibs.reset();
842 }
843
844 // Release the CLI-cached board while the static DRC_ITEM tables it serializes against are
845 // still alive; deferring to static teardown crashes reading dangling severity keys
846 if( m_jobHandler )
847 m_jobHandler->ClearCachedBoard();
848
849 end_common();
850}
851
852
853void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aSrcProjectName,
854 const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
855 const wxString& aSrcFilePath, wxString& aErrors )
856{
857 wxFileName destFile( aSrcFilePath );
858 wxString destPath = destFile.GetPathWithSep();
859 wxUniChar pathSep = wxFileName::GetPathSeparator();
860 wxString ext = destFile.GetExt();
861
862 if( destPath.StartsWith( aProjectBasePath + pathSep ) )
863 destPath.Replace( aProjectBasePath, aNewProjectBasePath, false );
864
865 wxString srcProjectFootprintLib = pathSep + aSrcProjectName + wxT( ".pretty" ) + pathSep;
866 wxString newProjectFootprintLib = pathSep + aNewProjectName + wxT( ".pretty" ) + pathSep;
867
868 destPath.Replace( srcProjectFootprintLib, newProjectFootprintLib, true );
869
870 destFile.SetPath( destPath );
871
874 {
875 if( destFile.GetName() == aSrcProjectName )
876 destFile.SetName( aNewProjectName );
877
878 CopySexprFile( aSrcFilePath, destFile.GetFullPath(),
879 [&]( const std::string& token, wxString& value )
880 {
881 if( token == "sheetfile" )
882 {
883 for( const wxString extension : { wxT( ".sch" ), wxT( ".kicad_sch" ) } )
884 {
885 if( value == aSrcProjectName + extension )
886 {
887 value = aNewProjectName + extension;
888 return true;
889 }
890 else if( value == aProjectBasePath + "/" + aSrcProjectName + extension )
891 {
892 value = aNewProjectBasePath + "/" + aNewProjectName + extension;
893 return true;
894 }
895 else if( value.StartsWith( aProjectBasePath ) )
896 {
897 value.Replace( aProjectBasePath, aNewProjectBasePath, false );
898 return true;
899 }
900 }
901 }
902
903 return false;
904 },
905 aErrors );
906 }
907 else if( ext == FILEEXT::LegacyPcbFileExtension )
908 {
909 if( destFile.GetName() == aSrcProjectName )
910 destFile.SetName( aNewProjectName );
911
912 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
913 }
916 {
917 // Footprints are not project-specific. Keep their source names.
918 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
919 }
921 {
922 // TODO
923 }
924 else if( ext == wxT( "rpt" ) )
925 {
926 // DRC must be the "gold standard". Since we can't guarantee that there aren't
927 // any non-deterministic cases in the save-as algorithm, we don't want to certify
928 // the result with the source's DRC report. Therefore copy it under the old
929 // name.
930 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
931 }
932 else if( destFile.GetName() == FILEEXT::FootprintLibraryTableFileName )
933 {
934 wxFileName libTableFn( aSrcFilePath );
935 LIBRARY_TABLE libTable( libTableFn, LIBRARY_TABLE_SCOPE::PROJECT );
936 libTable.SetPath( destFile.GetFullPath() );
937 libTable.SetType( LIBRARY_TABLE_TYPE::FOOTPRINT );
938
939 for( LIBRARY_TABLE_ROW& row : libTable.Rows() )
940 {
941 wxString uri = row.URI();
942
943 uri.Replace( wxT( "/" ) + aSrcProjectName + wxT( ".pretty" ),
944 wxT( "/" ) + aNewProjectName + wxT( ".pretty" ) );
945
946 row.SetURI( uri );
947 }
948
949 libTable.Save().map_error(
950 [&]( const LIBRARY_ERROR& aError )
951 {
952 wxString msg;
953
954 if( !aErrors.empty() )
955 aErrors += wxT( "\n" );
956
957 msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() );
958 aErrors += msg;
959 } );
960 }
961 else
962 {
963 wxFAIL_MSG( wxT( "Unexpected filetype for Pcbnew::SaveFileAs()" ) );
964 }
965}
966
967
968int IFACE::HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter )
969{
970 return m_jobHandler->RunJob( aJob, aReporter, aProgressReporter );
971}
972
973
974bool IFACE::HandleJobConfig( JOB* aJob, wxWindow* aParent )
975{
976 return m_jobHandler->HandleJobConfig( aJob, aParent );
977}
978
979
981{
982 if( m_openHandler )
983 {
984 if( aServer )
985 aServer->DeregisterHandler( m_openHandler.get() );
986
987 m_openHandler.reset();
988 }
989
990 m_openContext.reset();
991
992 // The jobs handler caches the last-loaded board. Clear it so the next job
993 // uses the board from the newly opened document rather than a stale copy.
994 if( m_jobHandler )
995 m_jobHandler->ClearCachedBoard();
996}
997
998
1000{
1001 if( m_openFpHandler )
1002 {
1003 if( aServer )
1004 aServer->DeregisterHandler( m_openFpHandler.get() );
1005
1006 m_openFpHandler.reset();
1007 }
1008
1009 m_openFpContext.reset();
1010}
1011
1012
1013bool IFACE::HandleApiOpenDocument( const DOCUMENT_SPEC& aSpec, KICAD_API_SERVER* aServer, wxString* aError )
1014{
1015 wxCHECK( aServer, false );
1016
1017 if( aSpec.kind == DOCUMENT_SPEC::KIND::LIBID_KIND )
1018 return handleOpenFootprint( aSpec.path, aSpec.libId.GetUniStringLibId(), aServer, aError );
1019
1020 if( aSpec.kind == DOCUMENT_SPEC::KIND::CREATE_KIND )
1021 return handleCreatePcb( aSpec.path, aServer, aError );
1022
1023 if( aSpec.path.IsEmpty() )
1024 {
1025 if( aError )
1026 *aError = wxS( "No path specified to open" );
1027
1028 return false;
1029 }
1030
1031 return handleOpenPcb( aSpec.path, aServer, aError );
1032}
1033
1034
1035bool IFACE::handleOpenFootprint( const wxString& aProjectPath, const wxString& aLibIdStr, KICAD_API_SERVER* aServer,
1036 wxString* aError )
1037{
1038 LIB_ID fpid;
1039
1040 if( fpid.Parse( aLibIdStr ) >= 0 )
1041 {
1042 if( aError )
1043 *aError = wxString::Format( wxS( "Invalid footprint LIB_ID: %s" ), aLibIdStr );
1044
1045 return false;
1046 }
1047
1048 wxFileName projectPath( aProjectPath );
1049 projectPath.MakeAbsolute();
1050
1051 SETTINGS_MANAGER& settingsManager = Pgm().GetSettingsManager();
1052
1053 if( !settingsManager.LoadProject( projectPath.GetFullPath(), true ) )
1054 {
1055 wxLogTrace( traceApi, "Warning: no project file found for %s", aProjectPath );
1056 }
1057
1058 PROJECT* project = settingsManager.GetProject( projectPath.GetFullPath() );
1059
1060 if( !project )
1061 {
1062 if( aError )
1063 *aError = wxString::Format( wxS( "Error loading project for %s" ), aProjectPath );
1064
1065 return false;
1066 }
1067
1068 std::shared_ptr<HEADLESS_FOOTPRINT_CONTEXT> newContext;
1069
1070 try
1071 {
1073 adapter->AsyncLoad();
1074 adapter->BlockUntilLoaded();
1075 std::unique_ptr<FOOTPRINT> footprint( adapter->LoadFootprintWithOptionalNickname( fpid, true ) );
1076
1077 if( !footprint )
1078 {
1079 if( aError )
1080 *aError = wxString::Format( wxS( "Footprint not found: %s" ), aLibIdStr );
1081
1082 return false;
1083 }
1084
1085 newContext = std::make_shared<HEADLESS_FOOTPRINT_CONTEXT>(
1086 std::move( footprint ), fpid, project, GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" ), m_kiway );
1087 }
1088 catch( ... )
1089 {
1090 if( aError )
1091 *aError = wxString::Format( wxS( "Failed to load footprint: %s" ), aLibIdStr );
1092
1093 return false;
1094 }
1095
1096 closeFootprint( aServer );
1097
1098 if( !m_apiHandlerFpLibs )
1099 {
1100 m_apiHandlerFpLibs = std::make_unique<API_HANDLER_FP_LIBRARIES>();
1101 aServer->RegisterHandler( m_apiHandlerFpLibs.get() );
1102 }
1103
1104 m_openFpContext = std::move( newContext );
1105
1106 m_openFpHandler = std::make_unique<API_HANDLER_FOOTPRINT>( m_openFpContext, nullptr );
1107 aServer->RegisterHandler( m_openFpHandler.get() );
1108
1109 return true;
1110}
1111
1112
1113bool IFACE::handleOpenPcb( const wxString& aPath, KICAD_API_SERVER* aServer, wxString* aError )
1114{
1115 wxFileName projectPath( aPath );
1116
1117 if( projectPath.GetExt() == FILEEXT::KiCadPcbFileExtension )
1118 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1119 else if( projectPath.GetExt() != FILEEXT::ProjectFileExtension )
1120 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1121
1122 projectPath.MakeAbsolute();
1123
1124 // We currently only support one document per type (and each needs to come from
1125 // the same project). This will need evolution once we support MDI and multi-project.
1126 closeBoard( aServer );
1127
1128 SETTINGS_MANAGER& settingsManager = Pgm().GetSettingsManager();
1129
1130 // Reuse an already-loaded project if one exists for this path.
1131 PROJECT* project = settingsManager.GetProject( projectPath.GetFullPath() );
1132
1133 if( !project )
1134 {
1135 if( !settingsManager.LoadProject( projectPath.GetFullPath(), true ) )
1136 wxLogTrace( traceApi, "Warning: no project file found for %s", aPath );
1137
1138 project = settingsManager.GetProject( projectPath.GetFullPath() );
1139 }
1140
1141 if( !project )
1142 {
1143 if( aError )
1144 *aError = wxString::Format( wxS( "Error loading project for %s" ), aPath );
1145
1146 return false;
1147 }
1148
1149 wxFileName boardPath( projectPath );
1150 boardPath.SetExt( FILEEXT::KiCadPcbFileExtension );
1151
1152 if( !boardPath.FileExists() )
1153 {
1154 if( aError )
1155 *aError = wxString::Format( wxS( "File not found: %s" ), aPath );
1156
1157 return false;
1158 }
1159
1160 PCB_IO_MGR::PCB_FILE_T pluginType =
1162
1163 if( pluginType == PCB_IO_MGR::FILE_TYPE_NONE )
1164 {
1165 if( aError )
1166 *aError = wxString::Format( wxS( "%s is not a recognized file type" ), aPath );
1167
1168 return false;
1169 }
1170
1171 std::shared_ptr<HEADLESS_PCB_CONTEXT> newContext;
1172
1173 try
1174 {
1175 std::unique_ptr<BOARD> loadedBoard = BOARD_LOADER::Load( boardPath.GetFullPath(), pluginType, project );
1176
1177 if( !loadedBoard )
1178 {
1179 if( aError )
1180 *aError = wxS( "Failed to load board" );
1181
1182 return false;
1183 }
1184
1185 newContext = std::make_shared<HEADLESS_PCB_CONTEXT>( std::move( loadedBoard ), project,
1187 }
1188 catch( const IO_ERROR& ioe )
1189 {
1190 if( aError )
1191 *aError = wxString::Format( wxS( "Failed to load board: %s" ), ioe.What() );
1192
1193 return false;
1194 }
1195 catch( ... )
1196 {
1197 if( aError )
1198 *aError = wxS( "Failed to load board" );
1199
1200 return false;
1201 }
1202
1203 if( !m_apiHandlerFpLibs )
1204 {
1205 m_apiHandlerFpLibs = std::make_unique<API_HANDLER_FP_LIBRARIES>();
1206 aServer->RegisterHandler( m_apiHandlerFpLibs.get() );
1207 }
1208
1209 m_openContext = std::move( newContext );
1210
1211 m_openHandler = std::make_unique<API_HANDLER_PCB>( m_openContext, nullptr );
1212 aServer->RegisterHandler( m_openHandler.get() );
1213
1214 return true;
1215}
1216
1217
1218bool IFACE::handleCreatePcb( const wxString& aPath, KICAD_API_SERVER* aServer, wxString* aError )
1219{
1220 wxFileName boardPath( aPath );
1221 boardPath.MakeAbsolute();
1222
1223 wxFileName projectPath( boardPath );
1224 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1225
1226 if( m_openContext && m_openContext->IsContentModified() )
1227 {
1228 if( aError )
1229 *aError = wxS( "The current board has unsaved changes; save or revert it first" );
1230
1231 return false;
1232 }
1233
1234 closeBoard( aServer );
1235
1236 SETTINGS_MANAGER& settingsManager = Pgm().GetSettingsManager();
1237
1238 PROJECT* project = settingsManager.GetProject( projectPath.GetFullPath() );
1239
1240 if( !project )
1241 {
1242 settingsManager.LoadProject( projectPath.GetFullPath(), true );;
1243 project = settingsManager.GetProject( projectPath.GetFullPath() );
1244 }
1245
1246 if( !project )
1247 {
1248 if( aError )
1249 *aError = wxString::Format( wxS( "Error creating project for %s" ), aPath );
1250
1251 return false;
1252 }
1253
1254 std::shared_ptr<HEADLESS_PCB_CONTEXT> newContext;
1255
1256 try
1257 {
1258 std::unique_ptr<BOARD> newBoard = BOARD_LOADER::CreateEmptyBoard( project );
1259
1260 if( !newBoard )
1261 {
1262 if( aError )
1263 *aError = wxS( "Failed to create board" );
1264
1265 return false;
1266 }
1267
1268 newBoard->SetFileName( boardPath.GetFullPath() );
1269
1270 newContext = std::make_shared<HEADLESS_PCB_CONTEXT>( std::move( newBoard ), project,
1272 }
1273 catch( ... )
1274 {
1275 if( aError )
1276 *aError = wxS( "Failed to create board" );
1277
1278 return false;
1279 }
1280
1281 m_openContext = std::move( newContext );
1282
1283 if( !m_apiHandlerFpLibs )
1284 {
1285 m_apiHandlerFpLibs = std::make_unique<API_HANDLER_FP_LIBRARIES>();
1286 aServer->RegisterHandler( m_apiHandlerFpLibs.get() );
1287 }
1288
1289 m_openHandler = std::make_unique<API_HANDLER_PCB>( m_openContext, nullptr );
1290 aServer->RegisterHandler( m_openHandler.get() );
1291
1292 return true;
1293}
1294
1295
1296bool IFACE::HandleApiCloseDocument( const DOCUMENT_SPEC& aSpec, KICAD_API_SERVER* aServer, wxString* aError )
1297{
1298 wxCHECK( aServer, false );
1299
1300 if( aSpec.kind == DOCUMENT_SPEC::KIND::LIBID_KIND )
1301 {
1302 if( !m_openFpContext )
1303 {
1304 if( aError )
1305 *aError = wxS( "No footprint is currently open" );
1306
1307 return false;
1308 }
1309
1310 if( aSpec.libId.IsValid() && m_openFpContext->GetLoadedFPID() != aSpec.libId )
1311 {
1312 if( aError )
1313 *aError = wxS( "Requested document does not match the open document" );
1314
1315 return false;
1316 }
1317
1318 closeFootprint( aServer );
1319 return true;
1320 }
1321
1322 if( !m_openContext )
1323 {
1324 if( aError )
1325 *aError = wxS( "No board is currently open" );
1326
1327 return false;
1328 }
1329
1330 if( !aSpec.path.IsEmpty() )
1331 {
1332 wxFileName currentBoard( m_openContext->GetCurrentFileName() );
1333
1334 if( currentBoard.GetFullName() != wxFileName( aSpec.path ).GetFullName() )
1335 {
1336 if( aError )
1337 *aError = wxS( "Requested document does not match the open document" );
1338
1339 return false;
1340 }
1341 }
1342
1343 closeBoard( aServer );
1344 return true;
1345}
1346
1347
1349{
1350 constexpr static int interval = 150;
1351 constexpr static int timeLimit = 120000;
1352
1353 wxCHECK( aKiway, /* void */ );
1354
1355 // Use compare_exchange to atomically check and set the flag to prevent race conditions
1356 // when PreloadLibraries is called multiple times concurrently (e.g., from project manager
1357 // and pcb editor both scheduling via CallAfter)
1358 bool expected = false;
1359
1360 if( !m_libraryPreloadInProgress.compare_exchange_strong( expected, true ) )
1361 return;
1362
1364
1366 Pgm().GetBackgroundJobMonitor().Create( _( "Loading Footprint Libraries" ) );
1367
1368 auto preload =
1369 [this, aKiway]() -> void
1370 {
1371 std::shared_ptr<BACKGROUND_JOB_REPORTER> reporter =
1373
1375
1376 int elapsed = 0;
1377 bool aborted = false;
1378
1379 reporter->Report( _( "Loading Footprint Libraries" ) );
1380 adapter->AsyncLoad();
1381
1382 while( true )
1383 {
1384 if( m_libraryPreloadAbort.load() )
1385 {
1386 m_libraryPreloadAbort.store( false );
1387 aborted = true;
1388 break;
1389 }
1390
1391 std::this_thread::sleep_for( std::chrono::milliseconds( interval ) );
1392
1393 if( std::optional<float> loadStatus = adapter->AsyncLoadProgress() )
1394 {
1395 float progress = *loadStatus;
1396 reporter->SetCurrentProgress( progress );
1397
1398 if( progress >= 1 )
1399 break;
1400 }
1401 else
1402 {
1403 reporter->SetCurrentProgress( 1 );
1404 break;
1405 }
1406
1407 elapsed += interval;
1408
1409 if( elapsed > timeLimit )
1410 break;
1411 }
1412
1413 // AbortAsyncLoad() sets the adapter's worker abort flag and then blocks,
1414 // so workers exit at their next checkpoint. BlockUntilLoaded() alone just
1415 // waits for each future to complete naturally, which can hang indefinitely
1416 // if a worker is stuck on a stalled network or filesystem operation.
1417 if( aborted )
1418 adapter->AbortAsyncLoad();
1419 else
1420 adapter->BlockUntilLoaded();
1421
1422 // If aborted, skip operations that use the adapter since the project may have changed
1423 // and the adapter's project reference could be stale. This prevents use-after-free
1424 // crashes when switching projects during library preload.
1425 if( !aborted )
1426 {
1427 // Report library load errors from adapter
1429 }
1430 else
1431 {
1432 wxLogTrace( traceLibraries, "pcbnew PreloadLibraries: aborted, skipping footprint processing" );
1433 }
1434
1435 m_libraryPreloadAbort.store( false );
1438
1439 // Only send reload notifications if we weren't aborted
1440 if( !aborted )
1441 {
1442 std::string payload = "";
1443 aKiway->ExpressMail( FRAME_PCB_EDITOR, MAIL_RELOAD_LIB, payload, nullptr, true );
1444 aKiway->ExpressMail( FRAME_FOOTPRINT_EDITOR, MAIL_RELOAD_LIB, payload, nullptr, true );
1445 aKiway->ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload, nullptr, true );
1446 }
1447
1448 m_libraryPreloadInProgress.store( false );
1449 };
1450
1451 std::future<void> preloadFuture = std::async( std::launch::async, preload );
1452 m_libraryPreloadReturn = std::move( preloadFuture );
1453}
1454
1455
1457{
1458 if( m_libraryPreloadInProgress.load() )
1459 m_libraryPreloadAbort.store( true );
1460}
1461
1462
1463void IFACE::CancelPreload( bool aBlock )
1464{
1465 if( m_libraryPreloadInProgress.load() )
1466 {
1467 m_libraryPreloadAbort.store( true );
1468
1469 if( aBlock )
1471 }
1472}
1473
1474
1476{
1477 wxCHECK_RET( aServer, "no API server provided" );
1478
1479 if( !m_apiHandlerFpLibs )
1480 {
1481 m_apiHandlerFpLibs = std::make_unique<API_HANDLER_FP_LIBRARIES>();
1482 aServer->RegisterHandler( m_apiHandlerFpLibs.get() );
1483 }
1484}
1485
1486
1488{
1490
1491 if( !adapter )
1492 return false;
1493
1494 adapter->AsyncLoad();
1495 return true;
1496}
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
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 std::unique_ptr< BOARD > CreateEmptyBoard(PROJECT *aProject)
static std::unique_ptr< BOARD > Load(const wxString &aFileName, PCB_IO_MGR::PCB_FILE_T aFormat, PROJECT *aProject, const OPTIONS &aOptions)
static CLI_PROGRESS_REPORTER & GetInstance()
static CLI_REPORTER & GetInstance()
Definition reporter.cpp:261
static bool IsOnStandardSocketPath()
static void AnnounceToPrimary(FRAME_T aFrameType)
The base frame for deriving all KiCad main window classes.
SNAP_INFERENCE_SETTINGS m_SnapInference
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.
FOOTPRINT * LoadFootprintWithOptionalNickname(const LIB_ID &aFootprintId, bool aKeepUUID)
Load a footprint having aFootprintId with possibly an empty nickname.
static FOOTPRINT_PREVIEW_PANEL * New(KIWAY *aKiway, wxWindow *aParent, UNITS_PROVIDER *aUnitsProvider)
Component library viewer main window.
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()
An simple container class that lets us dispatch output jobs to kifaces.
Definition job.h:184
void RegisterHandler(API_HANDLER *aHandler)
Adds a new request handler to the server.
void DeregisterHandler(API_HANDLER *aHandler)
Keeps the documents drawn on a pair of diff canvases alive.
A KIFACE implementation.
Definition kiface_base.h:35
KIFACE_BASE(const char *aKifaceName, KIWAY::FACE_T aId)
Definition kiface_base.h:64
void InitSettings(APP_SETTINGS_BASE *aSettings)
Definition kiface_base.h:94
void end_common()
Common things to do for a top program module, during OnKifaceEnd();.
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:92
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?
static int Apply(const git_merge_driver_source *aSrc, const char **aPathOut, unsigned int *aModeOut, git_buf *aMergedOut)
libgit2 merge-driver apply callback shim.
static int Apply(const git_merge_driver_source *aSrc, const char **aPathOut, unsigned int *aModeOut, git_buf *aMergedOut)
A mix in class which holds the location of a wxWindow's KIWAY.
void SetKiway(wxWindow *aDest, KIWAY *aKiway)
It is only used for debugging, since "this" is not a wxWindow*.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:348
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:401
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:499
FACE_T
Known KIFACE implementations.
Definition kiway.h:354
@ FACE_PCB
pcbnew DSO
Definition kiway.h:356
virtual void CommonSettingsChanged(int aFlags=0)
Call CommonSettingsChanged() on all KIWAY_PLAYERs.
Definition kiway.cpp:593
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition kiway.cpp:208
std::optional< float > AsyncLoadProgress() const
Returns the fraction of the libraries queued by AsyncLoad() that have been processed,...
std::vector< KI_ERROR > GetLibraryLoadErrors() const
Returns all library load errors as newline-separated strings for display.
void AbortAsyncLoad()
Aborts any async load in progress; blocks until fully done aborting.
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.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:65
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
wxString GetUniStringLibId() const
Definition lib_id.h:144
MAGNETIC_SETTINGS m_MagneticItems
SNAP_INFERENCE_SETTINGS m_SnapInference
The main frame for Pcbnew.
PCB_FILE_T
The set of file types that the PCB_IO_MGR knows about, and for which there has been a plugin written,...
Definition pcb_io_mgr.h:52
static PCB_FILE_T FindPluginTypeFromBoardPath(const wxString &aFileName, int aCtl=0)
Return a plugin type given a path for a board file.
Container for data for KiCad programs.
Definition pgm_base.h:101
virtual BACKGROUND_JOBS_MONITOR & GetBackgroundJobMonitor() const
Definition pgm_base.h:129
void AddLibraryLoadMessages(const std::vector< KI_ERROR > &aMessages)
Add library load messages to all registered status bars.
void ClearLibraryLoadMessages()
Clear library load messages from all registered status bars.
KICAD_API_SERVER & GetApiServer()
Definition pgm_base.h:141
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:123
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:63
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.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
PROJECT * GetProject(const wxString &aFullPath) const
Retrieve a loaded project by name.
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)
GAL-backed canvas for visualizing a KICAD_DIFF::DIFF_SCENE.
This file is part of the common library.
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition cvpcb.cpp:165
#define _(s)
Abstract pattern-matching tool and implementations.
EDA_UNITS
Definition eda_units.h:44
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition frame_type.h:29
@ PANEL_PCB_GRIDS
Definition frame_type.h:100
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ PANEL_3DV_TOOLBARS
Definition frame_type.h:111
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:41
@ PANEL_3DV_OPENGL
Definition frame_type.h:109
@ PANEL_FP_DEFAULT_GRAPHICS_VALUES
Definition frame_type.h:95
@ PANEL_PCB_TOOLBARS
Definition frame_type.h:104
@ PANEL_PCB_ORIGINS_AXES
Definition frame_type.h:106
@ FRAME_FOOTPRINT_WIZARD
Definition frame_type.h:42
@ PANEL_PCB_EDIT_OPTIONS
Definition frame_type.h:102
@ PANEL_FP_DISPLAY_OPTIONS
Definition frame_type.h:88
@ PANEL_PCB_COLORS
Definition frame_type.h:103
@ PANEL_FP_SNAPPING
Definition frame_type.h:90
@ PANEL_FP_USER_LAYER_NAMES
Definition frame_type.h:96
@ PANEL_3DV_RAYTRACING
Definition frame_type.h:110
@ DIALOG_PCB_LIBRARY_TABLE
Definition frame_type.h:131
@ FRAME_FOOTPRINT_PREVIEW
Definition frame_type.h:44
@ FRAME_FOOTPRINT_CHOOSER
Definition frame_type.h:40
@ PANEL_FP_GRIDS
Definition frame_type.h:89
@ PANEL_FP_ORIGINS_AXES
Definition frame_type.h:97
@ PANEL_PCB_DISPLAY_OPTS
Definition frame_type.h:99
@ DIALOG_CONFIGUREPATHS
Definition frame_type.h:128
@ PANEL_FP_COLORS
Definition frame_type.h:92
@ PANEL_FP_DEFAULT_FIELDS
Definition frame_type.h:94
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
@ FRAME_PCB_DISPLAY3D
Definition frame_type.h:43
@ PANEL_FP_EDIT_OPTIONS
Definition frame_type.h:91
@ PANEL_FP_TOOLBARS
Definition frame_type.h:93
@ PANEL_PCB_ACTION_PLUGINS
Definition frame_type.h:105
@ PANEL_3DV_DISPLAY_OPTIONS
Definition frame_type.h:108
@ FRAME_CVPCB
Definition frame_type.h:48
@ PANEL_PCB_SNAPPING
Definition frame_type.h:101
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:388
void KiCopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
Definition gestfich.cpp:361
static const std::string ProjectFileExtension
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.
const wxChar *const traceApi
Flag to enable debug output related to the IPC API and its plugin system.
Definition api_utils.cpp:33
#define KIFACE_API
@ KIFACE_MERGE_DOCUMENT
int (*)( int aKind, const wxString& aAncestor, const wxString& aOurs, const wxString& aTheirs,...
Definition kiface_ids.h:70
@ KIFACE_FOOTPRINT_LIBRARY_ADAPTER
Definition kiface_ids.h:30
@ KIFACE_FOOTPRINTS_LOAD_PROGRESS
Function pointer type: float (*)() Returns how far the library loader has gotten as a fraction of the...
Definition kiface_ids.h:45
@ KIFACE_FILTER_FOOTPRINTS
Function pointer type: wxString (*)(const wxString& aFilterJson) Input JSON: {"pin_count": N,...
Definition kiface_ids.h:35
@ KIFACE_TRIGGER_FOOTPRINTS_LOAD
Function pointer type: bool (*)() Starts loading the footprint libraries in the background.
Definition kiface_ids.h:40
@ KIFACE_ATTACH_DIFF_CANVASES
KICAD_DIFF::DIFF_CANVAS_CONTEXT* (*)( int aKind, const wxString& aFileA, const wxString& aFileB,...
Definition kiface_ids.h:85
@ KIFACE_OPEN_DIFF_DIALOG
int (*)( int aKind, const wxString& aFileA, const wxString& aFileB, const wxString& aLabelA,...
Definition kiface_ids.h:77
#define KFCTL_CLI
Running as CLI app.
Definition kiway.h:176
#define KIFACE_GETTER
Definition kiway.h:110
#define KICTL_KICAD_ONLY
chosen file is from KiCad according to user
This file contains miscellaneous commonly used macros and functions.
@ MAIL_RELOAD_LIB
Definition mail_type.h:55
DOC_KIND
Document type a diff/merge entry point should route to, derived from a file path's extension.
bool RegisterMergeDriver(const char *aName, MERGE_APPLY_FN aApply)
Register a KiCad merge driver with libgit2.
PCB::IFACE KIFACE_BASE, UNITS_PROVIDER kiface("pcbnew", KIWAY::FACE_PCB)
static int pcbnewOpenDiffDialogExport(int aKind, const wxString &aFileA, const wxString &aFileB, const wxString &aLabelA, const wxString &aLabelB, wxWindow *aParent, REPORTER *aReporter)
Definition pcbnew.cpp:735
static int pcbnewMergeExport(int aKind, const wxString &aAncestor, const wxString &aOurs, const wxString &aTheirs, const wxString &aOutput, bool aInteractive, bool aSingleFile, REPORTER *aReporter)
Definition pcbnew.cpp:725
static KICAD_DIFF::DIFF_CANVAS_CONTEXT * pcbnewAttachDiffCanvasesExport(int aKind, const wxString &aFileA, const wxString &aFileB, WIDGET_DIFF_CANVAS *aBefore, WIDGET_DIFF_CANVAS *aAfter, KICAD_DIFF::DOCUMENT_DIFF *aDiff, REPORTER *aReporter)
Definition pcbnew.cpp:744
void InvokePcbLibTableEditor(KIWAY *aKiway, wxWindow *aCaller)
Show the modal DIALOG_EDIT_LIBRARY_TABLES for purposes of editing the global and project library tabl...
PANEL_SNAPPING * CreateSnappingPanel(wxWindow *aParent, SETTINGS_T *aCfg, FRAME_T aFrameType, SNAP_INFERENCE_SETTINGS SETTINGS_T::*aInference=nullptr, MAGNETIC_SETTINGS SETTINGS_T::*aMagnetics=nullptr)
Build the snapping page for an editor.
static bool startFootprintLibraryLoad()
Start loading the footprint libraries in the background.
Definition pcbnew.cpp:269
static PROJECT * footprintLibraryProject()
Return the project whose footprint libraries the kiface-level footprint services work with.
Definition pcbnew.cpp:107
static wxString filterFootprints(const wxString &aFilterJson)
Filter footprints based on criteria passed as JSON.
Definition pcbnew.cpp:144
static float footprintLibraryLoadProgress()
Return how far a background load has got.
Definition pcbnew.cpp:289
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition pcbnew.cpp:759
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
T * GetToolbarSettings(const wxString &aFilename)
T * GetAppSettings(const char *aFilename)
The outcome of a footprint match query, and the JSON encoding used to move it across the Pcbnew kifac...
bool OnKifaceStart(PGM_BASE *aProgram, int aCtlBits, KIWAY *aKiway) override
Typically start_common() is called from here.
The full set of changes between two parsed documents of one type.
wxString path
File path (KIND::FILE_KIND) or project path (KIND::LIBID_KIND).
Definition kiway.h:164
LIB_ID libId
Library identifier; valid when kind == KIND::LIBID_KIND.
Definition kiway.h:165
Implement a participant in the KIWAY alchemy.
Definition kiway.h:153
std::atomic_bool m_libraryPreloadInProgress
Definition pcbnew.cpp:709
bool OnKifaceStart(PGM_BASE *aProgram, int aCtlBits, KIWAY *aKiway) override
Typically start_common() is called from here.
Definition pcbnew.cpp:770
void PreloadLibraries(KIWAY *aKiway) override
Definition pcbnew.cpp:1348
KIWAY * m_kiway
Definition pcbnew.cpp:715
void ProjectChanged() override
Definition pcbnew.cpp:1456
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:853
void CancelPreload(bool aBlock=true) override
Definition pcbnew.cpp:1463
std::shared_ptr< BACKGROUND_JOB > m_libraryPreloadBackgroundJob
Definition pcbnew.cpp:707
void * IfaceOrAddress(int aDataId) override
Return a pointer to the requested object.
Definition pcbnew.cpp:605
void RegisterLibraryHandlers(KICAD_API_SERVER *aServer) override
Register this face's library API handlers on the given server.
Definition pcbnew.cpp:1475
void Reset() override
Reloads global state.
Definition pcbnew.cpp:821
std::unique_ptr< API_HANDLER_FOOTPRINT > m_openFpHandler
Definition pcbnew.cpp:719
wxWindow * CreateKiWindow(wxWindow *aParent, int aClassId, KIWAY *aKiway, int aCtlBits=0) override
Create a wxWindow for the current project.
Definition pcbnew.cpp:334
bool handleOpenFootprint(const wxString &aProjectPath, const wxString &aLibIdStr, KICAD_API_SERVER *aServer, wxString *aError)
Definition pcbnew.cpp:1035
IFACE(const char *aName, KIWAY::FACE_T aType)
Definition pcbnew.cpp:323
void closeFootprint(KICAD_API_SERVER *aServer)
Definition pcbnew.cpp:999
std::unique_ptr< API_HANDLER_PCB > m_openHandler
Definition pcbnew.cpp:717
std::atomic_bool m_libraryPreloadAbort
Definition pcbnew.cpp:710
int HandleJob(JOB *aJob, REPORTER *aReporter, PROGRESS_REPORTER *aProgressReporter) override
Definition pcbnew.cpp:968
void closeBoard(KICAD_API_SERVER *aServer)
Definition pcbnew.cpp:980
bool LoadAllLibraries() override
Starts a background load of all libraries of the type owned by this face.
Definition pcbnew.cpp:1487
std::shared_ptr< HEADLESS_FOOTPRINT_CONTEXT > m_openFpContext
Definition pcbnew.cpp:718
bool HandleApiCloseDocument(const DOCUMENT_SPEC &aSpec, KICAD_API_SERVER *aServer, wxString *aError) override
Close the document identified by aSpec.
Definition pcbnew.cpp:1296
std::shared_ptr< HEADLESS_PCB_CONTEXT > m_openContext
Definition pcbnew.cpp:716
bool HandleApiOpenDocument(const DOCUMENT_SPEC &aSpec, KICAD_API_SERVER *aServer, wxString *aError) override
Definition pcbnew.cpp:1013
PCBNEW_JOBS_HANDLER * JobHandler() const
Accessor for the non-job diff/merge exports (pcbnewMergeExport etc.).
Definition pcbnew.cpp:668
std::unique_ptr< API_HANDLER_FP_LIBRARIES > m_apiHandlerFpLibs
Definition pcbnew.cpp:720
std::unique_ptr< PCBNEW_JOBS_HANDLER > m_jobHandler
Definition pcbnew.cpp:706
bool HandleJobConfig(JOB *aJob, wxWindow *aParent) override
Definition pcbnew.cpp:974
bool handleCreatePcb(const wxString &aPath, KICAD_API_SERVER *aServer, wxString *aError)
Definition pcbnew.cpp:1218
bool handleOpenPcb(const wxString &aPath, KICAD_API_SERVER *aServer, wxString *aError)
Definition pcbnew.cpp:1113
void OnKifaceEnd() override
Called just once just before the DSO is to be unloaded.
Definition pcbnew.cpp:828
std::future< void > m_libraryPreloadReturn
Definition pcbnew.cpp:708
IbisParser parser & reporter
KIBIS top(path, &reporter)
VECTOR3I expected(15, 30, 45)
static const long long MM
wxString result
Test unit parsing edge cases and error handling.
#define ENVVARS_CHANGED
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.