KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kicad_manager_frame.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) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2013 CERN (www.cern.ch)
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 "kicad_id.h"
23#include "pcm.h"
24#include "pgm_kicad.h"
25#include "project_tree.h"
26#include "project_tree_pane.h"
29#include "local_history_pane.h"
31
32#include <advanced_config.h>
34#include <bitmaps.h>
35#include <build_version.h>
36#include <confirm.h>
40#include <local_history.h>
42#include <wx/msgdlg.h>
43#include <eda_base_frame.h>
44#include <executable_names.h>
45#include <file_history.h>
46#include <local_history.h>
47#include <policy_keys.h>
48#include <gestfich.h>
49#include <kiplatform/app.h>
51#include <kiplatform/ui.h>
52#include <kiplatform/policy.h>
53#include <build_version.h>
54#include <kiway.h>
55#include <kiway_mail.h>
56#include <launch_ext.h>
57#include <lockfile.h>
59#include <reporter.h>
61#include <sch_file_versions.h>
64#include <tool/action_manager.h>
65#include <tool/action_toolbar.h>
66#include <tool/common_control.h>
68#include <tool/tool_manager.h>
74#include <widgets/kistatusbar.h>
75#include <widgets/ui_common.h>
76#include <wx/ffile.h>
77#include <wx/filedlg.h>
78#include <wx/dnd.h>
79#include <wx/process.h>
80#include <algorithm>
81#include <atomic>
82#include <update_manager.h>
83#include <jobs/jobset.h>
85
86#include <../pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h> // for SEXPR_BOARD_FILE_VERSION def
87
88
89#ifdef __WXMAC__
90#include <MacTypes.h>
91#include <ApplicationServices/ApplicationServices.h>
92#endif
93
94#include "kicad_manager_frame.h"
96
98
99
100#define EDITORS_CAPTION _( "Editors" )
101#define PROJECT_FILES_CAPTION _( "Project Files" )
102
103#define ID_INIT_WATCHED_PATHS 52913
104
105#define SEP() wxFileName::GetPathSeparator()
106
107
108// Menubar and toolbar event table
109BEGIN_EVENT_TABLE( KICAD_MANAGER_FRAME, EDA_BASE_FRAME )
110 // Window events
113
114 // Menu events
131 KICAD_MANAGER_FRAME::OnCompareProjectBranches )
132
133 // Range menu events
135 EVT_MENU( ID_FILE_LIST_CLEAR, KICAD_MANAGER_FRAME::OnClearFileHistory )
136
137 // Special functions
138 EVT_MENU( ID_INIT_WATCHED_PATHS, KICAD_MANAGER_FRAME::OnChangeWatchedPaths )
139
140 // Drop files event
141 EVT_DROP_FILES( KICAD_MANAGER_FRAME::OnDropFiles )
142
143END_EVENT_TABLE()
144
145// See below the purpose of this include
146#include <wx/xml/xml.h>
147
148KICAD_MANAGER_FRAME::KICAD_MANAGER_FRAME( wxWindow* parent, const wxString& title, const wxPoint& pos,
149 const wxSize& size ) :
152 m_openSavedWindows( false ),
153 m_restoredFromHistory( false ),
154 m_active_project( false ),
155 m_showHistoryPanel( false ),
156 m_showGitCommitPanel( true ),
157 m_projectTreePane( nullptr ),
158 m_historyPane( nullptr ),
159 m_gitCommitPane( nullptr ),
160 m_launcher( nullptr ),
161 m_lastToolbarIconSize( 0 ),
162 m_pcmButton( nullptr ),
163 m_pcmUpdateCount( 0 )
164{
165 const int defaultLeftWinWidth = FromDIP( 250 );
166
167 m_leftWinWidth = defaultLeftWinWidth; // Default value
168 m_aboutTitle = "KiCad";
169
170 // JPC: A very ugly hack to fix an issue on Linux: if the wxbase315u_xml_gcc_custom.so is
171 // used **only** in PCM, it is not found in some cases at run time.
172 // So just use it in the main module to avoid a not found issue
173 // wxbase315u_xml_gcc_custom shared object when launching Kicad
174 wxXmlDocument dummy;
175
176 // Create the status line (bottom of the frame). Left half is for project name; right half
177 // is for Reporter (currently used by archiver/unarchiver and PCM).
178 // Note: this is a KISTATUSBAR status bar. Therefore the specified number of fields
179 // is the extra number of fields, not the full field count.
180 // We need here 2 fields: the extra fiels to display the project name, and another field
181 // to display a info (specific to Windows) using the FIELD_OFFSET_BGJOB_TEXT id offset (=1)
182 // So the extra field count is 1
183 CreateStatusBar( 2 );
186 Pgm().RegisterLibraryLoadStatusBar( (KISTATUSBAR*) GetStatusBar() );
187 GetStatusBar()->SetFont( KIUI::GetStatusFont( this ) );
188
189 // Give an icon
190 wxIcon icon;
191 wxIconBundle icon_bundle;
192
193 if( IsNightlyVersion())
194 {
195 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly, 48 ) );
196 icon_bundle.AddIcon( icon );
197 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly, 128 ) );
198 icon_bundle.AddIcon( icon );
199 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly, 256 ) );
200 icon_bundle.AddIcon( icon );
201 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly_32 ) );
202 icon_bundle.AddIcon( icon );
203 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly_16 ) );
204 icon_bundle.AddIcon( icon );
205 }
206 else
207 {
208 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad, 48 ) );
209 icon_bundle.AddIcon( icon );
210 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad, 128 ) );
211 icon_bundle.AddIcon( icon );
212 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad, 256 ) );
213 icon_bundle.AddIcon( icon );
214 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_32 ) );
215 icon_bundle.AddIcon( icon );
216 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_16 ) );
217 icon_bundle.AddIcon( icon );
218 }
219
220 SetIcons( icon_bundle );
221
222 // Load the settings
223 LoadSettings( config() );
224
225 // Left window: is the box which display tree project
226 m_projectTreePane = new PROJECT_TREE_PANE( this );
227
228 setupTools();
229 setupUIConditions();
230
231 m_toolbarSettings = GetToolbarSettings<KICAD_MANAGER_TOOLBAR_SETTINGS>( "kicad-toolbars" );
232 configureToolbars();
233 RecreateToolbars();
234 ReCreateMenuBar();
235
236 m_auimgr.SetManagedWindow( this );
237 m_auimgr.SetFlags( wxAUI_MGR_LIVE_RESIZE );
238
239 m_auimgr.AddPane( m_tbLeft, EDA_PANE().VToolbar().Name( "TopMainToolbar" ).Left().Layer( 2 ) );
240
241 // There is no wxAUIPaneInfo::SetSize(), but a trick is to use MinSize() to set the required pane width,
242 // and after give a reasonable MinSize value.
243 m_auimgr.AddPane( m_projectTreePane,
244 EDA_PANE().Palette().Name( "ProjectTree" ).Left().Layer( 1 )
245 .Caption( PROJECT_FILES_CAPTION ).PaneBorder( false )
246 .MinSize( m_leftWinWidth, -1 ).Floatable( false ).Movable( false ) );
247
248 m_historyPane = new LOCAL_HISTORY_PANE( this );
249 m_auimgr.AddPane( m_historyPane,
250 EDA_PANE().Palette().Name( "LocalHistory" ).Left().Layer( 1 ).Position( 1 )
251 .Caption( _( "Local History" ) ).PaneBorder( false )
252 .Floatable( false ).Movable( false ).CloseButton( true ).Hide() );
253
254 if( m_showHistoryPanel )
255 m_auimgr.GetPane( m_historyPane ).Show();
256
257 m_gitCommitPane = new GIT_COMMIT_PANE( this );
258 m_auimgr.AddPane( m_gitCommitPane, EDA_PANE()
259 .Palette()
260 .Name( GitCommitPaneName() )
261 .Left()
262 .Layer( 1 )
263 .Position( 2 )
264 .Caption( _( "Version Control" ) )
265 .MinSize( wxSize( m_gitCommitPane->GetMinDockWidth(), -1 ) )
266 .PaneBorder( false )
267 .Floatable( false )
268 .Movable( false )
269 .CloseButton( true )
270 .Hide() );
271
272 if( m_showGitCommitPanel )
273 m_auimgr.GetPane( m_gitCommitPane ).Show();
274
275 // Refresh the changed-file list when the user returns to the project manager, since
276 // edits are made in the separate editor windows.
277 Bind( wxEVT_ACTIVATE,
278 [this]( wxActivateEvent& aEvent )
279 {
280 aEvent.Skip();
281
282 // Reading the status walks the repository, so only do it for a pane the user can
283 // actually see. Showing the pane refreshes it, so the gate cannot leave it stale.
284 if( aEvent.GetActive() && GitCommitPaneShown() )
285 m_gitCommitPane->RefreshFileList();
286 } );
287
288 wxSize client_size = GetClientSize();
289 m_notebook = new wxAuiNotebook( this, wxID_ANY, wxPoint( client_size.x, client_size.y ),
290 FromDIP( wxSize( 700, 590 ) ),
291 wxAUI_NB_TOP | wxAUI_NB_CLOSE_ON_ALL_TABS | wxAUI_NB_TAB_MOVE
292 | wxAUI_NB_SCROLL_BUTTONS | wxNO_BORDER );
293
294 m_notebook->SetArtProvider( new WX_AUI_TAB_ART() );
295
296 m_notebook->Bind( wxEVT_AUINOTEBOOK_PAGE_CLOSE, &KICAD_MANAGER_FRAME::onNotebookPageCloseRequest, this );
297 m_notebook->Bind( wxEVT_AUINOTEBOOK_PAGE_CLOSED, &KICAD_MANAGER_FRAME::onNotebookPageCountChanged, this );
298 m_launcher = new PANEL_KICAD_LAUNCHER( m_notebook );
299
300 m_notebook->Freeze();
301 m_launcher->SetClosable( false );
302 m_notebook->AddPage( m_launcher, EDITORS_CAPTION, false );
303 m_notebook->SetTabCtrlHeight( 0 );
304 m_notebook->Thaw();
305
306 m_auimgr.AddPane( m_notebook, EDA_PANE().Canvas().Name( "Editors" ).Center().Caption( EDITORS_CAPTION )
307 .PaneBorder( false ).MinSize( m_notebook->GetBestSize() ) );
308
309 m_auimgr.Update();
310
311 // Now the actual m_projectTreePane size is set, give it a reasonable min width
312 m_auimgr.GetPane( m_projectTreePane ).MinSize( defaultLeftWinWidth, FromDIP( 80 ) );
313
314
315 wxSizer* mainSizer = GetSizer();
316
317 // Only fit the initial window size the first time KiCad is run.
318 if( mainSizer && config()->m_Window.state.size_x == 0 && config()->m_Window.state.size_y == 0 )
319 {
320 Layout();
321 mainSizer->Fit( this );
322 Center();
323 }
324
325 if( ADVANCED_CFG::GetCfg().m_HideVersionFromTitle )
326 SetTitle( wxT( "KiCad" ) );
327 else
328 SetTitle( wxString( "KiCad " ) + GetMajorMinorVersion() );
329
330 // Do not let the messages window have initial focus
331 m_projectTreePane->SetFocus();
332
333 // Init for dropping files
336
337 // Gerber files
338 // Note that all gerber files are aliased as GerberFileExtension
342
343 DragAcceptFiles( true );
344}
345
346
348{
350 Unbind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
351
352 m_notebook->Unbind( wxEVT_AUINOTEBOOK_PAGE_CLOSE, &KICAD_MANAGER_FRAME::onNotebookPageCloseRequest, this );
353 m_notebook->Unbind( wxEVT_AUINOTEBOOK_PAGE_CLOSED, &KICAD_MANAGER_FRAME::onNotebookPageCountChanged, this );
354
357 Pgm().UnregisterLibraryLoadStatusBar( (KISTATUSBAR*) GetStatusBar() );
358
359 // Shutdown all running tools
360 if( m_toolManager )
361 m_toolManager->ShutdownAllTools();
362
363 if( m_pcm )
364 m_pcm->StopBackgroundUpdate();
365
366 // Stop update manager before tearing down the AUI framework. The update
367 // task runs on the thread pool and may call CallAfter on this frame, so it
368 // must complete before we uninitialize AUI or destroy child windows.
369 m_updateManager.reset();
370
371 delete m_actions;
372 delete m_toolManager;
373 delete m_toolDispatcher;
374
375 m_auimgr.UnInit();
376}
377
379{
380 if( m_notebook->GetPageCount() == 1 )
381 m_notebook->SetTabCtrlHeight( 0 );
382 else
383 m_notebook->SetTabCtrlHeight( -1 );
384}
385
386
388{
390}
391
392
394{
395 wxAuiNotebook* notebook = (wxAuiNotebook*) evt.GetEventObject();
396 wxWindow* page = notebook->GetPage( evt.GetSelection() );
397
398 if( PANEL_NOTEBOOK_BASE* panel = dynamic_cast<PANEL_NOTEBOOK_BASE*>( page ) )
399 {
400 if( panel->GetClosable() )
401 {
402 if( !panel->GetCanClose() )
403 evt.Veto();
404
405 CallAfter(
406 [this]()
407 {
409 } );
410 }
411 else
412 {
413 evt.Veto();
414 }
415 }
416}
417
418
419wxStatusBar* KICAD_MANAGER_FRAME::OnCreateStatusBar( int number, long style, wxWindowID id,
420 const wxString& name )
421{
422 KISTATUSBAR* sb = new KISTATUSBAR( number, this, id,
426
427 size_t sbFieldCnt = static_cast<size_t>( sb->GetFieldsCount() );
428 std::vector<int> sbFieldSizes( sbFieldCnt );
429
430 for( size_t i = 0; i < sbFieldCnt; i++ )
431 sbFieldSizes[i] = sb->GetStatusWidth( static_cast<int>( i ) );
432
433 // Field 0 (the project path) is the only stretchable field so it uses all the leftover width
434 // before ellipsizing. Field 1 gets a fixed width sized to its watcher text; longer content
435 // (archive progress) is ellipsized rather than allowed to steal the path's width.
436 if( sbFieldCnt > 0 )
437 sbFieldSizes[0] = -1;
438
439 if( sbFieldCnt > 1 )
440 {
441 int margin = KIUI::GetTextSize( wxT( "XX" ), sb ).x;
442 int watcherWidth = std::max( KIUI::GetTextSize( _( "Local path: monitoring folder changes" ), sb ).x,
443 KIUI::GetTextSize( _( "Network path: not monitoring folder changes" ), sb ).x );
444
445 sbFieldSizes[1] = watcherWidth + margin;
446 }
447
448 sb->SetStatusWidths( sbFieldCnt, sbFieldSizes.data() );
449
450 return sb;
451}
452
453
455{
456 // creates the PLUGIN_CONTENT_MANAGER, if not exists
457 if( m_pcm )
458 return;
459
460 m_pcm = std::make_shared<PLUGIN_CONTENT_MANAGER>(
461 [this]( int aUpdateCount )
462 {
463 if( Pgm().m_Quitting )
464 return;
465
466 m_pcmUpdateCount = aUpdateCount;
467
468 if( aUpdateCount > 0 )
469 {
471 wxS( "pcm" ),
472 _( "PCM Updates Available" ),
473 wxString::Format( _( "%d package update(s) available" ), aUpdateCount ),
474 wxT( "" ) );
475 }
476 else
477 {
478 Pgm().GetNotificationsManager().Remove( wxS( "pcm" ) );
479 }
480
481 CallAfter(
482 [this]()
483 {
485 } );
486 });
487
488 m_pcm->SetRepositoryList( kicadSettings()->m_PcmRepositories );
489}
490
491
493{
494 // Create the manager
496 m_toolManager->SetEnvironment( nullptr, nullptr, nullptr, config(), this );
498
500
501 // Attach the events to the tool dispatcher
503 Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
504
505 // Register tools
506 m_toolManager->RegisterTool( new COMMON_CONTROL );
507 m_toolManager->RegisterTool( new KICAD_MANAGER_CONTROL );
508 m_toolManager->InitTools();
509}
510
511
513{
515
516 ACTION_MANAGER* manager = m_toolManager->GetActionManager();
517
518 wxASSERT( manager );
519
520 auto activeProject =
521 [this] ( const SELECTION& )
522 {
523 return m_active_project;
524 };
525
526#define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
527
528 ACTION_CONDITIONS activeProjectCond;
529 activeProjectCond.Enable( activeProject );
530
531 manager->SetConditions( ACTIONS::saveAs, activeProjectCond );
532 manager->SetConditions( KICAD_MANAGER_ACTIONS::exportForOlderVersion, activeProjectCond );
533 manager->SetConditions( KICAD_MANAGER_ACTIONS::closeProject, activeProjectCond );
534 manager->SetConditions( KICAD_MANAGER_ACTIONS::archiveProject, activeProjectCond );
535 manager->SetConditions( KICAD_MANAGER_ACTIONS::newJobsetFile, activeProjectCond );
536 manager->SetConditions( KICAD_MANAGER_ACTIONS::openJobsetFile, activeProjectCond );
537
538 auto historyCond =
539 [this]( const SELECTION& )
540 {
541 return HistoryPanelShown();
542 };
543
545
546 auto gitCommitPaneCond = [this]( const SELECTION& )
547 {
548 return GitCommitPaneShown();
549 };
550
551 manager->SetConditions( ACTIONS::showGitCommitPane, ACTION_CONDITIONS().Check( gitCommitPaneCond ) );
552
553 // These are just here for text boxes, search boxes, etc. in places such as the standard
554 // file dialogs.
558
559#undef ENABLE
560}
561
562
564{
565 return m_projectTreePane;
566}
567
568
570{
572 wxASSERT( ret );
573 return ret;
574}
575
576
578{
579 KICAD_SETTINGS* ret = dynamic_cast<KICAD_SETTINGS*>( config() );
580 wxASSERT( ret );
581 return ret;
582}
583
584
586{
587 CallAfter(
588 [&]()
589 {
590 KIFACE *schface = Kiway().KiFACE( KIWAY::FACE_SCH );
591 schface->PreloadLibraries( &Kiway() );
592
593 KIFACE *pcbface = Kiway().KiFACE( KIWAY::FACE_PCB );
594 pcbface->PreloadLibraries( &Kiway() );
595
597 } );
598}
599
600
602{
603 return GetProjectFileName();
604}
605
606
608{
610 : wxString( wxEmptyString );
611}
612
613
615{
616 wxFileName fn( GetProjectFileName() );
617
619 return fn.GetFullPath();
620}
621
622
624{
625 wxFileName fn( GetProjectFileName() );
626
628 return fn.GetFullPath();
629}
630
631
633{
634 wxFileName fn( GetProjectFileName() );
635
636 fn.SetExt( FILEEXT::PcbFileExtension );
637 return fn.GetFullPath();
638}
639
640
642{
643 wxFileName fn( GetProjectFileName() );
644
646 return fn.GetFullPath();
647}
648
649
651{
652 m_projectTreePane->ReCreateTreePrj();
653}
654
655
660
661
663{
664 return PgmTop().GetHelpFileName();
665}
666
667
668void KICAD_MANAGER_FRAME::OnSize( wxSizeEvent& event )
669{
670 if( m_auimgr.GetManagedWindow() )
671 m_auimgr.Update();
672
673 event.Skip();
674}
675
676
678{
679 // All fileNames are now in m_AcceptedFiles vector.
680 // Check if contains a project file name and load project.
681 // If not, open files in dedicated app.
682 for( const wxFileName& fileName : m_AcceptedFiles )
683 {
684 wxString ext = fileName.GetExt();
685
687 {
688 wxString fn = fileName.GetFullPath();
689 m_toolManager->RunAction<wxString*>( *m_acceptedExts.at( fileName.GetExt() ), &fn );
690
691 return;
692 }
693 }
694
695 // Then stock gerber files in gerberFiles and run action for other files.
696 wxString gerberFiles;
697
698 // Gerbview editor should be able to open Gerber and drill files
699 for( const wxFileName& fileName : m_AcceptedFiles )
700 {
701 wxString ext = fileName.GetExt();
702
706 {
707 gerberFiles += wxT( '\"' );
708 gerberFiles += fileName.GetFullPath() + wxT( '\"' );
709 gerberFiles = gerberFiles.Pad( 1 );
710 }
711 else
712 {
713 wxString fn = fileName.GetFullPath();
714 m_toolManager->RunAction<wxString*>( *m_acceptedExts.at( fileName.GetExt() ), &fn );
715 }
716 }
717
718 // Execute Gerbviewer
719 if( !gerberFiles.IsEmpty() )
720 {
721 wxString fullEditorName = FindKicadFile( GERBVIEW_EXE );
722
723 if( wxFileExists( fullEditorName ) )
724 {
725 wxString command = fullEditorName + " " + gerberFiles;
726 m_toolManager->RunAction<wxString*>( *m_acceptedExts.at( FILEEXT::GerberFileExtension ), &command );
727 }
728 }
729}
730
731
732bool KICAD_MANAGER_FRAME::canCloseWindow( wxCloseEvent& aEvent )
733{
734 KICAD_SETTINGS* settings = kicadSettings();
736
737 for( size_t i = 0; i < m_notebook->GetPageCount(); i++ )
738 {
739 wxWindow* page = m_notebook->GetPage( i );
740
741 if( PANEL_NOTEBOOK_BASE* panel = dynamic_cast<PANEL_NOTEBOOK_BASE*>( page ) )
742 {
743 if( !panel->GetCanClose() )
744 return false;
745 }
746 }
747
748 // CloseProject will recursively ask all the open editors if they need to save changes.
749 // If any of them cancel then we need to cancel closing the KICAD_MANAGER_FRAME.
750 if( CloseProject( true ) )
751 {
752 // Don't propagate event to frames which have already been closed
753 aEvent.StopPropagation();
754
755 return true;
756 }
757 else
758 {
759 if( aEvent.CanVeto() )
760 aEvent.Veto();
761
762 return false;
763 }
764}
765
766
768{
769#ifdef _WINDOWS_
770 // For some obscure reason, on Windows, when killing Kicad from the Windows task manager
771 // if a editor frame (schematic, library, board editor or fp editor) is open and has
772 // some edition to save, OnCloseWindow is run twice *at the same time*, creating race
773 // conditions between OnCloseWindow() code.
774 // Therefore I added (JPC) a ugly hack to discard the second call (unwanted) during
775 // execution of the first call (only one call is right).
776 // Note also if there is no change made in editors, this behavior does not happen.
777 static std::atomic<unsigned int> lock_close_event( 0 );
778
779 if( ++lock_close_event > 1 ) // Skip extra calls
780 {
781 return;
782 }
783#endif
784
785 m_projectTreePane->Show( false );
786 Pgm().m_Quitting = true;
787
788 Destroy();
789
790#ifdef _WINDOWS_
791 lock_close_event = 0; // Reenable event management
792#endif
793}
794
795
797{
799
800 if( !aIsExplicitUserSave && !cfg.ShouldAutoSave() )
801 return;
802
803 cfg.m_OpenJobSets.clear();
804
805 for( size_t i = 0; i < m_notebook->GetPageCount(); i++ )
806 {
807 if( PANEL_JOBSET* jobset = dynamic_cast<PANEL_JOBSET*>( m_notebook->GetPage( i ) ) )
808 {
809 wxFileName jobsetFn( jobset->GetFilePath() );
810 jobsetFn.MakeRelativeTo( Prj().GetProjectPath() );
811 cfg.m_OpenJobSets.emplace_back( jobsetFn.GetFullPath() );
812 }
813 }
814
815 cfg.SaveToFile( Prj().GetProjectPath() );
816}
817
818
819void KICAD_MANAGER_FRAME::OnExit( wxCommandEvent& event )
820{
821 Close( true );
822}
823
824
826{
827 if( !Kiway().PlayersClose( false ) )
828 return false;
829
830 // Abort any in-progress background load, since the threads depend on the project not changing
831 KIFACE *schface = Kiway().KiFACE( KIWAY::FACE_SCH );
832 schface->CancelPreload();
833
834 KIFACE *pcbface = Kiway().KiFACE( KIWAY::FACE_PCB );
835 pcbface->CancelPreload();
836
837 // Save the project file for the currently loaded project.
838 if( m_active_project )
839 {
841
842 if( Prj().GetLocalSettings().ShouldAutoSave() && Prj().GetProjectFile().ShouldAutoSave() )
843 {
845
846 if( aSave )
847 mgr.SaveProject();
848 }
849
850 // Ensure the Last_Save tag is at HEAD before closing. This handles the case where
851 // autosave commits were made after the last explicit save - without this, the next
852 // project load would offer to restore the autosave state, which is incorrect after
853 // a clean close.
854 wxString projPath = Prj().GetProjectPath();
855
856 // Wait for any in-flight autosave so the HEAD check below isn't racing it.
858
859 if( Pgm().GetCommonSettings()->AutosaveUsesLocalHistory()
860 && !projPath.IsEmpty() && Kiway().LocalHistory().HistoryExists( projPath ) )
861 {
862 if( Kiway().LocalHistory().HeadNewerThanLastSave( projPath ) )
863 {
864 // Tag unconditionally: even on no-op snapshots Last_Save must anchor at HEAD.
865 Kiway().LocalHistory().CommitFullProjectSnapshot( projPath, wxS( "Close" ) );
866 Kiway().LocalHistory().TagSave( projPath, wxS( "project" ) );
867 }
868 }
869
870 // The editors clean up autosaves for sheets actually dirtied in their session.
871 // Anything still on disk here was deferred by the user in the recovery dialog
872 // and must survive so the dialog can offer it again on the next open.
873
874 m_active_project = false;
875 // Enforce local history size limit (if enabled) once all pending saves/backups are done.
876 if( Pgm().GetCommonSettings()
877 && Pgm().GetCommonSettings()->AutosaveUsesLocalHistory() )
878 {
879 unsigned long long int limit = Pgm().GetCommonSettings()->m_Backup.limit_total_size;
880
881 if( limit > 0 && Kiway().LocalHistory().IsCompacting() )
882 {
883 Kiway().LocalHistory().EnforceSizeLimitInBackground( Prj().GetProjectPath(), (size_t) limit );
884 }
885 else if( limit > 0 )
886 {
887 WX_PROGRESS_REPORTER reporter( this, _( "Local History" ), 3, PR_NO_ABORT );
888 Kiway().LocalHistory().EnforceSizeLimit( Prj().GetProjectPath(), (size_t) limit, &reporter );
889 }
890 }
891
892 // Unregister the project saver before unloading the project to prevent
893 // dangling references
895
896 // Must run before the unload below, which releases the git session without waiting.
897 m_projectTreePane->WaitForGitOperations();
898
899 mgr.UnloadProject( &Prj() );
900 }
901
902 SetStatusText( "" );
903
904 // Traverse pages in reverse order so deleting them doesn't mess up our iterator.
905 for( int i = (int) m_notebook->GetPageCount() - 1; i >= 0; i-- )
906 {
907 wxWindow* page = m_notebook->GetPage( i );
908
909 if( PANEL_NOTEBOOK_BASE* panel = dynamic_cast<PANEL_NOTEBOOK_BASE*>( page ) )
910 {
911 if( panel->GetProjectTied() )
912 m_notebook->DeletePage( i );
913 }
914 }
915
916 m_projectTreePane->EmptyTreePrj();
918
919 return true;
920}
921
922
923void KICAD_MANAGER_FRAME::OpenJobsFile( const wxFileName& aFileName, bool aCreate, bool aResaveProjectPreferences )
924{
925 for( size_t i = 0; i < m_notebook->GetPageCount(); i++ )
926 {
927 if( PANEL_JOBSET* panel = dynamic_cast<PANEL_JOBSET*>( m_notebook->GetPage( i ) ) )
928 {
929 if( aFileName.GetFullPath() == panel->GetFilePath() )
930 {
931 m_notebook->SetSelection( i );
932 return;
933 }
934 }
935 }
936
937 try
938 {
939 std::unique_ptr<JOBSET> jobsFile = std::make_unique<JOBSET>( aFileName.GetFullPath().ToStdString() );
940
941 jobsFile->LoadFromFile();
942
943 if( aCreate && !aFileName.FileExists() )
944 {
945 JOBSET_DESTINATION* dest = jobsFile->AddNewDestination( JOBSET_DESTINATION_T::FOLDER );
946 dest->m_outputHandler->SetOutputPath( aFileName.GetName() );
947 jobsFile->SaveToFile( wxEmptyString, true );
948 }
949
950 PANEL_JOBSET* jobPanel = new PANEL_JOBSET( m_notebook, this, std::move( jobsFile ) );
951 jobPanel->SetProjectTied( true );
952 jobPanel->SetClosable( true );
953 m_notebook->AddPage( jobPanel, aFileName.GetFullName(), true );
955
956 if( aResaveProjectPreferences )
958 }
959 catch( ... )
960 {
961 DisplayErrorMessage( this, _( "Error opening jobs file" ) );
962 }
963}
964
965
966bool KICAD_MANAGER_FRAME::LoadProject( const wxFileName& aProjectFileName )
967{
968 // The project file should be valid by the time we get here or something has gone wrong.
969 if( !aProjectFileName.Exists() )
970 return false;
971
972 wxString fullPath = aProjectFileName.GetFullPath();
973
974 // Inspect only; SETTINGS_MANAGER::LoadProject() takes the real lock
975 LOCKFILE lockFile = LOCKFILE::Inspect( fullPath );
976
977 bool lockOverrideGranted = false;
978
979 if( !lockFile.Valid() )
980 {
981 wxString msg;
982 msg.Printf( _( "Project '%s' is already open by '%s' at '%s'." ),
983 fullPath,
984 lockFile.GetUsername(),
985 lockFile.GetHostname() );
986
987 if( !AskOverrideLock( this, msg ) )
988 return false; // User clicked Cancel - abort project loading entirely
989
990 // Clear the lock so the load below can take it
991 LOCKFILE overridden( fullPath );
992 overridden.OverrideLock();
993
994 lockOverrideGranted = true;
995 }
996
997 // Any open KIFACE's must be closed if they are not part of the new project.
998 // (We never want a KIWAY_PLAYER open on a KIWAY that isn't in the same project.)
999 // User is prompted here to close those KIWAY_PLAYERs:
1000 if( !CloseProject( true ) )
1001 return false;
1002
1003 m_active_project = true;
1004
1005 // NB: when loading a legacy project SETTINGS_MANAGER::LoadProject() will convert it to
1006 // current extension. Be very careful with aProjectFileName vs. Prj().GetProjectPath()
1007 // from here on out.
1008
1009 Pgm().GetSettingsManager().LoadProject( fullPath );
1010
1011 // Propagate lock override decision to the loaded project
1012 if( lockOverrideGranted )
1013 Prj().SetLockOverrideGranted( true );
1014
1015 LoadWindowState( aProjectFileName.GetFullName() );
1016
1017 if( aProjectFileName.IsDirWritable() )
1018 SetMruPath( Prj().GetProjectPath() );
1019
1020 if( Pgm().GetCommonSettings()->AutosaveUsesLocalHistory()
1021 && Kiway().LocalHistory().HeadNewerThanLastSave( Prj().GetProjectPath() ) )
1022 {
1023 wxString head = Kiway().LocalHistory().GetHeadHash( Prj().GetProjectPath() );
1024
1025 KICAD_MESSAGE_DIALOG dlg( this, _( "KiCad found unsaved changes from your last session that are newer than "
1026 "the saved project files." ),
1027 _( "Recover Unsaved Changes" ), wxYES_NO | wxICON_QUESTION );
1028
1029 dlg.SetExtendedMessage( _( "This can happen if your previous session ended unexpectedly.\n\n"
1030 "Choose 'Restore' to recover those changes, or 'Discard' to keep the "
1031 "currently saved files." ) );
1032
1033 dlg.SetYesNoLabels( _( "Restore" ), _( "Discard" ) );
1034
1035 if( dlg.ShowModal() == wxID_YES )
1036 {
1037 // The dialog above is the confirmation, skip RestoreCommit's own prompt.
1038 Kiway().LocalHistory().RestoreCommit( Prj().GetProjectPath(), head, this, false );
1039 }
1040 else
1041 {
1042 // User declined; commit on-disk state and tag unconditionally so Last_Save anchors
1043 // at HEAD even if no new commit was needed.
1044 Kiway().LocalHistory().CommitFullProjectSnapshot( Prj().GetProjectPath(), wxS( "Declined restore" ) );
1045 Kiway().LocalHistory().TagSave( Prj().GetProjectPath(), wxS( "project" ) );
1046 }
1047 }
1048
1049 // Save history & window state to disk now. Don't wait around for a crash.
1050 KICAD_SETTINGS* settings = kicadSettings();
1051 SaveSettings( settings );
1052 settings->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( settings ) );
1053
1054 m_projectTreePane->ReCreateTreePrj();
1055 m_historyPane->RefreshHistory( Prj().GetProjectPath() );
1056
1057 if( GitCommitPaneShown() )
1058 m_gitCommitPane->RefreshFileList();
1059
1060 for( const wxString& jobset : Prj().GetLocalSettings().m_OpenJobSets )
1061 {
1062 wxFileName jobsetFn( jobset );
1063 jobsetFn.MakeAbsolute( Prj().GetProjectPath() );
1064
1065 if( jobsetFn.Exists() )
1066 OpenJobsFile( jobsetFn.GetFullPath(), false, false );
1067 }
1068
1069 // Always start with the apps page
1070 m_notebook->SetSelection( 0 );
1071
1072 // Rebuild the list of watched paths.
1073 // however this is possible only when the main loop event handler is running,
1074 // so we use it to run the rebuild function.
1075 wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED, ID_INIT_WATCHED_PATHS );
1076
1077 wxPostEvent( this, cmd );
1078
1079 PrintPrjInfo();
1080
1081 KIPLATFORM::APP::RegisterApplicationRestart( aProjectFileName.GetFullPath() );
1082 m_openSavedWindows = true;
1083
1084 KIPLATFORM::ENV::AddToRecentDocs( aProjectFileName.GetFullPath() );
1085
1086 // Now that we have a new project, trigger a library preload, which will load in any
1087 // project-specific symbol and footprint libraries into the manager
1089 return true;
1090}
1091
1092
1093void KICAD_MANAGER_FRAME::CreateNewProject( const wxFileName& aProjectFileName, bool aCreateStubFiles )
1094{
1095 wxCHECK_RET( aProjectFileName.DirExists() && aProjectFileName.IsDirWritable(),
1096 "Project folder must exist and be writable to create a new project." );
1097
1098 // If the project is legacy, convert it
1099 if( !aProjectFileName.FileExists() )
1100 {
1101 wxFileName legacyPro( aProjectFileName );
1102 legacyPro.SetExt( FILEEXT::LegacyProjectFileExtension );
1103
1104 if( legacyPro.FileExists() )
1105 {
1106 GetSettingsManager()->LoadProject( legacyPro.GetFullPath() );
1108
1109 wxRemoveFile( legacyPro.GetFullPath() );
1110 }
1111 else
1112 {
1113 // Copy template project file from template folder.
1114 wxString srcFileName = sys_search().FindValidPath( "kicad.kicad_pro" );
1115
1116 wxFileName destFileName( aProjectFileName );
1117 destFileName.SetExt( FILEEXT::ProjectFileExtension );
1118
1119 // Create a minimal project file if the template project file could not be copied
1120 if( !wxFileName::FileExists( srcFileName )
1121 || !wxCopyFile( srcFileName, destFileName.GetFullPath() ) )
1122 {
1123 wxFFile file( destFileName.GetFullPath(), "wb" );
1124
1125 if( file.IsOpened() )
1126 file.Write( wxT( "{\n}\n") );
1127
1128 // wxFFile dtor will close the file
1129 }
1130 }
1131 }
1132
1133 // Create a "stub" for a schematic root sheet and a board if requested.
1134 // It will avoid messages from the schematic editor or the board editor to create a new file
1135 // And forces the user to create main files under the right name for the project manager
1136 if( aCreateStubFiles )
1137 {
1138 wxFileName fn( aProjectFileName.GetFullPath() );
1140
1141 // If a <project>.kicad_sch file does not exist, create a "stub" file ( minimal schematic
1142 // file ).
1143 if( !fn.FileExists() )
1144 {
1145 wxFFile file( fn.GetFullPath(), "wb" );
1146
1147 if( file.IsOpened() )
1148 {
1149 file.Write( wxString::Format( "(kicad_sch\n"
1150 "\t(version %d)\n"
1151 "\t(generator \"eeschema\")\n"
1152 "\t(generator_version \"%s\")\n"
1153 "\t(uuid %s)\n"
1154 "\t(paper \"A4\")\n"
1155 "\t(lib_symbols)\n"
1156 "\t(sheet_instances\n"
1157 "\t\t(path \"/\"\n"
1158 "\t\t\t(page \"1\")\n"
1159 "\t\t)\n"
1160 "\t)\n"
1161 "\t(embedded_fonts no)\n"
1162 ")",
1165 KIID().AsString() ) );
1166 }
1167
1168 // wxFFile dtor will close the file
1169 }
1170
1171 // If a <project>.kicad_pcb or <project>.brd file does not exist,
1172 // create a .kicad_pcb "stub" file
1173 fn.SetExt( FILEEXT::KiCadPcbFileExtension );
1174 wxFileName leg_fn( fn );
1175 leg_fn.SetExt( FILEEXT::LegacyPcbFileExtension );
1176
1177 if( !fn.FileExists() && !leg_fn.FileExists() )
1178 {
1179 wxFFile file( fn.GetFullPath(), "wb" );
1180
1181 if( file.IsOpened() )
1182 {
1183 // Create a small dummy file as a stub for pcbnew:
1184 file.Write( wxString::Format( "(kicad_pcb (version %d) (generator \"pcbnew\") (generator_version \"%s\")\n)",
1186 }
1187
1188 // wxFFile dtor will close the file
1189 }
1190 }
1191
1192 // Save history & window state to disk now. Don't wait around for a crash.
1193 KICAD_SETTINGS* settings = kicadSettings();
1194 SaveSettings( settings );
1195 settings->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( settings ) );
1196
1197 m_openSavedWindows = true;
1198}
1199
1200
1202{
1203 std::shared_ptr<KIGIT_COMMON> gitCommon = Prj().GetGitCommon();
1204 git_repository* repo = gitCommon->GetRepo();
1205
1206 if( !repo )
1207 {
1208 wxMessageBox( _( "Compare Project Branches requires a project that is "
1209 "tracked by git." ),
1210 _( "Compare Branches" ),
1211 wxOK | wxICON_INFORMATION, this );
1212 return;
1213 }
1214
1215 std::vector<wxString> refs;
1216
1217 // libgit2 is not safe for concurrent use of one repository, so read the refs under the git
1218 // action lock. If a background operation holds it, fall back to HEAD.
1219 if( std::unique_lock<std::mutex> lock = gitCommon->TryLockAction(); lock.owns_lock() )
1220 refs = KIGIT::CompareBranchRefs( repo );
1221
1222 if( refs.empty() )
1223 refs.push_back( wxS( "HEAD" ) );
1224
1225 DIALOG_GIT_MR_REVIEW dlg( this, gitCommon.get(), refs );
1226 dlg.ShowModal();
1227}
1228
1229
1231{
1232 // show all files in file dialog (in Kicad all files are editable texts):
1233 wxString wildcard = FILEEXT::AllFilesWildcard();
1234
1235 wxString default_dir = Prj().GetProjectPath();
1236
1237 wxFileDialog dlg( this, _( "Edit File in Text Editor" ), default_dir, wxEmptyString, wildcard,
1238 wxFD_OPEN );
1239
1241
1242 if( dlg.ShowModal() == wxID_CANCEL )
1243 return;
1244
1245 wxString filename = dlg.GetPath();
1246
1247 if( !dlg.GetPath().IsEmpty() && !Pgm().GetTextEditor().IsEmpty() )
1248 m_toolManager->RunAction<wxString*>( KICAD_MANAGER_ACTIONS::openTextEditor, &filename );
1249}
1250
1251
1252void KICAD_MANAGER_FRAME::OnEditAdvancedCfg( wxCommandEvent& WXUNUSED( event ) )
1253{
1254 DIALOG_EDIT_CFG dlg( this );
1255 dlg.ShowModal();
1256}
1257
1258
1260{
1261 m_projectTreePane->ReCreateTreePrj();
1262}
1263
1264
1266{
1267 // call my base class
1269
1270 // tooltips in toolbars
1272 m_launcher->CreateLaunchers();
1273
1274 // update captions
1275 int pageId = m_notebook->FindPage( m_launcher );
1276
1277 if( pageId != wxNOT_FOUND )
1278 m_notebook->SetPageText( pageId, EDITORS_CAPTION );
1279
1280 m_auimgr.GetPane( m_projectTreePane ).Caption( PROJECT_FILES_CAPTION );
1281 m_auimgr.Update();
1282
1283 m_projectTreePane->FileWatcherReset();
1284
1285 PrintPrjInfo();
1286}
1287
1288
1290{
1292
1293 if( m_pcm && ( aFlags & ENVVARS_CHANGED ) )
1294 m_pcm->ReadEnvVar();
1295
1296 COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
1297
1298 if( m_lastToolbarIconSize == 0
1300 {
1303 }
1304
1305 m_projectTreePane->ReCreateTreePrj();
1306
1307 // The tree rebuild above does not reach the panel.
1308 if( m_gitCommitPane )
1309 {
1310 m_gitCommitPane->RefreshFileList();
1311 m_gitCommitPane->ReloadAdvancedWindow();
1312 }
1313}
1314
1315
1317{
1318 wxString file = GetProjectFileName();
1319
1320 // empty file string means no project loaded
1321 if( !Prj().IsNullProject() &&
1322 Prj().GetProjectLock() == nullptr )
1323 {
1324 LOCKFILE lockFile( file );
1325
1326 if( !lockFile.Valid() )
1327 {
1328 wxString msg;
1329 msg.Printf( _( "Project '%s' is already open by '%s' at '%s'." ),
1330 file,
1331 lockFile.GetUsername(),
1332 lockFile.GetHostname() );
1333
1334 if( AskOverrideLock( this, msg ) )
1335 {
1336 lockFile.OverrideLock();
1337 }
1338 }
1339
1340 Prj().SetReadOnly( !lockFile.Valid() || Prj().GetProjectFile().IsReadOnly() );
1341 Prj().SetProjectLock( new LOCKFILE( std::move( lockFile ) ) );
1342 }
1343
1344 wxString title;
1345
1346 if( !file.IsEmpty() )
1347 {
1348 wxFileName fn( file );
1349
1350 title = fn.GetName();
1351
1352 if( Prj().IsReadOnly() )
1353 title += wxS( " " ) + _( "[Read Only]" );
1354 }
1355 else
1356 {
1357 title = _( "[no project loaded]" );
1358 }
1359
1360 if( ADVANCED_CFG::GetCfg().m_HideVersionFromTitle )
1361 title += wxT( " \u2014 " ) + wxString( wxS( "KiCad" ) );
1362 else
1363 title += wxT( " \u2014 " ) + wxString( wxS( "KiCad " ) ) + GetMajorMinorVersion();
1364
1365 SetTitle( title );
1366
1367 // Register project file saver. Ensures project file participates in
1368 // autosave history commits without affecting dirty state.
1370 [this]( const wxString& aProjectPath, std::vector<HISTORY_FILE_DATA>& aFileData )
1371 {
1372 Prj().SaveToHistory( aProjectPath, aFileData );
1373 },
1375}
1376
1377
1379{
1381
1382 auto settings = dynamic_cast<KICAD_SETTINGS*>( aCfg );
1383
1384 wxCHECK( settings, /*void*/ );
1385
1386 m_leftWinWidth = settings->m_LeftWinWidth;
1387 m_showHistoryPanel = settings->m_ShowHistoryPanel;
1388 m_showGitCommitPanel = settings->m_ShowGitCommitPanel;
1389}
1390
1391
1393{
1395
1396 KICAD_SETTINGS* settings = dynamic_cast<KICAD_SETTINGS*>( aCfg );
1397
1398 wxCHECK( settings, /*void*/ );
1399
1400 settings->m_LeftWinWidth = m_projectTreePane->GetSize().x;
1401 settings->m_ShowHistoryPanel = m_historyPane && m_auimgr.GetPane( m_historyPane ).IsShown();
1403
1404 if( !m_isClosing )
1406}
1407
1408
1410{
1411 wxString status = wxString::Format( _( "Project: %s" ), Prj().GetProjectFullName() );
1412 SetStatusText( status, 0 );
1413}
1414
1415
1420
1421
1422void KICAD_MANAGER_FRAME::OnIdle( wxIdleEvent& aEvent )
1423{
1429 if( !m_openSavedWindows )
1430 return;
1431
1432 m_openSavedWindows = false;
1433
1434 if( Pgm().GetCommonSettings()->m_Session.remember_open_files )
1435 {
1436 int previousOpenCount = std::count_if( Prj().GetLocalSettings().m_files.begin(),
1437 Prj().GetLocalSettings().m_files.end(),
1438 [&]( const PROJECT_FILE_STATE& f )
1439 {
1440 return !f.fileName.EndsWith( FILEEXT::ProjectFileExtension ) && f.open;
1441 } );
1442
1443 if( previousOpenCount > 0 )
1444 {
1445 APP_PROGRESS_DIALOG progressReporter( _( "Restoring session" ), wxEmptyString, previousOpenCount, this );
1446
1447 // We don't currently support opening more than one view per file
1448 std::set<wxString> openedFiles;
1449
1450 int i = 0;
1451
1452 for( const PROJECT_FILE_STATE& file : Prj().GetLocalSettings().m_files )
1453 {
1454 if( file.open && !openedFiles.count( file.fileName ) )
1455 {
1456 progressReporter.Update( i++, wxString::Format( _( "Restoring '%s'" ), file.fileName ) );
1457
1458 openedFiles.insert( file.fileName );
1459 wxFileName fn( file.fileName );
1460
1461 if( fn.GetExt() == FILEEXT::LegacySchematicFileExtension
1462 || fn.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1463 {
1465 }
1466 else if( fn.GetExt() == FILEEXT::LegacyPcbFileExtension
1467 || fn.GetExt() == FILEEXT::KiCadPcbFileExtension )
1468 {
1470 }
1471 }
1472
1473 wxYield();
1474 }
1475 }
1476 }
1477
1478 // clear file states regardless if we opened windows or not due to setting
1480
1481 // After restore from history, mark open editors as dirty so user is prompted to save
1483 {
1484 m_restoredFromHistory = false;
1485
1486 // Mark schematic editor as dirty if open
1487 if( KIWAY_PLAYER* schFrame = Kiway().Player( FRAME_SCH, false ) )
1488 schFrame->OnModify();
1489
1490 // Mark PCB editor as dirty if open
1491 if( KIWAY_PLAYER* pcbFrame = Kiway().Player( FRAME_PCB_EDITOR, false ) )
1492 pcbFrame->OnModify();
1493 }
1494
1495 KICAD_SETTINGS* settings = kicadSettings();
1496
1498 && settings->m_PcmUpdateCheck )
1499 {
1500 if( !m_pcm )
1501 CreatePCM();
1502
1503 m_pcm->RunBackgroundUpdate();
1504 }
1505
1506#ifdef KICAD_UPDATE_CHECK
1507 if( !m_updateManager && settings->m_KiCadUpdateCheck )
1508 {
1509 m_updateManager = std::make_unique<UPDATE_MANAGER>();
1510 m_updateManager->CheckForUpdate( this );
1511 }
1512#endif
1513
1514 // This little diddy is needed to get the window put into the Mac dock icon's context menu.
1515 Raise();
1516}
1517
1518
1520{
1521 m_pcmButton = aButton;
1522
1524}
1525
1526
1528{
1529 if( m_pcmButton )
1530 {
1531 if( m_pcmUpdateCount > 0 )
1532 {
1533 m_pcmButton->SetShowBadge( true );
1534 m_pcmButton->SetBadgeText( wxString::Format( "%d", m_pcmUpdateCount ) );
1535 }
1536 else
1537 {
1538 m_pcmButton->SetShowBadge( false );
1539 }
1540
1541 m_pcmButton->Refresh();
1542 }
1543}
1544
1545
1547{
1548 // No idea why, but the same mechanism used in EDA_DRAW_FRAME doesn't work here
1549 // the only thing that seems to work is to blow it all up and start from scratch.
1550 m_auimgr.DetachPane( m_tbLeft );
1551 delete m_tbLeft;
1552 m_tbLeft = nullptr;
1554 m_auimgr.AddPane( m_tbLeft, EDA_PANE().HToolbar().Name( "TopMainToolbar" ).Left().Layer( 2 ) );
1555
1556 m_auimgr.Update();
1557}
1558
1559
1561{
1562 wxAuiPaneInfo& pane = m_auimgr.GetPane( m_historyPane );
1563 bool show = !pane.IsShown();
1564 pane.Show( show );
1565
1566 if( show )
1567 m_historyPane->RefreshHistory( Prj().GetProjectPath() );
1568
1569 m_auimgr.Update();
1570}
1571
1572
1574{
1575 if( !Kiway().PlayersClose( true ) )
1576 return;
1577
1578 if( Kiway().LocalHistory().RestoreCommit( Prj().GetProjectPath(), aHash, this ) )
1579 {
1580 m_restoredFromHistory = true; // Mark editors dirty when they reopen
1581 }
1582
1583 m_projectTreePane->ReCreateTreePrj();
1584 m_openSavedWindows = true;
1585 m_historyPane->RefreshHistory( Prj().GetProjectPath() );
1586}
1587
1588
1590{
1591 return m_historyPane && m_auimgr.GetPane( m_historyPane ).IsShown();
1592}
1593
1594
1596{
1597 wxAuiPaneInfo& pane = m_auimgr.GetPane( m_gitCommitPane );
1598 bool show = !pane.IsShown();
1599
1600 pane.Show( show );
1601
1602 if( show )
1603 m_gitCommitPane->RefreshFileList();
1604
1605 m_auimgr.Update();
1606}
1607
1608
1610{
1611 return m_gitCommitPane && m_auimgr.GetPane( m_gitCommitPane ).IsShown();
1612}
const char * name
constexpr EDA_IU_SCALE unityScale
Definition base_units.h:131
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition bitmap.cpp:100
@ icon_kicad_nightly
@ icon_kicad_nightly_32
@ icon_kicad_nightly_16
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
bool IsNightlyVersion()
Check if the build is meant to be nightly.
static TOOL_ACTION paste
Definition actions.h:76
static TOOL_ACTION saveAs
Definition actions.h:55
static TOOL_ACTION copy
Definition actions.h:74
static TOOL_ACTION showGitCommitPane
Definition actions.h:263
static TOOL_ACTION cut
Definition actions.h:73
Manage TOOL_ACTION objects.
void SetConditions(const TOOL_ACTION &aAction, const ACTION_CONDITIONS &aConditions)
Set the conditions the UI elements for activating a specific tool action should use for determining t...
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
wxProgressDialog with the option to also update the application progress on the taskbar
virtual bool Update(int aValue, const wxString &aNewMsg=wxEmptyString, bool *aSkip=nullptr) override
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
void UnregisterStatusBar(KISTATUSBAR *aStatusBar)
Removes status bar from handling.
void RegisterStatusBar(KISTATUSBAR *aStatusBar)
Add a status bar for handling.
A bitmap button widget that behaves like an AUI toolbar item's button when it is drawn.
Handle actions that are shared between different applications.
APPEARANCE m_Appearance
AUTO_BACKUP m_Backup
Git PR-style branch comparison dialog (Phase 10).
int ShowModal() override
The base frame for deriving all KiCad main window classes.
void LoadWindowState(const wxString &aFileName)
void CommonSettingsChanged(int aFlags) override
Notification event that some of the common (suite-wide) settings have changed.
void ShowChangedLanguage() override
Redraw the menus and what not in current language.
virtual void setupUIConditions()
Setup the UI conditions for the various actions and their controls in this frame.
std::vector< wxFileName > m_AcceptedFiles
SETTINGS_MANAGER * GetSettingsManager() const
wxAuiManager m_auimgr
virtual void RecreateToolbars()
virtual void LoadSettings(APP_SETTINGS_BASE *aCfg)
Load common frame parameters from a configuration file.
ACTION_TOOLBAR * m_tbLeft
std::map< const wxString, TOOL_ACTION * > m_acceptedExts
Associate file extensions with action to execute.
virtual void SaveSettings(APP_SETTINGS_BASE *aCfg)
Save common frame parameters to a configuration data file.
void SetMruPath(const wxString &aPath)
bool m_isClosing
Set by the close window event handler after frames are asked if they can close.
Specialization of the wxAuiPaneInfo class for KiCad panels.
Docked panel for committing: the branch to commit to, a summary and description, the commit options,...
void SetOutputPath(const wxString &aPath)
Definition jobs_output.h:56
virtual bool SaveToFile(const wxString &aDirectory="", bool aForce=false)
Calls Store() and then writes the contents of the JSON document to a file.
static TOOL_ACTION viewDroppedGerbers
static TOOL_ACTION loadProject
static TOOL_ACTION exportForOlderVersion
static TOOL_ACTION showLocalHistory
static TOOL_ACTION editSchematic
static TOOL_ACTION openTextEditor
static TOOL_ACTION archiveProject
static TOOL_ACTION closeProject
static TOOL_ACTION openJobsetFile
static TOOL_ACTION newJobsetFile
Handle actions in the kicad manager frame.
The main KiCad project manager frame.
std::shared_ptr< PLUGIN_CONTENT_MANAGER > m_pcm
void SetPcmButton(BITMAP_BUTTON *aButton)
void CreateNewProject(const wxFileName &aProjectFileName, bool aCreateStubFiles=true)
Creates a new project by setting up and initial project, schematic, and board files.
const SEARCH_STACK & sys_search() override
Return a SEARCH_STACK pertaining to entire program.
void OnImportEasyEdaProFiles(wxCommandEvent &event)
Open dialog to import EasyEDA Pro schematic and board files.
void ProjectChanged() override
Notification event that the project has changed.
void ShowChangedLanguage() override
Redraw the menus and what not in current language.
const wxString SchLegacyFileName()
wxWindow * GetToolCanvas() const override
Canvas access.
void OnImportEasyEdaFiles(wxCommandEvent &event)
Open dialog to import EasyEDA Std schematic and board files.
void OnImportPadsProjectFiles(wxCommandEvent &event)
Open dialog to import PADS Logic schematic and PCB files.
void OnImportEasyPcFiles(wxCommandEvent &event)
Open dialog to import an Easy-PC / DesignSpark PCB project, schematic or board.
void OnImportAltiumProjectFiles(wxCommandEvent &event)
Open dialog to import Altium project files.
const wxString GetProjectFileName() const
KICAD_SETTINGS * kicadSettings() const
void OnImportEagleFiles(wxCommandEvent &event)
Open dialog to import Eagle schematic and board files.
wxStatusBar * OnCreateStatusBar(int number, long style, wxWindowID id, const wxString &name) override
Create the status line (like a wxStatusBar).
void OnExit(wxCommandEvent &event)
void OpenJobsFile(const wxFileName &aFileName, bool aCreate=false, bool aResaveProjectPreferences=true)
bool canCloseWindow(wxCloseEvent &aCloseEvent) override
void OnSize(wxSizeEvent &event) override
GIT_COMMIT_PANE * m_gitCommitPane
virtual void setupUIConditions() override
Setup the UI conditions for the various actions and their controls in this frame.
PROJECT_TREE_PANE * m_projectTreePane
void OnImportGedaFiles(wxCommandEvent &event)
Open dialog to import gEDA/gaf schematic and PCB files.
void RestoreCommitFromHistory(const wxString &aHash)
void DoWithAcceptedFiles() override
Execute action on accepted dropped file.
void OnOpenFileInTextEditor(wxCommandEvent &event)
APP_SETTINGS_BASE * config() const override
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
void OnImportOrcadFiles(wxCommandEvent &event)
Open dialog to import an OrCAD schematic file.
const wxString PcbLegacyFileName()
void OnEditAdvancedCfg(wxCommandEvent &event)
void OnImportPcadProjectFiles(wxCommandEvent &event)
KICAD_MANAGER_FRAME(wxWindow *parent, const wxString &title, const wxPoint &pos, const wxSize &size)
bool CloseProject(bool aSave)
Closes the project, and saves it if aSave is true;.
wxString GetCurrentFileName() const override
Get the full filename + path of the currently opened file in the frame.
void onNotebookPageCloseRequest(wxAuiNotebookEvent &evt)
void CommonSettingsChanged(int aFlags) override
Notification event that some of the common (suite-wide) settings have changed.
void LoadSettings(APP_SETTINGS_BASE *aCfg) override
Load common frame parameters from a configuration file.
void OnIdle(wxIdleEvent &event)
void PrintPrjInfo()
Prints the current working directory name and the project name on the text panel.
void OnImportDipTraceFiles(wxCommandEvent &event)
Open dialog to import DipTrace schematic and board files.
void SaveOpenJobSetsToLocalSettings(bool aIsExplicitUserSave=false)
bool LoadProject(const wxFileName &aProjectFileName)
Loads a new project.
bool m_restoredFromHistory
Set after restore to mark editors dirty.
void onNotebookPageCountChanged(wxAuiNotebookEvent &evt)
LOCAL_HISTORY_PANE * m_historyPane
void OnImportCadstarArchiveFiles(wxCommandEvent &event)
Open dialog to import CADSTAR Schematic and PCB Archive files.
void OnImportTarget3001Files(wxCommandEvent &event)
void OnCompareProjectBranches(wxCommandEvent &event)
Open DIALOG_GIT_MR_REVIEW so the user can pick two refs and review the changed-file list between them...
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Save common frame parameters to a configuration data file.
BITMAP_BUTTON * m_pcmButton
PANEL_KICAD_LAUNCHER * m_launcher
void HideTabsIfNeeded()
Hides the tabs for Editor notebook if there is only 1 page.
wxString help_name() override
std::unique_ptr< UPDATE_MANAGER > m_updateManager
std::vector< wxString > m_OpenProjects
Definition kiid.h:46
KISTATUSBAR is a wxStatusBar suitable for Kicad manager.
Definition kistatusbar.h:50
virtual void SetStatusWidths(int aSize, const int *aWidths) override
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition kiway.cpp:214
@ FACE_SCH
eeschema DSO
Definition kiway.h:355
@ FACE_PCB
pcbnew DSO
Definition kiway.h:356
LOCAL_HISTORY & LocalHistory()
Return the LOCAL_HISTORY associated with this KIWAY.
Definition kiway.h:457
void EnforceSizeLimitInBackground(const wxString &aProjectPath, size_t aMaxBytes)
Run EnforceSizeLimit without a reporter on a background thread, after any running compaction.
bool EnforceSizeLimit(const wxString &aProjectPath, size_t aMaxBytes, PROGRESS_REPORTER *aReporter=nullptr)
Enforce total size limit by rebuilding trimmed history keeping newest commits whose cumulative unique...
bool TagSave(const wxString &aProjectPath, const wxString &aFileType)
Tag a manual save in the local history repository.
wxString GetHeadHash(const wxString &aProjectPath)
Return the current head commit hash.
void WaitForPendingSave()
Block until any pending background save completes.
bool RestoreCommit(const wxString &aProjectPath, const wxString &aHash, wxWindow *aParent=nullptr, bool aConfirm=true)
Restore the project files to the state recorded by the given commit hash.
bool CommitFullProjectSnapshot(const wxString &aProjectPath, const wxString &aTitle)
Commit a snapshot of the entire project directory (excluding the .history directory and ignored trans...
void RegisterSaver(const void *aSaverObject, const std::function< void(const wxString &, std::vector< HISTORY_FILE_DATA > &)> &aSaver, const std::weak_ptr< void > &aLifetime={})
Register a saver callback invoked during autosave history commits.
void UnregisterSaver(const void *aSaverObject)
Unregister a previously registered saver callback.
Advisory lock over a file, taken by writing a sibling lock file and holding an exclusive lock on it f...
Definition lockfile.h:54
bool OverrideLock(bool aRemoveOnRelease=true)
Force the lock, overwriting the data that existed already.
Definition lockfile.h:188
bool Valid() const
Definition lockfile.h:224
wxString GetUsername()
Definition lockfile.h:214
wxString GetHostname()
Definition lockfile.h:220
static LOCKFILE Inspect(const wxString &aFilename)
Look at a lock without taking it: nothing is created, nothing is claimed and nothing is removed on re...
Definition lockfile.h:113
void RegisterStatusBar(KISTATUSBAR *aStatusBar)
Add a status bar for handling.
void CreateOrUpdate(const wxString &aKey, const wxString &aTitle, const wxString &aDescription, const wxString &aHref=wxEmptyString)
Create a notification with the given parameters or updates an existing one with the same key.
void Remove(const wxString &aKey)
Remove a notification by key.
void UnregisterStatusBar(KISTATUSBAR *aStatusBar)
Remove status bar from handling.
static REPORTER & GetInstance()
Definition reporter.cpp:207
void SetClosable(bool aYes)
void SetProjectTied(bool aYes)
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:562
void PreloadDesignBlockLibraries(KIWAY *aKiway)
Starts a background job to preload the global and project design block libraries.
Definition pgm_base.cpp:908
virtual BACKGROUND_JOBS_MONITOR & GetBackgroundJobMonitor() const
Definition pgm_base.h:129
void UnregisterLibraryLoadStatusBar(KISTATUSBAR *aStatusBar)
Unregister a status bar from receiving library load warning messages.
bool m_Quitting
Definition pgm_base.h:390
void RegisterLibraryLoadStatusBar(KISTATUSBAR *aStatusBar)
Register a status bar to receive library load warning messages.
Definition pgm_base.cpp:989
virtual NOTIFICATIONS_MANAGER & GetNotificationsManager() const
Definition pgm_base.h:134
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:123
wxString GetHelpFileName()
Definition pgm_kicad.h:58
SEARCH_STACK & SysSearch()
Definition pgm_kicad.h:56
APP_SETTINGS_BASE * PgmSettings()
Definition pgm_kicad.h:54
The project local settings are things that are attached to a particular project, but also might be pa...
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Calls Store() and then writes the contents of the JSON document to a file.
std::vector< wxString > m_OpenJobSets
Window to display the tree files.
void SetProjectLock(LOCKFILE *aLockFile)
Definition project.cpp:554
virtual void SetReadOnly(bool aReadOnly=true)
Definition project.h:161
virtual std::shared_ptr< KIGIT_COMMON > GetGitCommon() const
This project's Git session, created empty on first use.
Definition project.cpp:84
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:270
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:276
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition project.h:207
std::weak_ptr< void > GetHistoryLifetimeToken() const
Liveness token handed to LOCAL_HISTORY::RegisterSaver so a shared autosave timer skips this project's...
Definition project.h:333
virtual void SetLockOverrideGranted(bool aGranted=true)
Definition project.h:165
void SaveToHistory(const wxString &aProjectPath, std::vector< HISTORY_FILE_DATA > &aFileData)
Produce HISTORY_FILE_DATA entries for project files (.kicad_pro and .kicad_prl).
Definition project.cpp:560
Look for files in a number of paths.
static bool ShowNever(const SELECTION &aSelection)
Always returns false.
bool SaveProject(const wxString &aFullPath=wxEmptyString, PROJECT *aProject=nullptr)
Save a loaded project.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
bool IsProjectOpen() const
Helper for checking if we have a project open.
bool UnloadProject(PROJECT *aProject, bool aSave=true)
Save, unload and unregister the given PROJECT.
std::vector< wxString > GetOpenProjects() const
bool TriggerBackupIfNeeded(REPORTER &aReporter) const
Call BackupProject() if a new backup is needed according to the current backup policy.
TOOL_MANAGER * m_toolManager
TOOL_DISPATCHER * m_toolDispatcher
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
ACTIONS * m_actions
virtual void DispatchWxEvent(wxEvent &aEvent)
Process wxEvents (mostly UI events), translate them to TOOL_EVENTs, and make tools handle those.
Master controller class:
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
bool AskOverrideLock(wxWindow *aParent, const wxString &aMessage)
Display a dialog indicating the file is already open, with an option to reset the lock.
Definition confirm.cpp:38
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
Definition confirm.h:48
#define ENABLE(x)
#define _(s)
Base window classes and related definitions.
#define KICAD_DEFAULT_DRAWFRAME_STYLE
#define KICAD_MANAGER_FRAME_NAME
EVT_MENU_RANGE(ID_GERBVIEW_DRILL_FILE1, ID_GERBVIEW_DRILL_FILEMAX, GERBVIEW_FRAME::OnDrlFileHistory) EVT_MENU_RANGE(ID_GERBVIEW_ZIP_FILE1
KiCad executable names.
const wxString GERBVIEW_EXE
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_SCH
Definition frame_type.h:30
@ KICAD_MAIN_FRAME_T
Definition frame_type.h:67
wxString FindKicadFile(const wxString &shortname)
Search the executable file shortname in KiCad binary path and return full file name if found or short...
Definition gestfich.cpp:68
static const std::string LegacySchematicFileExtension
static const std::string GerberJobFileExtension
static const std::string GerberFileExtension
static const std::string ProjectFileExtension
static const std::string LegacyPcbFileExtension
static const std::string LegacyProjectFileExtension
static const std::string KiCadSchematicFileExtension
static const std::string DrillFileExtension
static const std::string KiCadPcbFileExtension
static wxString AllFilesWildcard()
static bool IsGerberFileExtension(const wxString &ext)
@ ID_FILE_LIST_CLEAR
Definition id.h:58
@ ID_FILEMAX
Definition id.h:56
@ ID_FILE1
Definition id.h:55
PGM_KICAD & PgmTop()
Definition kicad.cpp:96
@ ID_IMPORT_EASYPC_PROJECT
Definition kicad_id.h:44
@ ID_EDIT_ADVANCED_CFG
Definition kicad_id.h:34
@ ID_IMPORT_DIPTRACE_PROJECT
Definition kicad_id.h:43
@ ID_IMPORT_EAGLE_PROJECT
Definition kicad_id.h:36
@ ID_IMPORT_EASYEDAPRO_PROJECT
Definition kicad_id.h:38
@ ID_IMPORT_PADS_PROJECT
Definition kicad_id.h:40
@ ID_IMPORT_GEDA_PROJECT
Definition kicad_id.h:42
@ ID_IMPORT_PCAD_PROJECT
Definition kicad_id.h:41
@ ID_IMPORT_CADSTAR_ARCHIVE_PROJECT
Definition kicad_id.h:35
@ ID_EDIT_LOCAL_FILE_IN_TEXT_EDITOR
Definition kicad_id.h:33
@ ID_IMPORT_ORCAD_PROJECT
Definition kicad_id.h:46
@ ID_IMPORT_EASYEDA_PROJECT
Definition kicad_id.h:37
@ ID_IMPORT_ALTIUM_PROJECT
Definition kicad_id.h:39
@ ID_COMPARE_PROJECT_BRANCHES
Definition kicad_id.h:47
@ ID_IMPORT_TARGET3001_PROJECT
Definition kicad_id.h:45
EVT_MENU(ID_COMPARE_PROJECT_BRANCHES, KICAD_MANAGER_FRAME::OnCompareProjectBranches) KICAD_MANAGER_FRAME
#define EDITORS_CAPTION
#define ID_INIT_WATCHED_PATHS
#define PROJECT_FILES_CAPTION
std::vector< wxString > CompareBranchRefs(git_repository *aRepo)
Refs to offer when comparing branches, base first and head second.
bool RegisterApplicationRestart(const wxString &aCommandLine)
Registers the application for restart with the OS with the given command line string to pass as args.
Definition unix/app.cpp:83
void AddToRecentDocs(const wxString &aPath)
PBOOL GetPolicyBool(const wxString &aKey)
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:640
KICOMMON_API wxFont GetStatusFont(wxWindow *aWindow)
KICOMMON_API wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
Definition ui_common.cpp:80
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
PGM_BASE & Pgm()
The global program "get" accessor.
#define POLICY_KEY_PCM
Definition policy_keys.h:27
#define SEXPR_SCHEMATIC_FILE_VERSION
Schematic file version.
T * GetToolbarSettings(const wxString &aFilename)
KIWAY Kiway(KFCTL_STANDALONE)
std::vector< FAB_LAYER_COLOR > dummy
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
ACTION_CONDITIONS & Enable(const SELECTION_CONDITION &aCondition)
unsigned long long limit_total_size
Maximum total size of backups (bytes), 0 for unlimited.
std::shared_ptr< JOBS_OUTPUT_HANDLER > m_outputHandler
Definition jobset.h:137
Implement a participant in the KIWAY alchemy.
Definition kiway.h:153
virtual void PreloadLibraries(KIWAY *aKiway)
Definition kiway.h:298
virtual void CancelPreload(bool aBlock=true)
Definition kiway.h:300
IbisParser parser & reporter
#define ENVVARS_CHANGED
Functions to provide common constants and other functions to assist in making a consistent UI.
Definition of file extensions used in Kicad.
#define PR_NO_ABORT