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"
28#include "local_history_pane.h"
30
31#include <advanced_config.h>
33#include <bitmaps.h>
34#include <build_version.h>
35#include <confirm.h>
39#include <local_history.h>
41#include <wx/msgdlg.h>
42#include <eda_base_frame.h>
43#include <executable_names.h>
44#include <file_history.h>
45#include <local_history.h>
46#include <policy_keys.h>
47#include <gestfich.h>
48#include <kiplatform/app.h>
50#include <kiplatform/ui.h>
51#include <kiplatform/policy.h>
52#include <build_version.h>
53#include <kiway.h>
54#include <kiway_mail.h>
55#include <launch_ext.h>
56#include <lockfile.h>
58#include <reporter.h>
60#include <sch_file_versions.h>
63#include <tool/action_manager.h>
64#include <tool/action_toolbar.h>
65#include <tool/common_control.h>
67#include <tool/tool_manager.h>
73#include <widgets/kistatusbar.h>
74#include <widgets/ui_common.h>
75#include <wx/ffile.h>
76#include <wx/filedlg.h>
77#include <wx/dnd.h>
78#include <wx/process.h>
79#include <algorithm>
80#include <atomic>
81#include <update_manager.h>
82#include <jobs/jobset.h>
84
85#include <../pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h> // for SEXPR_BOARD_FILE_VERSION def
86
87
88#ifdef __WXMAC__
89#include <MacTypes.h>
90#include <ApplicationServices/ApplicationServices.h>
91#endif
92
93#include "kicad_manager_frame.h"
95
97
98
99#define EDITORS_CAPTION _( "Editors" )
100#define PROJECT_FILES_CAPTION _( "Project Files" )
101
102#define ID_INIT_WATCHED_PATHS 52913
103
104#define SEP() wxFileName::GetPathSeparator()
105
106
107// Menubar and toolbar event table
108BEGIN_EVENT_TABLE( KICAD_MANAGER_FRAME, EDA_BASE_FRAME )
109 // Window events
112
113 // Menu events
129 KICAD_MANAGER_FRAME::OnCompareProjectBranches )
130
131 // Range menu events
133 EVT_MENU( ID_FILE_LIST_CLEAR, KICAD_MANAGER_FRAME::OnClearFileHistory )
134
135 // Special functions
136 EVT_MENU( ID_INIT_WATCHED_PATHS, KICAD_MANAGER_FRAME::OnChangeWatchedPaths )
137
138 // Drop files event
139 EVT_DROP_FILES( KICAD_MANAGER_FRAME::OnDropFiles )
140
141END_EVENT_TABLE()
142
143// See below the purpose of this include
144#include <wx/xml/xml.h>
145
146KICAD_MANAGER_FRAME::KICAD_MANAGER_FRAME( wxWindow* parent, const wxString& title,
147 const wxPoint& pos, const wxSize& size ) :
150 m_openSavedWindows( false ),
151 m_restoredFromHistory( false ),
152 m_active_project( false ),
153 m_showHistoryPanel( false ),
154 m_projectTreePane( nullptr ),
155 m_historyPane( nullptr ),
156 m_launcher( nullptr ),
157 m_lastToolbarIconSize( 0 ),
158 m_pcmButton( nullptr ),
159 m_pcmUpdateCount( 0 )
160{
161 const int defaultLeftWinWidth = FromDIP( 250 );
162
163 m_leftWinWidth = defaultLeftWinWidth; // Default value
164 m_aboutTitle = "KiCad";
165
166 // JPC: A very ugly hack to fix an issue on Linux: if the wxbase315u_xml_gcc_custom.so is
167 // used **only** in PCM, it is not found in some cases at run time.
168 // So just use it in the main module to avoid a not found issue
169 // wxbase315u_xml_gcc_custom shared object when launching Kicad
170 wxXmlDocument dummy;
171
172 // Create the status line (bottom of the frame). Left half is for project name; right half
173 // is for Reporter (currently used by archiver/unarchiver and PCM).
174 // Note: this is a KISTATUSBAR status bar. Therefore the specified number of fields
175 // is the extra number of fields, not the full field count.
176 // We need here 2 fields: the extra fiels to display the project name, and another field
177 // to display a info (specific to Windows) using the FIELD_OFFSET_BGJOB_TEXT id offset (=1)
178 // So the extra field count is 1
179 CreateStatusBar( 2 );
182 Pgm().RegisterLibraryLoadStatusBar( (KISTATUSBAR*) GetStatusBar() );
183 GetStatusBar()->SetFont( KIUI::GetStatusFont( this ) );
184
185 // Give an icon
186 wxIcon icon;
187 wxIconBundle icon_bundle;
188
189 if( IsNightlyVersion())
190 {
191 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly, 48 ) );
192 icon_bundle.AddIcon( icon );
193 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly, 128 ) );
194 icon_bundle.AddIcon( icon );
195 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly, 256 ) );
196 icon_bundle.AddIcon( icon );
197 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly_32 ) );
198 icon_bundle.AddIcon( icon );
199 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly_16 ) );
200 icon_bundle.AddIcon( icon );
201 }
202 else
203 {
204 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad, 48 ) );
205 icon_bundle.AddIcon( icon );
206 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad, 128 ) );
207 icon_bundle.AddIcon( icon );
208 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad, 256 ) );
209 icon_bundle.AddIcon( icon );
210 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_32 ) );
211 icon_bundle.AddIcon( icon );
212 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_16 ) );
213 icon_bundle.AddIcon( icon );
214 }
215
216 SetIcons( icon_bundle );
217
218 // Load the settings
219 LoadSettings( config() );
220
221 // Left window: is the box which display tree project
222 m_projectTreePane = new PROJECT_TREE_PANE( this );
223
224 setupTools();
225 setupUIConditions();
226
227 m_toolbarSettings = GetToolbarSettings<KICAD_MANAGER_TOOLBAR_SETTINGS>( "kicad-toolbars" );
228 configureToolbars();
229 RecreateToolbars();
230 ReCreateMenuBar();
231
232 m_auimgr.SetManagedWindow( this );
233 m_auimgr.SetFlags( wxAUI_MGR_LIVE_RESIZE );
234
235 m_auimgr.AddPane( m_tbLeft, EDA_PANE().VToolbar().Name( "TopMainToolbar" ).Left().Layer( 2 ) );
236
237 // There is no wxAUIPaneInfo::SetSize(), but a trick is to use MinSize() to set the required pane width,
238 // and after give a reasonable MinSize value.
239 m_auimgr.AddPane( m_projectTreePane,
240 EDA_PANE().Palette().Name( "ProjectTree" ).Left().Layer( 1 )
241 .Caption( PROJECT_FILES_CAPTION ).PaneBorder( false )
242 .MinSize( m_leftWinWidth, -1 ).Floatable( false ).Movable( false ) );
243
244 m_historyPane = new LOCAL_HISTORY_PANE( this );
245 m_auimgr.AddPane( m_historyPane,
246 EDA_PANE().Palette().Name( "LocalHistory" ).Left().Layer( 1 ).Position( 1 )
247 .Caption( _( "Local History" ) ).PaneBorder( false )
248 .Floatable( false ).Movable( false ).CloseButton( true ).Hide() );
249
250 if( m_showHistoryPanel )
251 m_auimgr.GetPane( m_historyPane ).Show();
252
253 wxSize client_size = GetClientSize();
254 m_notebook = new wxAuiNotebook( this, wxID_ANY, wxPoint( client_size.x, client_size.y ),
255 FromDIP( wxSize( 700, 590 ) ),
256 wxAUI_NB_TOP | wxAUI_NB_CLOSE_ON_ALL_TABS | wxAUI_NB_TAB_MOVE
257 | wxAUI_NB_SCROLL_BUTTONS | wxNO_BORDER );
258
259 m_notebook->SetArtProvider( new WX_AUI_TAB_ART() );
260
261 m_notebook->Bind( wxEVT_AUINOTEBOOK_PAGE_CLOSE, &KICAD_MANAGER_FRAME::onNotebookPageCloseRequest, this );
262 m_notebook->Bind( wxEVT_AUINOTEBOOK_PAGE_CLOSED, &KICAD_MANAGER_FRAME::onNotebookPageCountChanged, this );
263 m_launcher = new PANEL_KICAD_LAUNCHER( m_notebook );
264
265 m_notebook->Freeze();
266 m_launcher->SetClosable( false );
267 m_notebook->AddPage( m_launcher, EDITORS_CAPTION, false );
268 m_notebook->SetTabCtrlHeight( 0 );
269 m_notebook->Thaw();
270
271 m_auimgr.AddPane( m_notebook, EDA_PANE().Canvas().Name( "Editors" ).Center().Caption( EDITORS_CAPTION )
272 .PaneBorder( false ).MinSize( m_notebook->GetBestSize() ) );
273
274 m_auimgr.Update();
275
276 // Now the actual m_projectTreePane size is set, give it a reasonable min width
277 m_auimgr.GetPane( m_projectTreePane ).MinSize( defaultLeftWinWidth, FromDIP( 80 ) );
278
279
280 wxSizer* mainSizer = GetSizer();
281
282 // Only fit the initial window size the first time KiCad is run.
283 if( mainSizer && config()->m_Window.state.size_x == 0 && config()->m_Window.state.size_y == 0 )
284 {
285 Layout();
286 mainSizer->Fit( this );
287 Center();
288 }
289
290 if( ADVANCED_CFG::GetCfg().m_HideVersionFromTitle )
291 SetTitle( wxT( "KiCad" ) );
292 else
293 SetTitle( wxString( "KiCad " ) + GetMajorMinorVersion() );
294
295 // Do not let the messages window have initial focus
296 m_projectTreePane->SetFocus();
297
298 // Init for dropping files
301
302 // Gerber files
303 // Note that all gerber files are aliased as GerberFileExtension
307
308 DragAcceptFiles( true );
309}
310
311
313{
315 Unbind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
316
317 m_notebook->Unbind( wxEVT_AUINOTEBOOK_PAGE_CLOSE, &KICAD_MANAGER_FRAME::onNotebookPageCloseRequest, this );
318 m_notebook->Unbind( wxEVT_AUINOTEBOOK_PAGE_CLOSED, &KICAD_MANAGER_FRAME::onNotebookPageCountChanged, this );
319
322 Pgm().UnregisterLibraryLoadStatusBar( (KISTATUSBAR*) GetStatusBar() );
323
324 // Shutdown all running tools
325 if( m_toolManager )
326 m_toolManager->ShutdownAllTools();
327
328 if( m_pcm )
329 m_pcm->StopBackgroundUpdate();
330
331 // Stop update manager before tearing down the AUI framework. The update
332 // task runs on the thread pool and may call CallAfter on this frame, so it
333 // must complete before we uninitialize AUI or destroy child windows.
334 m_updateManager.reset();
335
336 delete m_actions;
337 delete m_toolManager;
338 delete m_toolDispatcher;
339
340 m_auimgr.UnInit();
341}
342
344{
345 if( m_notebook->GetPageCount() == 1 )
346 m_notebook->SetTabCtrlHeight( 0 );
347 else
348 m_notebook->SetTabCtrlHeight( -1 );
349}
350
351
353{
355}
356
357
359{
360 wxAuiNotebook* notebook = (wxAuiNotebook*) evt.GetEventObject();
361 wxWindow* page = notebook->GetPage( evt.GetSelection() );
362
363 if( PANEL_NOTEBOOK_BASE* panel = dynamic_cast<PANEL_NOTEBOOK_BASE*>( page ) )
364 {
365 if( panel->GetClosable() )
366 {
367 if( !panel->GetCanClose() )
368 evt.Veto();
369
370 CallAfter(
371 [this]()
372 {
374 } );
375 }
376 else
377 {
378 evt.Veto();
379 }
380 }
381}
382
383
384wxStatusBar* KICAD_MANAGER_FRAME::OnCreateStatusBar( int number, long style, wxWindowID id,
385 const wxString& name )
386{
387 KISTATUSBAR* sb = new KISTATUSBAR( number, this, id,
391
392 size_t sbFieldCnt = static_cast<size_t>( sb->GetFieldsCount() );
393 std::vector<int> sbFieldSizes( sbFieldCnt );
394
395 for( size_t i = 0; i < sbFieldCnt; i++ )
396 sbFieldSizes[i] = sb->GetStatusWidth( static_cast<int>( i ) );
397
398 // Field 0 (the project path) is the only stretchable field so it uses all the leftover width
399 // before ellipsizing. Field 1 gets a fixed width sized to its watcher text; longer content
400 // (archive progress) is ellipsized rather than allowed to steal the path's width.
401 if( sbFieldCnt > 0 )
402 sbFieldSizes[0] = -1;
403
404 if( sbFieldCnt > 1 )
405 {
406 int margin = KIUI::GetTextSize( wxT( "XX" ), sb ).x;
407 int watcherWidth = std::max( KIUI::GetTextSize( _( "Local path: monitoring folder changes" ), sb ).x,
408 KIUI::GetTextSize( _( "Network path: not monitoring folder changes" ), sb ).x );
409
410 sbFieldSizes[1] = watcherWidth + margin;
411 }
412
413 sb->SetStatusWidths( sbFieldCnt, sbFieldSizes.data() );
414
415 return sb;
416}
417
418
420{
421 // creates the PLUGIN_CONTENT_MANAGER, if not exists
422 if( m_pcm )
423 return;
424
425 m_pcm = std::make_shared<PLUGIN_CONTENT_MANAGER>(
426 [this]( int aUpdateCount )
427 {
428 if( Pgm().m_Quitting )
429 return;
430
431 m_pcmUpdateCount = aUpdateCount;
432
433 if( aUpdateCount > 0 )
434 {
436 wxS( "pcm" ),
437 _( "PCM Updates Available" ),
438 wxString::Format( _( "%d package update(s) available" ), aUpdateCount ),
439 wxT( "" ) );
440 }
441 else
442 {
443 Pgm().GetNotificationsManager().Remove( wxS( "pcm" ) );
444 }
445
446 CallAfter(
447 [this]()
448 {
450 } );
451 });
452
453 m_pcm->SetRepositoryList( kicadSettings()->m_PcmRepositories );
454}
455
456
458{
459 // Create the manager
461 m_toolManager->SetEnvironment( nullptr, nullptr, nullptr, config(), this );
463
465
466 // Attach the events to the tool dispatcher
468 Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
469
470 // Register tools
471 m_toolManager->RegisterTool( new COMMON_CONTROL );
472 m_toolManager->RegisterTool( new KICAD_MANAGER_CONTROL );
473 m_toolManager->InitTools();
474}
475
476
478{
480
481 ACTION_MANAGER* manager = m_toolManager->GetActionManager();
482
483 wxASSERT( manager );
484
485 auto activeProject =
486 [this] ( const SELECTION& )
487 {
488 return m_active_project;
489 };
490
491#define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
492
493 ACTION_CONDITIONS activeProjectCond;
494 activeProjectCond.Enable( activeProject );
495
496 manager->SetConditions( ACTIONS::saveAs, activeProjectCond );
497 manager->SetConditions( KICAD_MANAGER_ACTIONS::closeProject, activeProjectCond );
498 manager->SetConditions( KICAD_MANAGER_ACTIONS::archiveProject, activeProjectCond );
499 manager->SetConditions( KICAD_MANAGER_ACTIONS::newJobsetFile, activeProjectCond );
500 manager->SetConditions( KICAD_MANAGER_ACTIONS::openJobsetFile, activeProjectCond );
501
502 auto historyCond =
503 [this]( const SELECTION& )
504 {
505 return HistoryPanelShown();
506 };
507
509
510 // These are just here for text boxes, search boxes, etc. in places such as the standard
511 // file dialogs.
515
516#undef ENABLE
517}
518
519
521{
522 return m_projectTreePane;
523}
524
525
527{
529 wxASSERT( ret );
530 return ret;
531}
532
533
535{
536 KICAD_SETTINGS* ret = dynamic_cast<KICAD_SETTINGS*>( config() );
537 wxASSERT( ret );
538 return ret;
539}
540
541
543{
544 CallAfter(
545 [&]()
546 {
547 KIFACE *schface = Kiway().KiFACE( KIWAY::FACE_SCH );
548 schface->PreloadLibraries( &Kiway() );
549
550 KIFACE *pcbface = Kiway().KiFACE( KIWAY::FACE_PCB );
551 pcbface->PreloadLibraries( &Kiway() );
552
554 } );
555}
556
557
559{
560 return GetProjectFileName();
561}
562
563
565{
567 : wxString( wxEmptyString );
568}
569
570
572{
573 wxFileName fn( GetProjectFileName() );
574
576 return fn.GetFullPath();
577}
578
579
581{
582 wxFileName fn( GetProjectFileName() );
583
585 return fn.GetFullPath();
586}
587
588
590{
591 wxFileName fn( GetProjectFileName() );
592
593 fn.SetExt( FILEEXT::PcbFileExtension );
594 return fn.GetFullPath();
595}
596
597
599{
600 wxFileName fn( GetProjectFileName() );
601
603 return fn.GetFullPath();
604}
605
606
608{
609 m_projectTreePane->ReCreateTreePrj();
610}
611
612
617
618
620{
621 return PgmTop().GetHelpFileName();
622}
623
624
625void KICAD_MANAGER_FRAME::OnSize( wxSizeEvent& event )
626{
627 if( m_auimgr.GetManagedWindow() )
628 m_auimgr.Update();
629
630 event.Skip();
631}
632
633
635{
636 // All fileNames are now in m_AcceptedFiles vector.
637 // Check if contains a project file name and load project.
638 // If not, open files in dedicated app.
639 for( const wxFileName& fileName : m_AcceptedFiles )
640 {
641 wxString ext = fileName.GetExt();
642
644 {
645 wxString fn = fileName.GetFullPath();
646 m_toolManager->RunAction<wxString*>( *m_acceptedExts.at( fileName.GetExt() ), &fn );
647
648 return;
649 }
650 }
651
652 // Then stock gerber files in gerberFiles and run action for other files.
653 wxString gerberFiles;
654
655 // Gerbview editor should be able to open Gerber and drill files
656 for( const wxFileName& fileName : m_AcceptedFiles )
657 {
658 wxString ext = fileName.GetExt();
659
663 {
664 gerberFiles += wxT( '\"' );
665 gerberFiles += fileName.GetFullPath() + wxT( '\"' );
666 gerberFiles = gerberFiles.Pad( 1 );
667 }
668 else
669 {
670 wxString fn = fileName.GetFullPath();
671 m_toolManager->RunAction<wxString*>( *m_acceptedExts.at( fileName.GetExt() ), &fn );
672 }
673 }
674
675 // Execute Gerbviewer
676 if( !gerberFiles.IsEmpty() )
677 {
678 wxString fullEditorName = FindKicadFile( GERBVIEW_EXE );
679
680 if( wxFileExists( fullEditorName ) )
681 {
682 wxString command = fullEditorName + " " + gerberFiles;
683 m_toolManager->RunAction<wxString*>( *m_acceptedExts.at( FILEEXT::GerberFileExtension ), &command );
684 }
685 }
686}
687
688
689bool KICAD_MANAGER_FRAME::canCloseWindow( wxCloseEvent& aEvent )
690{
691 KICAD_SETTINGS* settings = kicadSettings();
693
694 for( size_t i = 0; i < m_notebook->GetPageCount(); i++ )
695 {
696 wxWindow* page = m_notebook->GetPage( i );
697
698 if( PANEL_NOTEBOOK_BASE* panel = dynamic_cast<PANEL_NOTEBOOK_BASE*>( page ) )
699 {
700 if( !panel->GetCanClose() )
701 return false;
702 }
703 }
704
705 // CloseProject will recursively ask all the open editors if they need to save changes.
706 // If any of them cancel then we need to cancel closing the KICAD_MANAGER_FRAME.
707 if( CloseProject( true ) )
708 {
709 // Don't propagate event to frames which have already been closed
710 aEvent.StopPropagation();
711
712 return true;
713 }
714 else
715 {
716 if( aEvent.CanVeto() )
717 aEvent.Veto();
718
719 return false;
720 }
721}
722
723
725{
726#ifdef _WINDOWS_
727 // For some obscure reason, on Windows, when killing Kicad from the Windows task manager
728 // if a editor frame (schematic, library, board editor or fp editor) is open and has
729 // some edition to save, OnCloseWindow is run twice *at the same time*, creating race
730 // conditions between OnCloseWindow() code.
731 // Therefore I added (JPC) a ugly hack to discard the second call (unwanted) during
732 // execution of the first call (only one call is right).
733 // Note also if there is no change made in editors, this behavior does not happen.
734 static std::atomic<unsigned int> lock_close_event( 0 );
735
736 if( ++lock_close_event > 1 ) // Skip extra calls
737 {
738 return;
739 }
740#endif
741
742 m_projectTreePane->Show( false );
743 Pgm().m_Quitting = true;
744
745 Destroy();
746
747#ifdef _WINDOWS_
748 lock_close_event = 0; // Reenable event management
749#endif
750}
751
752
754{
756
757 if( !aIsExplicitUserSave && !cfg.ShouldAutoSave() )
758 return;
759
760 cfg.m_OpenJobSets.clear();
761
762 for( size_t i = 0; i < m_notebook->GetPageCount(); i++ )
763 {
764 if( PANEL_JOBSET* jobset = dynamic_cast<PANEL_JOBSET*>( m_notebook->GetPage( i ) ) )
765 {
766 wxFileName jobsetFn( jobset->GetFilePath() );
767 jobsetFn.MakeRelativeTo( Prj().GetProjectPath() );
768 cfg.m_OpenJobSets.emplace_back( jobsetFn.GetFullPath() );
769 }
770 }
771
772 cfg.SaveToFile( Prj().GetProjectPath() );
773}
774
775
776void KICAD_MANAGER_FRAME::OnExit( wxCommandEvent& event )
777{
778 Close( true );
779}
780
781
783{
784 if( !Kiway().PlayersClose( false ) )
785 return false;
786
787 // Abort any in-progress background load, since the threads depend on the project not changing
788 KIFACE *schface = Kiway().KiFACE( KIWAY::FACE_SCH );
789 schface->CancelPreload();
790
791 KIFACE *pcbface = Kiway().KiFACE( KIWAY::FACE_PCB );
792 pcbface->CancelPreload();
793
794 // Save the project file for the currently loaded project.
795 if( m_active_project )
796 {
798
799 if( Prj().GetLocalSettings().ShouldAutoSave() && Prj().GetProjectFile().ShouldAutoSave() )
800 {
802
803 if( aSave )
804 mgr.SaveProject();
805 }
806
807 // Ensure the Last_Save tag is at HEAD before closing. This handles the case where
808 // autosave commits were made after the last explicit save - without this, the next
809 // project load would offer to restore the autosave state, which is incorrect after
810 // a clean close.
811 wxString projPath = Prj().GetProjectPath();
812
813 // Wait for any in-flight autosave so the HEAD check below isn't racing it.
815
816 if( Pgm().GetCommonSettings()->AutosaveUsesLocalHistory()
817 && !projPath.IsEmpty() && Kiway().LocalHistory().HistoryExists( projPath ) )
818 {
819 if( Kiway().LocalHistory().HeadNewerThanLastSave( projPath ) )
820 {
821 // Tag unconditionally: even on no-op snapshots Last_Save must anchor at HEAD.
822 Kiway().LocalHistory().CommitFullProjectSnapshot( projPath, wxS( "Close" ) );
823 Kiway().LocalHistory().TagSave( projPath, wxS( "project" ) );
824 }
825 }
826
827 // The editors clean up autosaves for sheets actually dirtied in their session.
828 // Anything still on disk here was deferred by the user in the recovery dialog
829 // and must survive so the dialog can offer it again on the next open.
830
831 m_active_project = false;
832 // Enforce local history size limit (if enabled) once all pending saves/backups are done.
833 if( Pgm().GetCommonSettings()
834 && Pgm().GetCommonSettings()->AutosaveUsesLocalHistory() )
835 {
836 unsigned long long int limit = Pgm().GetCommonSettings()->m_Backup.limit_total_size;
837
838 if( limit > 0 && Kiway().LocalHistory().IsCompacting() )
839 {
840 Kiway().LocalHistory().EnforceSizeLimitInBackground( Prj().GetProjectPath(), (size_t) limit );
841 }
842 else if( limit > 0 )
843 {
844 WX_PROGRESS_REPORTER reporter( this, _( "Local History" ), 3, PR_NO_ABORT );
845 Kiway().LocalHistory().EnforceSizeLimit( Prj().GetProjectPath(), (size_t) limit, &reporter );
846 }
847 }
848
849 // Unregister the project saver before unloading the project to prevent
850 // dangling references
852
853 mgr.UnloadProject( &Prj() );
854 }
855
856 SetStatusText( "" );
857
858 // Traverse pages in reverse order so deleting them doesn't mess up our iterator.
859 for( int i = (int) m_notebook->GetPageCount() - 1; i >= 0; i-- )
860 {
861 wxWindow* page = m_notebook->GetPage( i );
862
863 if( PANEL_NOTEBOOK_BASE* panel = dynamic_cast<PANEL_NOTEBOOK_BASE*>( page ) )
864 {
865 if( panel->GetProjectTied() )
866 m_notebook->DeletePage( i );
867 }
868 }
869
870 m_projectTreePane->EmptyTreePrj();
872
873 return true;
874}
875
876
877void KICAD_MANAGER_FRAME::OpenJobsFile( const wxFileName& aFileName, bool aCreate, bool aResaveProjectPreferences )
878{
879 for( size_t i = 0; i < m_notebook->GetPageCount(); i++ )
880 {
881 if( PANEL_JOBSET* panel = dynamic_cast<PANEL_JOBSET*>( m_notebook->GetPage( i ) ) )
882 {
883 if( aFileName.GetFullPath() == panel->GetFilePath() )
884 {
885 m_notebook->SetSelection( i );
886 return;
887 }
888 }
889 }
890
891 try
892 {
893 std::unique_ptr<JOBSET> jobsFile = std::make_unique<JOBSET>( aFileName.GetFullPath().ToStdString() );
894
895 jobsFile->LoadFromFile();
896
897 if( aCreate && !aFileName.FileExists() )
898 {
899 JOBSET_DESTINATION* dest = jobsFile->AddNewDestination( JOBSET_DESTINATION_T::FOLDER );
900 dest->m_outputHandler->SetOutputPath( aFileName.GetName() );
901 jobsFile->SaveToFile( wxEmptyString, true );
902 }
903
904 PANEL_JOBSET* jobPanel = new PANEL_JOBSET( m_notebook, this, std::move( jobsFile ) );
905 jobPanel->SetProjectTied( true );
906 jobPanel->SetClosable( true );
907 m_notebook->AddPage( jobPanel, aFileName.GetFullName(), true );
909
910 if( aResaveProjectPreferences )
912 }
913 catch( ... )
914 {
915 DisplayErrorMessage( this, _( "Error opening jobs file" ) );
916 }
917}
918
919
920bool KICAD_MANAGER_FRAME::LoadProject( const wxFileName& aProjectFileName )
921{
922 // The project file should be valid by the time we get here or something has gone wrong.
923 if( !aProjectFileName.Exists() )
924 return false;
925
926 wxString fullPath = aProjectFileName.GetFullPath();
927
928 // Inspect only; SETTINGS_MANAGER::LoadProject() takes the real lock
929 LOCKFILE lockFile = LOCKFILE::Inspect( fullPath );
930
931 bool lockOverrideGranted = false;
932
933 if( !lockFile.Valid() )
934 {
935 wxString msg;
936 msg.Printf( _( "Project '%s' is already open by '%s' at '%s'." ),
937 fullPath,
938 lockFile.GetUsername(),
939 lockFile.GetHostname() );
940
941 if( !AskOverrideLock( this, msg ) )
942 return false; // User clicked Cancel - abort project loading entirely
943
944 // Clear the lock so the load below can take it
945 LOCKFILE overridden( fullPath );
946 overridden.OverrideLock();
947
948 lockOverrideGranted = true;
949 }
950
951 // Any open KIFACE's must be closed if they are not part of the new project.
952 // (We never want a KIWAY_PLAYER open on a KIWAY that isn't in the same project.)
953 // User is prompted here to close those KIWAY_PLAYERs:
954 if( !CloseProject( true ) )
955 return false;
956
957 m_active_project = true;
958
959 // NB: when loading a legacy project SETTINGS_MANAGER::LoadProject() will convert it to
960 // current extension. Be very careful with aProjectFileName vs. Prj().GetProjectPath()
961 // from here on out.
962
963 Pgm().GetSettingsManager().LoadProject( fullPath );
964
965 // Propagate lock override decision to the loaded project
966 if( lockOverrideGranted )
967 Prj().SetLockOverrideGranted( true );
968
969 LoadWindowState( aProjectFileName.GetFullName() );
970
971 if( aProjectFileName.IsDirWritable() )
972 SetMruPath( Prj().GetProjectPath() );
973
974 if( Pgm().GetCommonSettings()->AutosaveUsesLocalHistory()
975 && Kiway().LocalHistory().HeadNewerThanLastSave( Prj().GetProjectPath() ) )
976 {
977 wxString head = Kiway().LocalHistory().GetHeadHash( Prj().GetProjectPath() );
978
979 KICAD_MESSAGE_DIALOG dlg( this, _( "KiCad found unsaved changes from your last session that are newer than "
980 "the saved project files." ),
981 _( "Recover Unsaved Changes" ), wxYES_NO | wxICON_QUESTION );
982
983 dlg.SetExtendedMessage( _( "This can happen if your previous session ended unexpectedly.\n\n"
984 "Choose 'Restore' to recover those changes, or 'Discard' to keep the "
985 "currently saved files." ) );
986
987 dlg.SetYesNoLabels( _( "Restore" ), _( "Discard" ) );
988
989 if( dlg.ShowModal() == wxID_YES )
990 {
991 // The dialog above is the confirmation, skip RestoreCommit's own prompt.
992 Kiway().LocalHistory().RestoreCommit( Prj().GetProjectPath(), head, this, false );
993 }
994 else
995 {
996 // User declined; commit on-disk state and tag unconditionally so Last_Save anchors
997 // at HEAD even if no new commit was needed.
998 Kiway().LocalHistory().CommitFullProjectSnapshot( Prj().GetProjectPath(), wxS( "Declined restore" ) );
999 Kiway().LocalHistory().TagSave( Prj().GetProjectPath(), wxS( "project" ) );
1000 }
1001 }
1002
1003 // Save history & window state to disk now. Don't wait around for a crash.
1004 KICAD_SETTINGS* settings = kicadSettings();
1005 SaveSettings( settings );
1006 settings->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( settings ) );
1007
1008 m_projectTreePane->ReCreateTreePrj();
1009 m_historyPane->RefreshHistory( Prj().GetProjectPath() );
1010
1011 for( const wxString& jobset : Prj().GetLocalSettings().m_OpenJobSets )
1012 {
1013 wxFileName jobsetFn( jobset );
1014 jobsetFn.MakeAbsolute( Prj().GetProjectPath() );
1015
1016 if( jobsetFn.Exists() )
1017 OpenJobsFile( jobsetFn.GetFullPath(), false, false );
1018 }
1019
1020 // Always start with the apps page
1021 m_notebook->SetSelection( 0 );
1022
1023 // Rebuild the list of watched paths.
1024 // however this is possible only when the main loop event handler is running,
1025 // so we use it to run the rebuild function.
1026 wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED, ID_INIT_WATCHED_PATHS );
1027
1028 wxPostEvent( this, cmd );
1029
1030 PrintPrjInfo();
1031
1032 KIPLATFORM::APP::RegisterApplicationRestart( aProjectFileName.GetFullPath() );
1033 m_openSavedWindows = true;
1034
1035 KIPLATFORM::ENV::AddToRecentDocs( aProjectFileName.GetFullPath() );
1036
1037 // Now that we have a new project, trigger a library preload, which will load in any
1038 // project-specific symbol and footprint libraries into the manager
1040 return true;
1041}
1042
1043
1044void KICAD_MANAGER_FRAME::CreateNewProject( const wxFileName& aProjectFileName, bool aCreateStubFiles )
1045{
1046 wxCHECK_RET( aProjectFileName.DirExists() && aProjectFileName.IsDirWritable(),
1047 "Project folder must exist and be writable to create a new project." );
1048
1049 // If the project is legacy, convert it
1050 if( !aProjectFileName.FileExists() )
1051 {
1052 wxFileName legacyPro( aProjectFileName );
1053 legacyPro.SetExt( FILEEXT::LegacyProjectFileExtension );
1054
1055 if( legacyPro.FileExists() )
1056 {
1057 GetSettingsManager()->LoadProject( legacyPro.GetFullPath() );
1059
1060 wxRemoveFile( legacyPro.GetFullPath() );
1061 }
1062 else
1063 {
1064 // Copy template project file from template folder.
1065 wxString srcFileName = sys_search().FindValidPath( "kicad.kicad_pro" );
1066
1067 wxFileName destFileName( aProjectFileName );
1068 destFileName.SetExt( FILEEXT::ProjectFileExtension );
1069
1070 // Create a minimal project file if the template project file could not be copied
1071 if( !wxFileName::FileExists( srcFileName )
1072 || !wxCopyFile( srcFileName, destFileName.GetFullPath() ) )
1073 {
1074 wxFFile file( destFileName.GetFullPath(), "wb" );
1075
1076 if( file.IsOpened() )
1077 file.Write( wxT( "{\n}\n") );
1078
1079 // wxFFile dtor will close the file
1080 }
1081 }
1082 }
1083
1084 // Create a "stub" for a schematic root sheet and a board if requested.
1085 // It will avoid messages from the schematic editor or the board editor to create a new file
1086 // And forces the user to create main files under the right name for the project manager
1087 if( aCreateStubFiles )
1088 {
1089 wxFileName fn( aProjectFileName.GetFullPath() );
1091
1092 // If a <project>.kicad_sch file does not exist, create a "stub" file ( minimal schematic
1093 // file ).
1094 if( !fn.FileExists() )
1095 {
1096 wxFFile file( fn.GetFullPath(), "wb" );
1097
1098 if( file.IsOpened() )
1099 {
1100 file.Write( wxString::Format( "(kicad_sch\n"
1101 "\t(version %d)\n"
1102 "\t(generator \"eeschema\")\n"
1103 "\t(generator_version \"%s\")\n"
1104 "\t(uuid %s)\n"
1105 "\t(paper \"A4\")\n"
1106 "\t(lib_symbols)\n"
1107 "\t(sheet_instances\n"
1108 "\t\t(path \"/\"\n"
1109 "\t\t\t(page \"1\")\n"
1110 "\t\t)\n"
1111 "\t)\n"
1112 "\t(embedded_fonts no)\n"
1113 ")",
1116 KIID().AsString() ) );
1117 }
1118
1119 // wxFFile dtor will close the file
1120 }
1121
1122 // If a <project>.kicad_pcb or <project>.brd file does not exist,
1123 // create a .kicad_pcb "stub" file
1124 fn.SetExt( FILEEXT::KiCadPcbFileExtension );
1125 wxFileName leg_fn( fn );
1126 leg_fn.SetExt( FILEEXT::LegacyPcbFileExtension );
1127
1128 if( !fn.FileExists() && !leg_fn.FileExists() )
1129 {
1130 wxFFile file( fn.GetFullPath(), "wb" );
1131
1132 if( file.IsOpened() )
1133 {
1134 // Create a small dummy file as a stub for pcbnew:
1135 file.Write( wxString::Format( "(kicad_pcb (version %d) (generator \"pcbnew\") (generator_version \"%s\")\n)",
1137 }
1138
1139 // wxFFile dtor will close the file
1140 }
1141 }
1142
1143 // Save history & window state to disk now. Don't wait around for a crash.
1144 KICAD_SETTINGS* settings = kicadSettings();
1145 SaveSettings( settings );
1146 settings->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( settings ) );
1147
1148 m_openSavedWindows = true;
1149}
1150
1151
1153{
1154 git_repository* repo = ( m_projectTreePane && m_projectTreePane->m_TreeProject )
1155 ? m_projectTreePane->m_TreeProject->GetGitRepo()
1156 : nullptr;
1157
1158 if( !repo )
1159 {
1160 wxMessageBox( _( "Compare Project Branches requires a project that is "
1161 "tracked by git." ),
1162 _( "Compare Branches" ),
1163 wxOK | wxICON_INFORMATION, this );
1164 return;
1165 }
1166
1167 // Seed the picker with the conventional "MR" pair: an integration branch
1168 // (main/master) as the base, the current branch as the head. Resolve the
1169 // current branch from HEAD so a checked-out feature branch lands at
1170 // index 1 (where DIALOG_GIT_MR_REVIEW selects its head ref) instead of
1171 // the literal "HEAD" string.
1172 wxString currentBranch;
1173 git_reference* head = nullptr;
1174
1175 if( git_repository_head( &head, repo ) == 0 )
1176 {
1177 const char* shorthand = git_reference_shorthand( head );
1178
1179 if( shorthand && *shorthand )
1180 currentBranch = wxString::FromUTF8( shorthand );
1181
1182 git_reference_free( head );
1183 }
1184
1185 std::vector<wxString> refs;
1186
1187 auto pushUnique = [&]( const wxString& aRef )
1188 {
1189 if( aRef.IsEmpty() )
1190 return;
1191
1192 for( const wxString& existing : refs )
1193 {
1194 if( existing == aRef )
1195 return;
1196 }
1197
1198 refs.push_back( aRef );
1199 };
1200
1201 pushUnique( wxS( "main" ) );
1202 pushUnique( wxS( "master" ) );
1203 pushUnique( currentBranch );
1204 pushUnique( wxS( "HEAD" ) );
1205
1206 DIALOG_GIT_MR_REVIEW dlg( this, repo, refs );
1207 dlg.ShowModal();
1208}
1209
1210
1212{
1213 // show all files in file dialog (in Kicad all files are editable texts):
1214 wxString wildcard = FILEEXT::AllFilesWildcard();
1215
1216 wxString default_dir = Prj().GetProjectPath();
1217
1218 wxFileDialog dlg( this, _( "Edit File in Text Editor" ), default_dir, wxEmptyString, wildcard,
1219 wxFD_OPEN );
1220
1222
1223 if( dlg.ShowModal() == wxID_CANCEL )
1224 return;
1225
1226 wxString filename = dlg.GetPath();
1227
1228 if( !dlg.GetPath().IsEmpty() && !Pgm().GetTextEditor().IsEmpty() )
1229 m_toolManager->RunAction<wxString*>( KICAD_MANAGER_ACTIONS::openTextEditor, &filename );
1230}
1231
1232
1233void KICAD_MANAGER_FRAME::OnEditAdvancedCfg( wxCommandEvent& WXUNUSED( event ) )
1234{
1235 DIALOG_EDIT_CFG dlg( this );
1236 dlg.ShowModal();
1237}
1238
1239
1241{
1242 m_projectTreePane->ReCreateTreePrj();
1243}
1244
1245
1247{
1248 // call my base class
1250
1251 // tooltips in toolbars
1253 m_launcher->CreateLaunchers();
1254
1255 // update captions
1256 int pageId = m_notebook->FindPage( m_launcher );
1257
1258 if( pageId != wxNOT_FOUND )
1259 m_notebook->SetPageText( pageId, EDITORS_CAPTION );
1260
1261 m_auimgr.GetPane( m_projectTreePane ).Caption( PROJECT_FILES_CAPTION );
1262 m_auimgr.Update();
1263
1264 m_projectTreePane->FileWatcherReset();
1265
1266 PrintPrjInfo();
1267}
1268
1269
1271{
1273
1274 if( m_pcm && ( aFlags & ENVVARS_CHANGED ) )
1275 m_pcm->ReadEnvVar();
1276
1277 COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
1278
1279 if( m_lastToolbarIconSize == 0
1281 {
1284 }
1285
1286 m_projectTreePane->ReCreateTreePrj();
1287}
1288
1289
1291{
1292 wxString file = GetProjectFileName();
1293
1294 // empty file string means no project loaded
1295 if( !Prj().IsNullProject() &&
1296 Prj().GetProjectLock() == nullptr )
1297 {
1298 LOCKFILE lockFile( file );
1299
1300 if( !lockFile.Valid() )
1301 {
1302 wxString msg;
1303 msg.Printf( _( "Project '%s' is already open by '%s' at '%s'." ),
1304 file,
1305 lockFile.GetUsername(),
1306 lockFile.GetHostname() );
1307
1308 if( AskOverrideLock( this, msg ) )
1309 {
1310 lockFile.OverrideLock();
1311 }
1312 }
1313
1314 Prj().SetReadOnly( !lockFile.Valid() || Prj().GetProjectFile().IsReadOnly() );
1315 Prj().SetProjectLock( new LOCKFILE( std::move( lockFile ) ) );
1316 }
1317
1318 wxString title;
1319
1320 if( !file.IsEmpty() )
1321 {
1322 wxFileName fn( file );
1323
1324 title = fn.GetName();
1325
1326 if( Prj().IsReadOnly() )
1327 title += wxS( " " ) + _( "[Read Only]" );
1328 }
1329 else
1330 {
1331 title = _( "[no project loaded]" );
1332 }
1333
1334 if( ADVANCED_CFG::GetCfg().m_HideVersionFromTitle )
1335 title += wxT( " \u2014 " ) + wxString( wxS( "KiCad" ) );
1336 else
1337 title += wxT( " \u2014 " ) + wxString( wxS( "KiCad " ) ) + GetMajorMinorVersion();
1338
1339 SetTitle( title );
1340
1341 // Register project file saver. Ensures project file participates in
1342 // autosave history commits without affecting dirty state.
1344 [this]( const wxString& aProjectPath, std::vector<HISTORY_FILE_DATA>& aFileData )
1345 {
1346 Prj().SaveToHistory( aProjectPath, aFileData );
1347 },
1349}
1350
1351
1353{
1355
1356 auto settings = dynamic_cast<KICAD_SETTINGS*>( aCfg );
1357
1358 wxCHECK( settings, /*void*/ );
1359
1360 m_leftWinWidth = settings->m_LeftWinWidth;
1361 m_showHistoryPanel = settings->m_ShowHistoryPanel;
1362}
1363
1364
1366{
1368
1369 KICAD_SETTINGS* settings = dynamic_cast<KICAD_SETTINGS*>( aCfg );
1370
1371 wxCHECK( settings, /*void*/ );
1372
1373 settings->m_LeftWinWidth = m_projectTreePane->GetSize().x;
1374 settings->m_ShowHistoryPanel = m_historyPane && m_auimgr.GetPane( m_historyPane ).IsShown();
1375
1376 if( !m_isClosing )
1378}
1379
1380
1382{
1383 wxString status = wxString::Format( _( "Project: %s" ), Prj().GetProjectFullName() );
1384 SetStatusText( status, 0 );
1385}
1386
1387
1392
1393
1394void KICAD_MANAGER_FRAME::OnIdle( wxIdleEvent& aEvent )
1395{
1401 if( !m_openSavedWindows )
1402 return;
1403
1404 m_openSavedWindows = false;
1405
1406 if( Pgm().GetCommonSettings()->m_Session.remember_open_files )
1407 {
1408 int previousOpenCount = std::count_if( Prj().GetLocalSettings().m_files.begin(),
1409 Prj().GetLocalSettings().m_files.end(),
1410 [&]( const PROJECT_FILE_STATE& f )
1411 {
1412 return !f.fileName.EndsWith( FILEEXT::ProjectFileExtension ) && f.open;
1413 } );
1414
1415 if( previousOpenCount > 0 )
1416 {
1417 APP_PROGRESS_DIALOG progressReporter( _( "Restoring session" ), wxEmptyString, previousOpenCount, this );
1418
1419 // We don't currently support opening more than one view per file
1420 std::set<wxString> openedFiles;
1421
1422 int i = 0;
1423
1424 for( const PROJECT_FILE_STATE& file : Prj().GetLocalSettings().m_files )
1425 {
1426 if( file.open && !openedFiles.count( file.fileName ) )
1427 {
1428 progressReporter.Update( i++, wxString::Format( _( "Restoring '%s'" ), file.fileName ) );
1429
1430 openedFiles.insert( file.fileName );
1431 wxFileName fn( file.fileName );
1432
1433 if( fn.GetExt() == FILEEXT::LegacySchematicFileExtension
1434 || fn.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1435 {
1437 }
1438 else if( fn.GetExt() == FILEEXT::LegacyPcbFileExtension
1439 || fn.GetExt() == FILEEXT::KiCadPcbFileExtension )
1440 {
1442 }
1443 }
1444
1445 wxYield();
1446 }
1447 }
1448 }
1449
1450 // clear file states regardless if we opened windows or not due to setting
1452
1453 // After restore from history, mark open editors as dirty so user is prompted to save
1455 {
1456 m_restoredFromHistory = false;
1457
1458 // Mark schematic editor as dirty if open
1459 if( KIWAY_PLAYER* schFrame = Kiway().Player( FRAME_SCH, false ) )
1460 schFrame->OnModify();
1461
1462 // Mark PCB editor as dirty if open
1463 if( KIWAY_PLAYER* pcbFrame = Kiway().Player( FRAME_PCB_EDITOR, false ) )
1464 pcbFrame->OnModify();
1465 }
1466
1467 KICAD_SETTINGS* settings = kicadSettings();
1468
1470 && settings->m_PcmUpdateCheck )
1471 {
1472 if( !m_pcm )
1473 CreatePCM();
1474
1475 m_pcm->RunBackgroundUpdate();
1476 }
1477
1478#ifdef KICAD_UPDATE_CHECK
1479 if( !m_updateManager && settings->m_KiCadUpdateCheck )
1480 {
1481 m_updateManager = std::make_unique<UPDATE_MANAGER>();
1482 m_updateManager->CheckForUpdate( this );
1483 }
1484#endif
1485
1486 // This little diddy is needed to get the window put into the Mac dock icon's context menu.
1487 Raise();
1488}
1489
1490
1492{
1493 m_pcmButton = aButton;
1494
1496}
1497
1498
1500{
1501 if( m_pcmButton )
1502 {
1503 if( m_pcmUpdateCount > 0 )
1504 {
1505 m_pcmButton->SetShowBadge( true );
1506 m_pcmButton->SetBadgeText( wxString::Format( "%d", m_pcmUpdateCount ) );
1507 }
1508 else
1509 {
1510 m_pcmButton->SetShowBadge( false );
1511 }
1512
1513 m_pcmButton->Refresh();
1514 }
1515}
1516
1517
1519{
1520 // No idea why, but the same mechanism used in EDA_DRAW_FRAME doesn't work here
1521 // the only thing that seems to work is to blow it all up and start from scratch.
1522 m_auimgr.DetachPane( m_tbLeft );
1523 delete m_tbLeft;
1524 m_tbLeft = nullptr;
1526 m_auimgr.AddPane( m_tbLeft, EDA_PANE().HToolbar().Name( "TopMainToolbar" ).Left().Layer( 2 ) );
1527
1528 m_auimgr.Update();
1529}
1530
1531
1533{
1534 wxAuiPaneInfo& pane = m_auimgr.GetPane( m_historyPane );
1535 bool show = !pane.IsShown();
1536 pane.Show( show );
1537
1538 if( show )
1539 m_historyPane->RefreshHistory( Prj().GetProjectPath() );
1540
1541 m_auimgr.Update();
1542}
1543
1544
1546{
1547 if( !Kiway().PlayersClose( true ) )
1548 return;
1549
1550 if( Kiway().LocalHistory().RestoreCommit( Prj().GetProjectPath(), aHash, this ) )
1551 {
1552 m_restoredFromHistory = true; // Mark editors dirty when they reopen
1553 }
1554
1555 m_projectTreePane->ReCreateTreePrj();
1556 m_openSavedWindows = true;
1557 m_historyPane->RefreshHistory( Prj().GetProjectPath() );
1558}
1559
1560
1562{
1563 return m_historyPane && m_auimgr.GetPane( m_historyPane ).IsShown();
1564}
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 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.
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 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
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 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:207
@ 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:459
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:546
void PreloadDesignBlockLibraries(KIWAY *aKiway)
Starts a background job to preload the global and project design block libraries.
Definition pgm_base.cpp:892
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.
Definition pgm_base.cpp:993
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:973
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:461
virtual void SetReadOnly(bool aReadOnly=true)
Definition project.h:161
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:177
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:183
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:315
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:467
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:69
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:67
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:45
@ 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:46
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
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:77
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:533
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:78
#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:136
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