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