KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kicad_manager_control.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) 2019 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
22#include <common.h>
23#include <env_vars.h>
24#include <executable_names.h>
25#include <pgm_base.h>
26#include <pgm_kicad.h>
27#include <policy_keys.h>
28#include <kiway.h>
29#include <kicad_manager_frame.h>
30#include <kiplatform/policy.h>
31#include <kiplatform/secrets.h>
32#include <kiplatform/ui.h>
33#include <confirm.h>
34#include <kidialog.h>
40#include <tool/selection.h>
41#include <tool/tool_event.h>
42#include <tool/tool_manager.h>
43#include <tool/common_control.h>
50#include <gestfich.h>
51#include <paths.h>
52#include <wx/dir.h>
53#include <wx/filedlg.h>
54#include "dialog_pcm.h"
56#include <project_tree_pane.h>
57#include <project_tree.h>
59#include <launch_ext.h>
60
62
64 TOOL_INTERACTIVE( "kicad.Control" ),
65 m_frame( nullptr ),
66 m_inShowPlayer( false )
67{
68}
69
70
75
76
77wxFileName KICAD_MANAGER_CONTROL::newProjectDirectory( wxString* aFileName, bool isRepo )
78{
79 wxString default_filename = aFileName ? *aFileName : wxString();
80
81 wxString default_dir = m_frame->GetMruPath();
82 wxFileDialog dlg( m_frame, _( "Create New Project" ), default_dir, default_filename,
83 ( isRepo ? wxString( "" ) : FILEEXT::ProjectFileWildcard() ),
84 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
85
86 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
87
88 // Add a "Create a new directory" checkbox
89 FILEDLG_NEW_PROJECT newProjectHook;
90 dlg.SetCustomizeHook( newProjectHook );
91
93
94 if( dlg.ShowModal() == wxID_CANCEL )
95 return wxFileName();
96
97 wxFileName pro( dlg.GetPath() );
98
99 // wxFileName automatically extracts an extension. But if it isn't
100 // a .pro extension, we should keep it as part of the filename
101 if( !pro.GetExt().IsEmpty() && pro.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
102 pro.SetName( pro.GetName() + wxT( "." ) + pro.GetExt() );
103
104 pro.SetExt( FILEEXT::ProjectFileExtension ); // enforce extension
105
106 if( !pro.IsAbsolute() )
107 pro.MakeAbsolute();
108
109 // Append a new directory with the same name of the project file.
110 bool createNewDir = false;
111
112 createNewDir = newProjectHook.GetCreateNewDir();
113
114 if( createNewDir )
115 pro.AppendDir( pro.GetName() );
116
117 // Check if the project directory is empty if it already exists.
118 wxDir directory( pro.GetPath() );
119
120 if( !pro.DirExists() )
121 {
122 if( !pro.Mkdir() )
123 {
124 wxString msg;
125 msg.Printf( _( "Folder '%s' could not be created.\n\n"
126 "Make sure you have write permissions and try again." ),
127 pro.GetPath() );
129 return wxFileName();
130 }
131 }
132 else if( directory.HasFiles() )
133 {
134 wxString msg = _( "The selected folder is not empty. It is recommended that you "
135 "create projects in their own empty folder.\n\n"
136 "Do you want to continue?" );
137
138 if( !IsOK( m_frame, msg ) )
139 return wxFileName();
140 }
141
142 return pro;
143}
144
145
147{
148 // The built-in "default" template lives in the stable default user templates path so that it
149 // is always available regardless of how KICAD_USER_TEMPLATE_DIR is configured. Seeding it
150 // into KICAD_USER_TEMPLATE_DIR would hide the default whenever the user points that variable
151 // at a custom location of their own. See https://gitlab.com/kicad/code/kicad/-/issues/24343
152 wxFileName defaultTemplate = EnsureDefaultProjectTemplate( PATHS::GetUserTemplatesPath() );
153
154 KICAD_SETTINGS* settings = GetAppSettings<KICAD_SETTINGS>( "kicad" );
155
156 wxString userTemplatesPath;
157 wxString systemTemplatesPath;
158
159 auto resolveTemplateDir = []( const wxString& aValue ) -> wxString
160 {
161 wxString resolved = ExpandEnvVarSubstitutions( aValue, nullptr );
162
163 // Skip values with unresolved references so we don't seed the selector with a
164 // bogus path that doesn't exist on disk.
165 if( resolved.Contains( wxT( "${" ) ) || resolved.Contains( wxT( "$(" ) ) )
166 return wxEmptyString;
167
168 wxFileName templatePath;
169 templatePath.AssignDir( resolved );
170 templatePath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
171 return templatePath.GetFullPath();
172 };
173
174 ENV_VAR_MAP_CITER itUser = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
175
176 if( itUser != Pgm().GetLocalEnvVariables().end() && itUser->second.GetValue() != wxEmptyString )
177 userTemplatesPath = resolveTemplateDir( itUser->second.GetValue() );
178
179 std::optional<wxString> v = ENV_VAR::GetVersionedEnvVarValue( Pgm().GetLocalEnvVariables(),
180 wxT( "TEMPLATE_DIR" ) );
181
182 if( v && !v->IsEmpty() )
183 systemTemplatesPath = resolveTemplateDir( *v );
184
185 // Point the selector at the seeded "default" template directory itself (not the whole user
186 // templates root) so that only the built-in default is offered as a built-in. Scanning the
187 // root would mislabel the user's own templates there as built-ins and disable editing them.
188 wxString defaultTemplatesPath;
189
190 if( defaultTemplate.IsOk() )
191 defaultTemplatesPath = resolveTemplateDir( defaultTemplate.GetPath() );
192
193 // The selector scans a directory containing a "meta" subdir as a single template, otherwise
194 // it iterates the immediate subdirectories. The default template's parent directory is the
195 // template root, so if KICAD_USER_TEMPLATE_DIR or the system template dir already point at
196 // that root the default is scanned there; skip the dedicated default scan to avoid duplicates.
197 if( !defaultTemplatesPath.IsEmpty() )
198 {
199 wxFileName defaultRootFn = defaultTemplate;
200 defaultRootFn.RemoveLastDir();
201 wxString defaultRoot = resolveTemplateDir( defaultRootFn.GetPath() );
202
203 if( defaultRoot == userTemplatesPath || defaultRoot == systemTemplatesPath )
204 defaultTemplatesPath = wxEmptyString;
205 }
206
207 // If we have no template source at all and could not seed the default, fall back to creating
208 // an empty project directory directly.
209 if( !defaultTemplate.IsOk() && userTemplatesPath.IsEmpty() && systemTemplatesPath.IsEmpty() )
210 {
211 wxFileName pro = newProjectDirectory();
212
213 if( !pro.IsOk() )
214 return -1;
215
216 m_frame->CreateNewProject( pro );
217 m_frame->LoadProject( pro );
218
219 return 0;
220 }
221
222 // Use RunMainStack to show the dialog on the main stack instead of the coroutine stack.
223 // This is necessary because the template selector uses a WebView which triggers WebKit's
224 // JavaScript VM initialization. WebKit's stack validation fails on coroutine stacks.
225 int result = wxID_CANCEL;
226 wxString selectedTemplatePath;
227 wxPoint templateWindowPos;
228 wxSize templateWindowSize;
229 wxString projectToEdit;
230 wxString browsedTemplatesPath;
231
233 [&]()
234 {
236 settings->m_TemplateWindowSize, userTemplatesPath,
237 systemTemplatesPath, defaultTemplatesPath,
238 settings->m_RecentTemplates,
239 settings->m_BrowsedTemplatesPath );
240
241 result = ps.ShowModal();
242 templateWindowPos = ps.GetPosition();
243 templateWindowSize = ps.GetSize();
244 projectToEdit = ps.GetProjectToEdit();
245 browsedTemplatesPath = ps.GetBrowsedTemplatesPath();
246
248
249 if( templ )
250 {
251 wxFileName htmlFile = templ->GetHtmlFile();
252 htmlFile.RemoveLastDir();
253 selectedTemplatePath = htmlFile.GetPath();
254 }
255 } );
256
257 settings->m_TemplateWindowPos = templateWindowPos;
258 settings->m_TemplateWindowSize = templateWindowSize;
259 settings->m_BrowsedTemplatesPath = browsedTemplatesPath;
260
261 // Check if user wants to edit a template instead of creating new project
262 if( result == wxID_APPLY )
263 {
264 if( !projectToEdit.IsEmpty() && wxFileExists( projectToEdit ) )
265 {
266 m_frame->LoadProject( wxFileName( projectToEdit ) );
267 return 0;
268 }
269 }
270
271 if( result != wxID_OK )
272 return -1;
273
274 if( selectedTemplatePath.IsEmpty() )
275 {
276 wxMessageBox( _( "No project template was selected. Cannot generate new project." ), _( "Error" ),
277 wxOK | wxICON_ERROR, m_frame );
278
279 return -1;
280 }
281
282 // Recreate the template object from the saved path
283 PROJECT_TEMPLATE selectedTemplate( selectedTemplatePath );
284
285 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
286 wxString title = _( "New Project Folder" );
287 wxFileDialog dlg( m_frame, title, default_dir, wxEmptyString, FILEEXT::ProjectFileWildcard(),
288 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
289
290 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
291
292 FILEDLG_NEW_PROJECT newProjectHook;
293 dlg.SetCustomizeHook( newProjectHook );
294
296
297 if( dlg.ShowModal() == wxID_CANCEL )
298 return -1;
299
300 wxFileName fn( dlg.GetPath() );
301
302 if( !fn.GetExt().IsEmpty() && fn.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
303 fn.SetName( fn.GetName() + wxT( "." ) + fn.GetExt() );
304
306
307 if( !fn.IsAbsolute() )
308 fn.MakeAbsolute();
309
310 bool createNewDir = false;
311 createNewDir = newProjectHook.GetCreateNewDir();
312
313 if( createNewDir )
314 fn.AppendDir( fn.GetName() );
315
316 if( !fn.DirExists() && !fn.Mkdir() )
317 {
318 DisplayErrorMessage( m_frame, wxString::Format( _( "Folder '%s' could not be created.\n\n"
319 "Make sure you have write permissions and try again." ),
320 fn.GetPath() ) );
321 return -1;
322 }
323
324 if( !fn.IsDirWritable() )
325 {
326 DisplayErrorMessage( m_frame, wxString::Format( _( "Insufficient permissions to write to folder '%s'." ),
327 fn.GetPath() ) );
328 return -1;
329 }
330
331 std::vector< wxFileName > destFiles;
332
333 if( selectedTemplate.GetDestinationFiles( fn, destFiles ) )
334 {
335 std::vector<wxFileName> overwrittenFiles;
336
337 for( const wxFileName& file : destFiles )
338 {
339 if( file.FileExists() )
340 overwrittenFiles.push_back( file );
341 }
342
343 if( !overwrittenFiles.empty() )
344 {
345 wxString extendedMsg = _( "Overwriting files:" ) + "\n";
346
347 for( const wxFileName& file : overwrittenFiles )
348 extendedMsg += "\n" + file.GetFullName();
349
350 KIDIALOG msgDlg( m_frame, _( "Similar files already exist in the destination folder." ),
351 _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
352 msgDlg.SetExtendedMessage( extendedMsg );
353 msgDlg.SetOKLabel( _( "Overwrite" ) );
354 msgDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
355
356 if( msgDlg.ShowModal() == wxID_CANCEL )
357 return -1;
358 }
359 }
360
361 wxString errorMsg;
362
363 if( !selectedTemplate.CreateProject( fn, &errorMsg ) )
364 {
365 DisplayErrorMessage( m_frame, _( "A problem occurred creating new project from template." ), errorMsg );
366 return -1;
367 }
368
369 // Update MRU list with the used template
370 wxFileName templateDir = selectedTemplate.GetHtmlFile();
371 templateDir.RemoveLastDir();
372 wxString templatePath = templateDir.GetPath();
373
374 settings->m_LastUsedTemplate = templatePath;
375
376 // Add to front of recent templates, remove duplicates, trim to 5
377 std::vector<wxString>& recentTemplates = settings->m_RecentTemplates;
378 recentTemplates.erase( std::remove( recentTemplates.begin(), recentTemplates.end(), templatePath ),
379 recentTemplates.end() );
380 recentTemplates.insert( recentTemplates.begin(), templatePath );
381
382 if( recentTemplates.size() > 5 )
383 recentTemplates.resize( 5 );
384
385 m_frame->CreateNewProject( fn.GetFullPath() );
386 m_frame->LoadProject( fn );
387 return 0;
388}
389
390
392{
393 DIALOG_GIT_REPOSITORY dlg( m_frame, nullptr );
394
395 dlg.SetTitle( _( "Clone Project from Git Repository" ) );
396
397 int ret = dlg.ShowModal();
398
399 if( ret != wxID_OK )
400 return -1;
401
402 wxString project_name = dlg.GetRepoName();
403 wxFileName pro = newProjectDirectory( &project_name, true );
404
405 if( !pro.IsOk() )
406 return -1;
407
408 PROJECT_TREE_PANE *pane = static_cast<PROJECT_TREE_PANE*>( m_frame->GetToolCanvas() );
409
410
411 GIT_CLONE_HANDLER cloneHandler( pane->m_TreeProject->GitCommon() );
412 pane->m_TreeProject->GitCommon()->SetCancelled( false );
413
414 cloneHandler.SetRemote( dlg.GetFullURL() );
415 cloneHandler.SetClonePath( pro.GetPath() );
416 cloneHandler.SetUsername( dlg.GetUsername() );
417 cloneHandler.SetPassword( dlg.GetPassword() );
418 cloneHandler.SetSSHKey( dlg.GetRepoSSHPath() );
419
420 cloneHandler.SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>( m_frame, _( "Clone Repository" ), 1,
421 PR_NO_ABORT ) );
422
423 if( !cloneHandler.PerformClone() )
424 {
425 DisplayErrorMessage( m_frame, cloneHandler.GetErrorString() );
426 return -1;
427 }
428
429 std::vector<wxString> projects = cloneHandler.GetProjectDirs();
430
431 if( projects.empty() )
432 {
433 DisplayErrorMessage( m_frame, _( "No project files were found in the repository." ) );
434 return -1;
435 }
436
437 // Currently, we pick the first project file we find in the repository.
438 // TODO: Look into spare checkout to allow the user to pick a partial repository
439 wxString dest = pro.GetPath() + wxFileName::GetPathSeparator() + projects.front();
440 m_frame->LoadProject( dest );
441
445
449 Prj().GetLocalSettings().m_GitRepoType = "https";
450 else
451 Prj().GetLocalSettings().m_GitRepoType = "local";
452
453 return 0;
454}
455
456
458{
459 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
460 wxFileDialog dlg( m_frame, _( "Create New Jobset" ), default_dir, wxEmptyString, FILEEXT::JobsetFileWildcard(),
461 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
462
464
465 if( dlg.ShowModal() == wxID_CANCEL )
466 return -1;
467
468 wxFileName jobsetFn( dlg.GetPath() );
469
470 // Check if the file already exists
471 bool fileExists = wxFileExists( jobsetFn.GetFullPath() );
472
473 if( fileExists )
474 {
475 // Remove the existing file so that a new one can be created
476 if( !wxRemoveFile( jobsetFn.GetFullPath() ) )
477 {
478 return -1;
479 }
480 }
481
482 m_frame->OpenJobsFile( jobsetFn.GetFullPath(), true );
483
484 return 0;
485}
486
487
488
489
490int KICAD_MANAGER_CONTROL::openProject( const wxString& aDefaultDir )
491{
492 wxString wildcard = FILEEXT::AllProjectFilesWildcard()
495
496 wxFileDialog dlg( m_frame, _( "Open Existing Project" ), aDefaultDir, wxEmptyString, wildcard,
497 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
498
499 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
500
502
503 if( dlg.ShowModal() == wxID_CANCEL )
504 return -1;
505
506 wxFileName pro( dlg.GetPath() );
507
508 if( !pro.IsAbsolute() )
509 pro.MakeAbsolute();
510
511 // You'd think wxFD_FILE_MUST_EXIST and the wild-cards would enforce these. Sentry
512 // indicates otherwise (at least on MSW).
513 if( !pro.Exists() || ( pro.GetExt() != FILEEXT::ProjectFileExtension
514 && pro.GetExt() != FILEEXT::LegacyProjectFileExtension ) )
515 {
516 return -1;
517 }
518
519 m_frame->LoadProject( pro );
520
521 return 0;
522}
523
524
529
530
532{
533 return openProject( m_frame->GetMruPath() );
534}
535
536
538{
539 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
540 wxFileDialog dlg( m_frame, _( "Open Jobset" ), default_dir, wxEmptyString, FILEEXT::JobsetFileWildcard(),
541 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
542
544
545 if( dlg.ShowModal() == wxID_CANCEL )
546 return -1;
547
548 wxFileName jobsetFn( dlg.GetPath() );
549
550 m_frame->OpenJobsFile( jobsetFn.GetFullPath(), true );
551
552 return 0;
553}
554
555
557{
558 m_frame->CloseProject( true );
559 return 0;
560}
561
562
564{
565 if( aEvent.Parameter<wxString*>() )
566 m_frame->LoadProject( wxFileName( *aEvent.Parameter<wxString*>() ) );
567 return 0;
568}
569
570
572{
573 wxFileName fileName = m_frame->GetProjectFileName();
574
575 fileName.SetExt( FILEEXT::ArchiveFileExtension );
576
577 wxFileDialog dlg( m_frame, _( "Archive Project Files" ), fileName.GetPath(), fileName.GetFullName(),
578 FILEEXT::ZipFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
579
581
582 if( dlg.ShowModal() == wxID_CANCEL )
583 return 0;
584
585 wxFileName zipFile = dlg.GetPath();
586
587 wxString currdirname = fileName.GetPathWithSep();
588 wxDir dir( currdirname );
589
590 if( !dir.IsOpened() ) // wxWidgets display a error message on issue.
591 return 0;
592
593 STATUSBAR_REPORTER reporter( m_frame->GetStatusBar(), 1 );
594 PROJECT_ARCHIVER archiver;
595
596 archiver.Archive( currdirname, zipFile.GetFullPath(), reporter, true, true );
597 return 0;
598}
599
600
602{
603 m_frame->UnarchiveFiles();
604 return 0;
605}
606
607
609{
610 // Open project directory in host OS's file explorer
611 LaunchExternal( Prj().GetProjectPath() );
612 return 0;
613}
614
616{
617 m_frame->RestoreLocalHistory();
618 return 0;
619}
620
621
623{
624 m_frame->ToggleLocalHistory();
625 return 0;
626}
627
628
630{
631 if( aEvent.Parameter<wxString*>() )
632 wxExecute( *aEvent.Parameter<wxString*>(), wxEXEC_ASYNC );
633
634 return 0;
635}
636
637
638
640{
641 wxString msg;
642
643 wxFileName currentProjectFile( Prj().GetProjectFullName() );
644 wxString currentProjectDirPath = currentProjectFile.GetPath();
645 wxString currentProjectName = Prj().GetProjectName();
646
647 wxString default_dir = m_frame->GetMruPath();
648
649 Prj().GetProjectFile().SaveToFile( currentProjectDirPath );
650 Prj().GetLocalSettings().SaveToFile( currentProjectDirPath );
651
652 if( default_dir == currentProjectDirPath
653 || default_dir == currentProjectDirPath + wxFileName::GetPathSeparator() )
654 {
655 // Don't start within the current project
656 wxFileName default_dir_fn( default_dir );
657 default_dir_fn.RemoveLastDir();
658 default_dir = default_dir_fn.GetPath();
659 }
660
661 wxFileDialog dlg( m_frame, _( "Save Project To" ), default_dir, wxEmptyString, wxEmptyString, wxFD_SAVE );
662
663 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
664
666
667 if( dlg.ShowModal() == wxID_CANCEL )
668 return -1;
669
670 wxFileName newProjectDir( dlg.GetPath(), wxEmptyString );
671
672 if( !newProjectDir.IsAbsolute() )
673 newProjectDir.MakeAbsolute();
674
675 if( wxDirExists( newProjectDir.GetFullPath() ) )
676 {
677 msg.Printf( _( "'%s' already exists." ), newProjectDir.GetFullPath() );
679 return -1;
680 }
681
682 if( !wxMkdir( newProjectDir.GetFullPath() ) )
683 {
684 DisplayErrorMessage( m_frame, wxString::Format( _( "Folder '%s' could not be created.\n\n"
685 "Please make sure you have sufficient permissions." ),
686 newProjectDir.GetPath() ) );
687 return -1;
688 }
689
690 if( !newProjectDir.IsDirWritable() )
691 {
692 DisplayErrorMessage( m_frame, wxString::Format( _( "Insufficient permissions to write to folder '%s'." ),
693 newProjectDir.GetFullPath() ) );
694 return -1;
695 }
696
697 const wxString& newProjectDirPath = newProjectDir.GetFullPath();
698 const wxString& newProjectName = newProjectDir.GetDirs().Last();
699 wxDir currentProjectDir( currentProjectDirPath );
700
701 PROJECT_TREE_TRAVERSER traverser( m_frame, currentProjectDirPath, currentProjectName,
702 newProjectDirPath, newProjectName );
703
704 currentProjectDir.Traverse( traverser );
705
706 if( !traverser.GetErrors().empty() )
707 DisplayErrorMessage( m_frame, traverser.GetErrors() );
708
709 if( !traverser.GetNewProjectFile().FileExists() )
710 m_frame->CreateNewProject( traverser.GetNewProjectFile() );
711
712 m_frame->LoadProject( traverser.GetNewProjectFile() );
713
714 return 0;
715}
716
717
719{
720 m_frame->RefreshProjectTree();
721 return 0;
722}
723
724
726{
727 ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
728 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
729 SELECTION dummySel;
730
731 if( conditionalMenu )
732 conditionalMenu->Evaluate( dummySel );
733
734 if( actionMenu )
735 actionMenu->UpdateAll();
736
737 return 0;
738}
739
740
742{
743 FRAME_T playerType = aEvent.Parameter<FRAME_T>();
744 KIWAY_PLAYER* player;
745
746 if( playerType == FRAME_SCH && !m_frame->IsProjectActive() )
747 {
748 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a schematic." ), wxEmptyString );
749 return -1;
750 }
751 else if( playerType == FRAME_PCB_EDITOR && !m_frame->IsProjectActive() )
752 {
753 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a pcb." ), wxEmptyString );
754 return -1;
755 }
756
757 if( m_inShowPlayer )
758 return -1;
759
761
762 try
763 {
764 player = m_frame->Kiway().Player( playerType, true );
765 }
766 catch( const IO_ERROR& err )
767 {
768 wxLogError( _( "Application failed to load:\n" ) + err.What() );
769 return -1;
770 }
771
772 if ( !player )
773 {
774 wxLogError( _( "Application cannot start." ) );
775 return -1;
776 }
777
778 if( !player->IsVisible() ) // A hidden frame might not have the document loaded.
779 {
780 wxString filepath;
781
782 if( playerType == FRAME_SCH )
783 {
784 wxFileName kicad_schematic( m_frame->SchFileName() );
785 wxFileName legacy_schematic( m_frame->SchLegacyFileName() );
786
787 if( !legacy_schematic.FileExists() || kicad_schematic.FileExists() )
788 filepath = kicad_schematic.GetFullPath();
789 else
790 filepath = legacy_schematic.GetFullPath();
791 }
792 else if( playerType == FRAME_PCB_EDITOR )
793 {
794 wxFileName kicad_board( m_frame->PcbFileName() );
795 wxFileName legacy_board( m_frame->PcbLegacyFileName() );
796
797 if( !legacy_board.FileExists() || kicad_board.FileExists() )
798 filepath = kicad_board.GetFullPath();
799 else
800 filepath = legacy_board.GetFullPath();
801 }
802
803 if( !filepath.IsEmpty() )
804 {
805 std::vector<wxString> file_list{ filepath };
806
807 if( !player->OpenProjectFiles( file_list ) )
808 {
809 player->Destroy();
810 return -1;
811 }
812 }
813
814 wxBusyCursor busy;
815 player->Show( true );
816 }
817
818 // Needed on Windows, other platforms do not use it, but it creates no issue
819 if( player->IsIconized() )
820 player->Iconize( false );
821
822 player->Raise();
823
824 // Raising the window does not set the focus on Linux. This should work on
825 // any platform.
826 if( wxWindow::FindFocus() != player )
827 player->SetFocus();
828
829 // Save window state to disk now. Don't wait around for a crash.
830 if( Pgm().GetCommonSettings()->m_Session.remember_open_files
831 && !player->GetCurrentFileName().IsEmpty()
832 && Prj().GetLocalSettings().ShouldAutoSave() )
833 {
834 wxFileName rfn( player->GetCurrentFileName() );
835 rfn.MakeRelativeTo( Prj().GetProjectPath() );
836
837 WINDOW_SETTINGS windowSettings;
838 player->SaveWindowSettings( &windowSettings );
839
840 Prj().GetLocalSettings().SaveFileState( rfn.GetFullPath(), &windowSettings, true );
841 Prj().GetLocalSettings().SaveToFile( Prj().GetProjectPath() );
842 }
843
844 return 0;
845}
846
847
849{
850 wxString execFile;
851 wxString param;
852
854 execFile = GERBVIEW_EXE;
856 execFile = BITMAPCONVERTER_EXE;
858 execFile = PCB_CALCULATOR_EXE;
860 execFile = PL_EDITOR_EXE;
862 execFile = Pgm().GetTextEditor();
864 execFile = EESCHEMA_EXE;
866 execFile = PCBNEW_EXE;
867 else
868 wxFAIL_MSG( "Execute(): unexpected request" );
869
870 if( execFile.IsEmpty() )
871 return 0;
872
873 if( aEvent.Parameter<wxString*>() )
874 param = *aEvent.Parameter<wxString*>();
875 else if( aEvent.IsAction( &KICAD_MANAGER_ACTIONS::viewGerbers ) && m_frame->IsProjectActive() )
876 param = m_frame->Prj().GetProjectPath();
877
878 COMMON_CONTROL* commonControl = m_toolMgr->GetTool<COMMON_CONTROL>();
879 return commonControl->Execute( execFile, param );
880}
881
882
884{
886 {
887 // policy disables the plugin manager
888 return 0;
889 }
890
891 // For some reason, after a click or a double click the bitmap button calling
892 // PCM keeps the focus althougt the focus was not set to this button.
893 // This hack force removing the focus from this button
894 m_frame->SetFocus();
895 wxSafeYield();
896
897 if( !m_frame->GetPcm() )
898 m_frame->CreatePCM();
899
900 DIALOG_PCM pcm( m_frame, m_frame->GetPcm() );
901 pcm.ShowModal();
902
903 const std::unordered_set<PCM_PACKAGE_TYPE>& changed = pcm.GetChangedPackageTypes();
904
905 if( changed.count( PCM_PACKAGE_TYPE::PT_PLUGIN ) || changed.count( PCM_PACKAGE_TYPE::PT_FAB ) )
906 {
907 std::string payload = "";
908 m_frame->Kiway().ExpressMail( FRAME_PCB_EDITOR, MAIL_RELOAD_PLUGINS, payload );
909 }
910
911 KICAD_SETTINGS* settings = GetAppSettings<KICAD_SETTINGS>( "kicad" );
912
913 if( changed.count( PCM_PACKAGE_TYPE::PT_LIBRARY )
914 && ( settings->m_PcmLibAutoAdd || settings->m_PcmLibAutoRemove ) )
915 {
916 KIWAY& kiway = m_frame->Kiway();
917
918 // Reset state containing global lib tables
919 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_SCH, false ) )
920 kiface->Reset();
921
922 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_PCB, false ) )
923 kiface->Reset();
924
925 // Reload lib tables
926 std::string payload = "";
927
930 kiway.ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload );
933 }
934
935 if( changed.count( PCM_PACKAGE_TYPE::PT_COLORTHEME ) )
937
938 return 0;
939}
940
941
943{
954
960
963
973
976
978}
static TOOL_ACTION zoomRedraw
Definition actions.h:128
static TOOL_ACTION saveAs
Definition actions.h:55
static TOOL_ACTION updateMenu
Definition actions.h:266
Define the structure of a menu based on ACTIONs.
Definition action_menu.h:43
void UpdateAll()
Run update handlers for the menu and its submenus.
Handle actions that are shared between different applications.
int Execute(const TOOL_EVENT &aEvent)
const wxString & GetFullURL() const
KIGIT_COMMON::GIT_CONN_TYPE GetRepoType() const
wxString GetRepoSSHPath() const
Implementing pcm main dialog.
Definition dialog_pcm.h:39
const std::unordered_set< PCM_PACKAGE_TYPE > & GetChangedPackageTypes() const
Returns types of packages that were installed/uninstalled.
Definition dialog_pcm.h:82
int ShowModal() override
wxString GetBrowsedTemplatesPath() const
Last directory chosen via the "Browse..." button so the caller can persist it.
bool GetCreateNewDir() const
Gets the selected state of the create new directory checkbox.
void SetRemote(const wxString &aRemote)
void SetClonePath(const wxString &aPath)
void SetProgressReporter(std::unique_ptr< WX_PROGRESS_REPORTER > aProgressReporter)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
static TOOL_ACTION viewDroppedGerbers
static TOOL_ACTION openDemoProject
static TOOL_ACTION unarchiveProject
static TOOL_ACTION loadProject
static TOOL_ACTION editOtherPCB
static TOOL_ACTION restoreLocalHistory
static TOOL_ACTION newProject
static TOOL_ACTION editOtherSch
static TOOL_ACTION showLocalHistory
static TOOL_ACTION editSchematic
static TOOL_ACTION openTextEditor
static TOOL_ACTION archiveProject
static TOOL_ACTION openProject
static TOOL_ACTION closeProject
static TOOL_ACTION convertImage
static TOOL_ACTION editDrawingSheet
static TOOL_ACTION openProjectDirectory
static TOOL_ACTION openJobsetFile
static TOOL_ACTION newJobsetFile
static TOOL_ACTION editFootprints
static TOOL_ACTION showPluginManager
static TOOL_ACTION showCalculator
static TOOL_ACTION viewGerbers
static TOOL_ACTION newFromRepository
static TOOL_ACTION editSymbols
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
int OpenProject(const TOOL_EVENT &aEvent)
int NewJobsetFile(const TOOL_EVENT &aEvent)
void setTransitions() override
Set up handlers for various events.
int OpenDemoProject(const TOOL_EVENT &aEvent)
int CloseProject(const TOOL_EVENT &aEvent)
int ToggleLocalHistory(const TOOL_EVENT &aEvent)
int ArchiveProject(const TOOL_EVENT &aEvent)
bool m_inShowPlayer
Re-entrancy guard.
int SaveProjectAs(const TOOL_EVENT &aEvent)
int NewProject(const TOOL_EVENT &aEvent)
int RestoreLocalHistory(const TOOL_EVENT &aEvent)
int UnarchiveProject(const TOOL_EVENT &aEvent)
int ViewDroppedViewers(const TOOL_EVENT &aEvent)
Imports a non kicad project from a sch/pcb dropped file.
int ShowPluginManager(const TOOL_EVENT &aEvent)
int UpdateMenu(const TOOL_EVENT &aEvent)
int OpenJobsetFile(const TOOL_EVENT &aEvent)
wxFileName newProjectDirectory(wxString *aFileName=nullptr, bool isRepo=false)
int NewFromRepository(const TOOL_EVENT &aEvent)
int LoadProject(const TOOL_EVENT &aEvent)
KICAD_MANAGER_FRAME * m_frame
Pointer to the currently used edit/draw frame.
int ExploreProject(const TOOL_EVENT &aEvent)
int ShowPlayer(const TOOL_EVENT &aEvent)
int Refresh(const TOOL_EVENT &aEvent)
int openProject(const wxString &aDefaultDir)
int Execute(const TOOL_EVENT &aEvent)
std::vector< wxString > m_RecentTemplates
wxSize m_TemplateWindowSize
wxString m_BrowsedTemplatesPath
wxPoint m_TemplateWindowPos
wxString m_LastUsedTemplate
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:51
int ShowModal() override
Definition kidialog.cpp:89
void SetCancelled(bool aCancel)
wxString GetErrorString()
void SetPassword(const wxString &aPassword)
Set the password.
std::vector< wxString > GetProjectDirs()
Get a list of project directories.
void SetUsername(const wxString &aUsername)
Set the username.
void SetSSHKey(const wxString &aSSHKey)
Set the SSH key.
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:348
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr, bool aFromOtherThread=false)
Send aPayload to aDestination from aSource.
Definition kiway.cpp:486
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
static wxString GetUserTemplatesPath()
Gets the user path for custom templates.
Definition paths.cpp:71
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition paths.cpp:137
static wxString GetStockDemosPath()
Gets the stock (install) demos path.
Definition paths.cpp:449
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition pgm_base.cpp:792
virtual const wxString & GetTextEditor(bool aCanShowFileChooser=true)
Return the path to the preferred text editor application.
Definition pgm_base.cpp:216
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:123
static bool Archive(const wxString &aSrcDir, const wxString &aDestFile, REPORTER &aReporter, bool aVerbose=true, bool aIncludeExtraFiles=false)
Create an archive of the project.
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Calls Store() and then writes the contents of the JSON document to a file.
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Calls Store() and then writes the contents of the JSON document to a file.
void SaveFileState(const wxString &aFileName, const WINDOW_SETTINGS *aWindowCfg, bool aOpen)
A class which provides project template functionality.
size_t GetDestinationFiles(const wxFileName &aNewProjectPath, std::vector< wxFileName > &aDestFiles)
Fetch the list of destination files to be copied when the new project is created.
wxFileName GetHtmlFile()
Get the full Html filename for the project template.
bool CreateProject(wxFileName &aNewProjectPath, wxString *aErrorMsg=nullptr)
Copies and renames all template files to create a new project.
Window to display the tree files.
PROJECT_TREE * m_TreeProject
Traverser class to duplicate/copy project or template files with proper renaming.
wxFileName GetNewProjectFile() const
KIGIT_COMMON * GitCommon() const
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:195
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition project.h:207
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:201
void ReloadColorSettings()
Re-scan the color themes directory, reloading any changes it finds.
A wrapper for reporting to a specific text location in a statusbar.
Definition reporter.h:410
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:182
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:74
Generic, UI-independent tool event.
Definition tool_event.h:167
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:484
void RunMainStack(std::function< void()> aFunc)
Call a function using the main stack.
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_INTERACTIVE(TOOL_ID aId, const std::string &aName)
Create a tool with given id & name.
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition common.cpp:776
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:245
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 _(s)
Functions related to environment variables, including help functions.
KiCad executable names.
const wxString EESCHEMA_EXE
const wxString GERBVIEW_EXE
const wxString PL_EDITOR_EXE
const wxString BITMAPCONVERTER_EXE
const wxString PCBNEW_EXE
const wxString PCB_CALCULATOR_EXE
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition frame_type.h:29
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:41
@ FRAME_SCH_VIEWER
Definition frame_type.h:32
@ FRAME_SCH
Definition frame_type.h:30
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
@ FRAME_CVPCB
Definition frame_type.h:48
static const std::string ProjectFileExtension
static const std::string LegacyProjectFileExtension
static const std::string ArchiveFileExtension
static wxString ProjectFileWildcard()
static wxString JobsetFileWildcard()
static wxString LegacyProjectFileWildcard()
static wxString AllProjectFilesWildcard()
static wxString ZipFileWildcard()
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
PROJECT & Prj()
Definition kicad.cpp:733
bool LaunchExternal(const wxString &aPath)
Launches the given file or folder in the host OS.
@ MAIL_RELOAD_PLUGINS
Definition mail_type.h:55
@ MAIL_RELOAD_LIB
Definition mail_type.h:54
KICOMMON_API std::optional< wxString > GetVersionedEnvVarValue(const std::map< wxString, ENV_VAR_ITEM > &aMap, const wxString &aBaseName)
Attempt to retrieve the value of a versioned environment variable, such as KICAD8_TEMPLATE_DIR.
Definition env_vars.cpp:103
PBOOL GetPolicyBool(const wxString &aKey)
bool StoreSecret(const wxString &aService, const wxString &aKey, const wxString &aSecret)
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:533
@ PT_COLORTHEME
Definition pcm_data.h:48
@ PT_PLUGIN
Definition pcm_data.h:44
@ PT_LIBRARY
Definition pcm_data.h:46
@ PT_FAB
Definition pcm_data.h:45
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
#define POLICY_KEY_PCM
Definition policy_keys.h:27
wxFileName EnsureDefaultProjectTemplate(const wxString &aBaseDir)
Seed the built-in "default" project template under aBaseDir, creating the directory tree and minimal ...
T * GetAppSettings(const char *aFilename)
Implement a participant in the KIWAY alchemy.
Definition kiway.h:153
Store the common settings that are saved and loaded for each window / frame.
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)
IbisParser parser & reporter
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition wx_filename.h:35
#define PR_NO_ABORT