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 along
18 * with this program. If not, see <http://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 <wx/ffile.h>
55#include "dialog_pcm.h"
57#include <project_tree_pane.h>
58#include <project_tree.h>
60#include <launch_ext.h>
61
63
65 TOOL_INTERACTIVE( "kicad.Control" ),
66 m_frame( nullptr ),
67 m_inShowPlayer( false )
68{
69}
70
71
76
77
78wxFileName KICAD_MANAGER_CONTROL::newProjectDirectory( wxString* aFileName, bool isRepo )
79{
80 wxString default_filename = aFileName ? *aFileName : wxString();
81
82 wxString default_dir = m_frame->GetMruPath();
83 wxFileDialog dlg( m_frame, _( "Create New Project" ), default_dir, default_filename,
84 ( isRepo ? wxString( "" ) : FILEEXT::ProjectFileWildcard() ),
85 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
86
87 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
88
89 // Add a "Create a new directory" checkbox
90 FILEDLG_NEW_PROJECT newProjectHook;
91 dlg.SetCustomizeHook( newProjectHook );
92
94
95 if( dlg.ShowModal() == wxID_CANCEL )
96 return wxFileName();
97
98 wxFileName pro( dlg.GetPath() );
99
100 // wxFileName automatically extracts an extension. But if it isn't
101 // a .pro extension, we should keep it as part of the filename
102 if( !pro.GetExt().IsEmpty() && pro.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
103 pro.SetName( pro.GetName() + wxT( "." ) + pro.GetExt() );
104
105 pro.SetExt( FILEEXT::ProjectFileExtension ); // enforce extension
106
107 if( !pro.IsAbsolute() )
108 pro.MakeAbsolute();
109
110 // Append a new directory with the same name of the project file.
111 bool createNewDir = false;
112
113 createNewDir = newProjectHook.GetCreateNewDir();
114
115 if( createNewDir )
116 pro.AppendDir( pro.GetName() );
117
118 // Check if the project directory is empty if it already exists.
119 wxDir directory( pro.GetPath() );
120
121 if( !pro.DirExists() )
122 {
123 if( !pro.Mkdir() )
124 {
125 wxString msg;
126 msg.Printf( _( "Folder '%s' could not be created.\n\n"
127 "Make sure you have write permissions and try again." ),
128 pro.GetPath() );
130 return wxFileName();
131 }
132 }
133 else if( directory.HasFiles() )
134 {
135 wxString msg = _( "The selected folder is not empty. It is recommended that you "
136 "create projects in their own empty folder.\n\n"
137 "Do you want to continue?" );
138
139 if( !IsOK( m_frame, msg ) )
140 return wxFileName();
141 }
142
143 return pro;
144}
145
146
148{
149 ENV_VAR_MAP_CITER it = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
150
151 if( it == Pgm().GetLocalEnvVariables().end() || it->second.GetValue() == wxEmptyString )
152 return wxFileName();
153
154 // The value may itself reference other environment variables (e.g. ${KICAD_CONFIG_HOME}).
155 // Expand them before touching the filesystem, otherwise we create directories literally
156 // named "${OTHER_VAR}".
157 wxString resolved = ExpandEnvVarSubstitutions( it->second.GetValue(), nullptr );
158
159 // If expansion left an unresolved variable reference in the path, bail out rather than
160 // mkdir a literal "${MISSING}" directory under cwd.
161 if( resolved.Contains( wxT( "${" ) ) || resolved.Contains( wxT( "$(" ) ) )
162 return wxFileName();
163
164 wxFileName templatePath;
165 templatePath.AssignDir( resolved );
166 templatePath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
167 templatePath.AppendDir( "default" );
168
169 if( !templatePath.DirExists() && !templatePath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
170 return wxFileName();
171
172 wxFileName metaDir = templatePath;
173 metaDir.AppendDir( METADIR );
174
175 if( !metaDir.DirExists() && !metaDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
176 return wxFileName();
177
178 wxFileName infoFile = metaDir;
179 infoFile.SetFullName( METAFILE_INFO_HTML );
180
181 if( !infoFile.FileExists() )
182 {
183 wxFFile info( infoFile.GetFullPath(), wxT( "w" ) );
184
185 if( !info.IsOpened() )
186 return wxFileName();
187
188 info.Write( wxT( "<html><head><title>Default</title></head><body><h3>Default KiCad project template.</h3></body></html>" ) );
189 info.Close();
190 }
191
192 wxFileName proFile = templatePath;
193 proFile.SetFullName( wxT( "default.kicad_pro" ) );
194
195 if( !proFile.FileExists() )
196 {
197 wxFFile proj( proFile.GetFullPath(), wxT( "w" ) );
198
199 if( !proj.IsOpened() )
200 return wxFileName();
201
202 proj.Write( wxT( "{}" ) );
203 proj.Close();
204 }
205
206 if( infoFile.FileExists() && proFile.FileExists() )
207 return templatePath;
208 else
209 return wxFileName();
210}
211
213{
214 wxFileName defaultTemplate = ensureDefaultProjectTemplate();
215
216 if( !defaultTemplate.IsOk() )
217 {
218 wxFileName pro = newProjectDirectory();
219
220 if( !pro.IsOk() )
221 return -1;
222
223 m_frame->CreateNewProject( pro );
224 m_frame->LoadProject( pro );
225
226 return 0;
227 }
228
229 KICAD_SETTINGS* settings = GetAppSettings<KICAD_SETTINGS>( "kicad" );
230
231 wxString userTemplatesPath;
232 wxString systemTemplatesPath;
233
234 auto resolveTemplateDir = []( const wxString& aValue ) -> wxString
235 {
236 wxString resolved = ExpandEnvVarSubstitutions( aValue, nullptr );
237
238 // Skip values with unresolved references so we don't seed the selector with a
239 // bogus path that doesn't exist on disk.
240 if( resolved.Contains( wxT( "${" ) ) || resolved.Contains( wxT( "$(" ) ) )
241 return wxEmptyString;
242
243 wxFileName templatePath;
244 templatePath.AssignDir( resolved );
245 templatePath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
246 return templatePath.GetFullPath();
247 };
248
249 ENV_VAR_MAP_CITER itUser = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
250
251 if( itUser != Pgm().GetLocalEnvVariables().end() && itUser->second.GetValue() != wxEmptyString )
252 userTemplatesPath = resolveTemplateDir( itUser->second.GetValue() );
253
254 std::optional<wxString> v = ENV_VAR::GetVersionedEnvVarValue( Pgm().GetLocalEnvVariables(),
255 wxT( "TEMPLATE_DIR" ) );
256
257 if( v && !v->IsEmpty() )
258 systemTemplatesPath = resolveTemplateDir( *v );
259
260 // Use RunMainStack to show the dialog on the main stack instead of the coroutine stack.
261 // This is necessary because the template selector uses a WebView which triggers WebKit's
262 // JavaScript VM initialization. WebKit's stack validation fails on coroutine stacks.
263 int result = wxID_CANCEL;
264 wxString selectedTemplatePath;
265 wxPoint templateWindowPos;
266 wxSize templateWindowSize;
267 wxString projectToEdit;
268
270 [&]()
271 {
273 settings->m_TemplateWindowSize, userTemplatesPath,
274 systemTemplatesPath, settings->m_RecentTemplates );
275
276 result = ps.ShowModal();
277 templateWindowPos = ps.GetPosition();
278 templateWindowSize = ps.GetSize();
279 projectToEdit = ps.GetProjectToEdit();
280
282
283 if( templ )
284 {
285 wxFileName htmlFile = templ->GetHtmlFile();
286 htmlFile.RemoveLastDir();
287 selectedTemplatePath = htmlFile.GetPath();
288 }
289 } );
290
291 settings->m_TemplateWindowPos = templateWindowPos;
292 settings->m_TemplateWindowSize = templateWindowSize;
293
294 // Check if user wants to edit a template instead of creating new project
295 if( result == wxID_APPLY )
296 {
297 if( !projectToEdit.IsEmpty() && wxFileExists( projectToEdit ) )
298 {
299 m_frame->LoadProject( wxFileName( projectToEdit ) );
300 return 0;
301 }
302 }
303
304 if( result != wxID_OK )
305 return -1;
306
307 if( selectedTemplatePath.IsEmpty() )
308 {
309 wxMessageBox( _( "No project template was selected. Cannot generate new project." ), _( "Error" ),
310 wxOK | wxICON_ERROR, m_frame );
311
312 return -1;
313 }
314
315 // Recreate the template object from the saved path
316 PROJECT_TEMPLATE selectedTemplate( selectedTemplatePath );
317
318 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
319 wxString title = _( "New Project Folder" );
320 wxFileDialog dlg( m_frame, title, default_dir, wxEmptyString, FILEEXT::ProjectFileWildcard(),
321 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
322
323 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
324
325 FILEDLG_NEW_PROJECT newProjectHook;
326 dlg.SetCustomizeHook( newProjectHook );
327
329
330 if( dlg.ShowModal() == wxID_CANCEL )
331 return -1;
332
333 wxFileName fn( dlg.GetPath() );
334
335 if( !fn.GetExt().IsEmpty() && fn.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
336 fn.SetName( fn.GetName() + wxT( "." ) + fn.GetExt() );
337
339
340 if( !fn.IsAbsolute() )
341 fn.MakeAbsolute();
342
343 bool createNewDir = false;
344 createNewDir = newProjectHook.GetCreateNewDir();
345
346 if( createNewDir )
347 fn.AppendDir( fn.GetName() );
348
349 if( !fn.DirExists() && !fn.Mkdir() )
350 {
351 DisplayErrorMessage( m_frame, wxString::Format( _( "Folder '%s' could not be created.\n\n"
352 "Make sure you have write permissions and try again." ),
353 fn.GetPath() ) );
354 return -1;
355 }
356
357 if( !fn.IsDirWritable() )
358 {
359 DisplayErrorMessage( m_frame, wxString::Format( _( "Insufficient permissions to write to folder '%s'." ),
360 fn.GetPath() ) );
361 return -1;
362 }
363
364 std::vector< wxFileName > destFiles;
365
366 if( selectedTemplate.GetDestinationFiles( fn, destFiles ) )
367 {
368 std::vector<wxFileName> overwrittenFiles;
369
370 for( const wxFileName& file : destFiles )
371 {
372 if( file.FileExists() )
373 overwrittenFiles.push_back( file );
374 }
375
376 if( !overwrittenFiles.empty() )
377 {
378 wxString extendedMsg = _( "Overwriting files:" ) + "\n";
379
380 for( const wxFileName& file : overwrittenFiles )
381 extendedMsg += "\n" + file.GetFullName();
382
383 KIDIALOG msgDlg( m_frame, _( "Similar files already exist in the destination folder." ),
384 _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
385 msgDlg.SetExtendedMessage( extendedMsg );
386 msgDlg.SetOKLabel( _( "Overwrite" ) );
387 msgDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
388
389 if( msgDlg.ShowModal() == wxID_CANCEL )
390 return -1;
391 }
392 }
393
394 wxString errorMsg;
395
396 if( !selectedTemplate.CreateProject( fn, &errorMsg ) )
397 {
398 DisplayErrorMessage( m_frame, _( "A problem occurred creating new project from template." ), errorMsg );
399 return -1;
400 }
401
402 // Update MRU list with the used template
403 wxFileName templateDir = selectedTemplate.GetHtmlFile();
404 templateDir.RemoveLastDir();
405 wxString templatePath = templateDir.GetPath();
406
407 settings->m_LastUsedTemplate = templatePath;
408
409 // Add to front of recent templates, remove duplicates, trim to 5
410 std::vector<wxString>& recentTemplates = settings->m_RecentTemplates;
411 recentTemplates.erase( std::remove( recentTemplates.begin(), recentTemplates.end(), templatePath ),
412 recentTemplates.end() );
413 recentTemplates.insert( recentTemplates.begin(), templatePath );
414
415 if( recentTemplates.size() > 5 )
416 recentTemplates.resize( 5 );
417
418 m_frame->CreateNewProject( fn.GetFullPath() );
419 m_frame->LoadProject( fn );
420 return 0;
421}
422
423
425{
426 DIALOG_GIT_REPOSITORY dlg( m_frame, nullptr );
427
428 dlg.SetTitle( _( "Clone Project from Git Repository" ) );
429
430 int ret = dlg.ShowModal();
431
432 if( ret != wxID_OK )
433 return -1;
434
435 wxString project_name = dlg.GetRepoName();
436 wxFileName pro = newProjectDirectory( &project_name, true );
437
438 if( !pro.IsOk() )
439 return -1;
440
441 PROJECT_TREE_PANE *pane = static_cast<PROJECT_TREE_PANE*>( m_frame->GetToolCanvas() );
442
443
444 GIT_CLONE_HANDLER cloneHandler( pane->m_TreeProject->GitCommon() );
445 pane->m_TreeProject->GitCommon()->SetCancelled( false );
446
447 cloneHandler.SetRemote( dlg.GetFullURL() );
448 cloneHandler.SetClonePath( pro.GetPath() );
449 cloneHandler.SetUsername( dlg.GetUsername() );
450 cloneHandler.SetPassword( dlg.GetPassword() );
451 cloneHandler.SetSSHKey( dlg.GetRepoSSHPath() );
452
453 cloneHandler.SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>( m_frame, _( "Clone Repository" ), 1,
454 PR_NO_ABORT ) );
455
456 if( !cloneHandler.PerformClone() )
457 {
458 DisplayErrorMessage( m_frame, cloneHandler.GetErrorString() );
459 return -1;
460 }
461
462 std::vector<wxString> projects = cloneHandler.GetProjectDirs();
463
464 if( projects.empty() )
465 {
466 DisplayErrorMessage( m_frame, _( "No project files were found in the repository." ) );
467 return -1;
468 }
469
470 // Currently, we pick the first project file we find in the repository.
471 // TODO: Look into spare checkout to allow the user to pick a partial repository
472 wxString dest = pro.GetPath() + wxFileName::GetPathSeparator() + projects.front();
473 m_frame->LoadProject( dest );
474
478
482 Prj().GetLocalSettings().m_GitRepoType = "https";
483 else
484 Prj().GetLocalSettings().m_GitRepoType = "local";
485
486 return 0;
487}
488
489
491{
492 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
493 wxFileDialog dlg( m_frame, _( "Create New Jobset" ), default_dir, wxEmptyString, FILEEXT::JobsetFileWildcard(),
494 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
495
497
498 if( dlg.ShowModal() == wxID_CANCEL )
499 return -1;
500
501 wxFileName jobsetFn( dlg.GetPath() );
502
503 // Check if the file already exists
504 bool fileExists = wxFileExists( jobsetFn.GetFullPath() );
505
506 if( fileExists )
507 {
508 // Remove the existing file so that a new one can be created
509 if( !wxRemoveFile( jobsetFn.GetFullPath() ) )
510 {
511 return -1;
512 }
513 }
514
515 m_frame->OpenJobsFile( jobsetFn.GetFullPath(), true );
516
517 return 0;
518}
519
520
521
522
523int KICAD_MANAGER_CONTROL::openProject( const wxString& aDefaultDir )
524{
525 wxString wildcard = FILEEXT::AllProjectFilesWildcard()
528
529 wxFileDialog dlg( m_frame, _( "Open Existing Project" ), aDefaultDir, wxEmptyString, wildcard,
530 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
531
532 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
533
535
536 if( dlg.ShowModal() == wxID_CANCEL )
537 return -1;
538
539 wxFileName pro( dlg.GetPath() );
540
541 if( !pro.IsAbsolute() )
542 pro.MakeAbsolute();
543
544 // You'd think wxFD_FILE_MUST_EXIST and the wild-cards would enforce these. Sentry
545 // indicates otherwise (at least on MSW).
546 if( !pro.Exists() || ( pro.GetExt() != FILEEXT::ProjectFileExtension
547 && pro.GetExt() != FILEEXT::LegacyProjectFileExtension ) )
548 {
549 return -1;
550 }
551
552 m_frame->LoadProject( pro );
553
554 return 0;
555}
556
557
562
563
565{
566 return openProject( m_frame->GetMruPath() );
567}
568
569
571{
572 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
573 wxFileDialog dlg( m_frame, _( "Open Jobset" ), default_dir, wxEmptyString, FILEEXT::JobsetFileWildcard(),
574 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
575
577
578 if( dlg.ShowModal() == wxID_CANCEL )
579 return -1;
580
581 wxFileName jobsetFn( dlg.GetPath() );
582
583 m_frame->OpenJobsFile( jobsetFn.GetFullPath(), true );
584
585 return 0;
586}
587
588
590{
591 m_frame->CloseProject( true );
592 return 0;
593}
594
595
597{
598 if( aEvent.Parameter<wxString*>() )
599 m_frame->LoadProject( wxFileName( *aEvent.Parameter<wxString*>() ) );
600 return 0;
601}
602
603
605{
606 wxFileName fileName = m_frame->GetProjectFileName();
607
608 fileName.SetExt( FILEEXT::ArchiveFileExtension );
609
610 wxFileDialog dlg( m_frame, _( "Archive Project Files" ), fileName.GetPath(), fileName.GetFullName(),
611 FILEEXT::ZipFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
612
614
615 if( dlg.ShowModal() == wxID_CANCEL )
616 return 0;
617
618 wxFileName zipFile = dlg.GetPath();
619
620 wxString currdirname = fileName.GetPathWithSep();
621 wxDir dir( currdirname );
622
623 if( !dir.IsOpened() ) // wxWidgets display a error message on issue.
624 return 0;
625
626 STATUSBAR_REPORTER reporter( m_frame->GetStatusBar(), 1 );
627 PROJECT_ARCHIVER archiver;
628
629 archiver.Archive( currdirname, zipFile.GetFullPath(), reporter, true, true );
630 return 0;
631}
632
633
635{
636 m_frame->UnarchiveFiles();
637 return 0;
638}
639
640
642{
643 // Open project directory in host OS's file explorer
644 LaunchExternal( Prj().GetProjectPath() );
645 return 0;
646}
647
649{
650 m_frame->RestoreLocalHistory();
651 return 0;
652}
653
654
656{
657 m_frame->ToggleLocalHistory();
658 return 0;
659}
660
661
663{
664 if( aEvent.Parameter<wxString*>() )
665 wxExecute( *aEvent.Parameter<wxString*>(), wxEXEC_ASYNC );
666
667 return 0;
668}
669
670
671
673{
674 wxString msg;
675
676 wxFileName currentProjectFile( Prj().GetProjectFullName() );
677 wxString currentProjectDirPath = currentProjectFile.GetPath();
678 wxString currentProjectName = Prj().GetProjectName();
679
680 wxString default_dir = m_frame->GetMruPath();
681
682 Prj().GetProjectFile().SaveToFile( currentProjectDirPath );
683 Prj().GetLocalSettings().SaveToFile( currentProjectDirPath );
684
685 if( default_dir == currentProjectDirPath
686 || default_dir == currentProjectDirPath + wxFileName::GetPathSeparator() )
687 {
688 // Don't start within the current project
689 wxFileName default_dir_fn( default_dir );
690 default_dir_fn.RemoveLastDir();
691 default_dir = default_dir_fn.GetPath();
692 }
693
694 wxFileDialog dlg( m_frame, _( "Save Project To" ), default_dir, wxEmptyString, wxEmptyString, wxFD_SAVE );
695
696 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
697
699
700 if( dlg.ShowModal() == wxID_CANCEL )
701 return -1;
702
703 wxFileName newProjectDir( dlg.GetPath(), wxEmptyString );
704
705 if( !newProjectDir.IsAbsolute() )
706 newProjectDir.MakeAbsolute();
707
708 if( wxDirExists( newProjectDir.GetFullPath() ) )
709 {
710 msg.Printf( _( "'%s' already exists." ), newProjectDir.GetFullPath() );
712 return -1;
713 }
714
715 if( !wxMkdir( newProjectDir.GetFullPath() ) )
716 {
717 DisplayErrorMessage( m_frame, wxString::Format( _( "Folder '%s' could not be created.\n\n"
718 "Please make sure you have sufficient permissions." ),
719 newProjectDir.GetPath() ) );
720 return -1;
721 }
722
723 if( !newProjectDir.IsDirWritable() )
724 {
725 DisplayErrorMessage( m_frame, wxString::Format( _( "Insufficient permissions to write to folder '%s'." ),
726 newProjectDir.GetFullPath() ) );
727 return -1;
728 }
729
730 const wxString& newProjectDirPath = newProjectDir.GetFullPath();
731 const wxString& newProjectName = newProjectDir.GetDirs().Last();
732 wxDir currentProjectDir( currentProjectDirPath );
733
734 PROJECT_TREE_TRAVERSER traverser( m_frame, currentProjectDirPath, currentProjectName,
735 newProjectDirPath, newProjectName );
736
737 currentProjectDir.Traverse( traverser );
738
739 if( !traverser.GetErrors().empty() )
740 DisplayErrorMessage( m_frame, traverser.GetErrors() );
741
742 if( !traverser.GetNewProjectFile().FileExists() )
743 m_frame->CreateNewProject( traverser.GetNewProjectFile() );
744
745 m_frame->LoadProject( traverser.GetNewProjectFile() );
746
747 return 0;
748}
749
750
752{
753 m_frame->RefreshProjectTree();
754 return 0;
755}
756
757
759{
760 ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
761 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
762 SELECTION dummySel;
763
764 if( conditionalMenu )
765 conditionalMenu->Evaluate( dummySel );
766
767 if( actionMenu )
768 actionMenu->UpdateAll();
769
770 return 0;
771}
772
773
775{
776 FRAME_T playerType = aEvent.Parameter<FRAME_T>();
777 KIWAY_PLAYER* player;
778
779 if( playerType == FRAME_SCH && !m_frame->IsProjectActive() )
780 {
781 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a schematic." ), wxEmptyString );
782 return -1;
783 }
784 else if( playerType == FRAME_PCB_EDITOR && !m_frame->IsProjectActive() )
785 {
786 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a pcb." ), wxEmptyString );
787 return -1;
788 }
789
790 if( m_inShowPlayer )
791 return -1;
792
794
795 try
796 {
797 player = m_frame->Kiway().Player( playerType, true );
798 }
799 catch( const IO_ERROR& err )
800 {
801 wxLogError( _( "Application failed to load:\n" ) + err.What() );
802 return -1;
803 }
804
805 if ( !player )
806 {
807 wxLogError( _( "Application cannot start." ) );
808 return -1;
809 }
810
811 if( !player->IsVisible() ) // A hidden frame might not have the document loaded.
812 {
813 wxString filepath;
814
815 if( playerType == FRAME_SCH )
816 {
817 wxFileName kicad_schematic( m_frame->SchFileName() );
818 wxFileName legacy_schematic( m_frame->SchLegacyFileName() );
819
820 if( !legacy_schematic.FileExists() || kicad_schematic.FileExists() )
821 filepath = kicad_schematic.GetFullPath();
822 else
823 filepath = legacy_schematic.GetFullPath();
824 }
825 else if( playerType == FRAME_PCB_EDITOR )
826 {
827 wxFileName kicad_board( m_frame->PcbFileName() );
828 wxFileName legacy_board( m_frame->PcbLegacyFileName() );
829
830 if( !legacy_board.FileExists() || kicad_board.FileExists() )
831 filepath = kicad_board.GetFullPath();
832 else
833 filepath = legacy_board.GetFullPath();
834 }
835
836 if( !filepath.IsEmpty() )
837 {
838 std::vector<wxString> file_list{ filepath };
839
840 if( !player->OpenProjectFiles( file_list ) )
841 {
842 player->Destroy();
843 return -1;
844 }
845 }
846
847 wxBusyCursor busy;
848 player->Show( true );
849 }
850
851 // Needed on Windows, other platforms do not use it, but it creates no issue
852 if( player->IsIconized() )
853 player->Iconize( false );
854
855 player->Raise();
856
857 // Raising the window does not set the focus on Linux. This should work on
858 // any platform.
859 if( wxWindow::FindFocus() != player )
860 player->SetFocus();
861
862 // Save window state to disk now. Don't wait around for a crash.
863 if( Pgm().GetCommonSettings()->m_Session.remember_open_files
864 && !player->GetCurrentFileName().IsEmpty()
865 && Prj().GetLocalSettings().ShouldAutoSave() )
866 {
867 wxFileName rfn( player->GetCurrentFileName() );
868 rfn.MakeRelativeTo( Prj().GetProjectPath() );
869
870 WINDOW_SETTINGS windowSettings;
871 player->SaveWindowSettings( &windowSettings );
872
873 Prj().GetLocalSettings().SaveFileState( rfn.GetFullPath(), &windowSettings, true );
874 Prj().GetLocalSettings().SaveToFile( Prj().GetProjectPath() );
875 }
876
877 return 0;
878}
879
880
882{
883 wxString execFile;
884 wxString param;
885
887 execFile = GERBVIEW_EXE;
889 execFile = BITMAPCONVERTER_EXE;
891 execFile = PCB_CALCULATOR_EXE;
893 execFile = PL_EDITOR_EXE;
895 execFile = Pgm().GetTextEditor();
897 execFile = EESCHEMA_EXE;
899 execFile = PCBNEW_EXE;
900 else
901 wxFAIL_MSG( "Execute(): unexpected request" );
902
903 if( execFile.IsEmpty() )
904 return 0;
905
906 if( aEvent.Parameter<wxString*>() )
907 param = *aEvent.Parameter<wxString*>();
908 else if( aEvent.IsAction( &KICAD_MANAGER_ACTIONS::viewGerbers ) && m_frame->IsProjectActive() )
909 param = m_frame->Prj().GetProjectPath();
910
911 COMMON_CONTROL* commonControl = m_toolMgr->GetTool<COMMON_CONTROL>();
912 return commonControl->Execute( execFile, param );
913}
914
915
917{
919 {
920 // policy disables the plugin manager
921 return 0;
922 }
923
924 // For some reason, after a click or a double click the bitmap button calling
925 // PCM keeps the focus althougt the focus was not set to this button.
926 // This hack force removing the focus from this button
927 m_frame->SetFocus();
928 wxSafeYield();
929
930 if( !m_frame->GetPcm() )
931 m_frame->CreatePCM();
932
933 DIALOG_PCM pcm( m_frame, m_frame->GetPcm() );
934 pcm.ShowModal();
935
936 const std::unordered_set<PCM_PACKAGE_TYPE>& changed = pcm.GetChangedPackageTypes();
937
938 if( changed.count( PCM_PACKAGE_TYPE::PT_PLUGIN ) || changed.count( PCM_PACKAGE_TYPE::PT_FAB ) )
939 {
940 std::string payload = "";
941 m_frame->Kiway().ExpressMail( FRAME_PCB_EDITOR, MAIL_RELOAD_PLUGINS, payload );
942 }
943
944 KICAD_SETTINGS* settings = GetAppSettings<KICAD_SETTINGS>( "kicad" );
945
946 if( changed.count( PCM_PACKAGE_TYPE::PT_LIBRARY )
947 && ( settings->m_PcmLibAutoAdd || settings->m_PcmLibAutoRemove ) )
948 {
949 KIWAY& kiway = m_frame->Kiway();
950
951 // Reset state containing global lib tables
952 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_SCH, false ) )
953 kiface->Reset();
954
955 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_PCB, false ) )
956 kiface->Reset();
957
958 // Reload lib tables
959 std::string payload = "";
960
963 kiway.ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload );
966 }
967
968 if( changed.count( PCM_PACKAGE_TYPE::PT_COLORTHEME ) )
970
971 return 0;
972}
973
974
976{
987
993
996
1006
1009
1011}
static TOOL_ACTION zoomRedraw
Definition actions.h:132
static TOOL_ACTION saveAs
Definition actions.h:59
static TOOL_ACTION updateMenu
Definition actions.h:270
Define the structure of a menu based on ACTIONs.
Definition action_menu.h:47
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:38
const std::unordered_set< PCM_PACKAGE_TYPE > & GetChangedPackageTypes() const
Definition dialog_pcm.h:81
int ShowModal() override
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
This method is meant to be overridden in order to specify handlers for 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)
Set up handlers for various events.
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
wxPoint m_TemplateWindowPos
wxString m_LastUsedTemplate
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:42
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:55
int ShowModal() override
Definition kidialog.cpp:93
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:315
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:500
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition kiway.cpp:211
@ FACE_SCH
eeschema DSO
Definition kiway.h:322
@ FACE_PCB
pcbnew DSO
Definition kiway.h:323
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:787
virtual const wxString & GetTextEditor(bool aCanShowFileChooser=true)
Return the path to the preferred text editor application.
Definition pgm_base.cpp:225
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:130
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.
PROJECT_TREE_PANE 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:199
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition project.h:210
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:204
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:361
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:224
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:78
Generic, UI-independent tool event.
Definition tool_event.h:171
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:473
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:708
The common library.
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:278
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:249
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:221
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:33
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:35
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:45
@ FRAME_SCH_VIEWER
Definition frame_type.h:36
@ FRAME_SCH
Definition frame_type.h:34
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:43
@ FRAME_CVPCB
Definition frame_type.h:52
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:669
static wxFileName ensureDefaultProjectTemplate()
bool LaunchExternal(const wxString &aPath)
Launches the given file or folder in the host OS.
@ MAIL_RELOAD_PLUGINS
Definition mail_type.h:59
@ MAIL_RELOAD_LIB
Definition mail_type.h:58
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:86
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:448
@ 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:31
#define METADIR
A directory which contains information about the project template and does not get copied.
#define METAFILE_INFO_HTML
A required html formatted file which contains information about the project template.
T * GetAppSettings(const char *aFilename)
Implement a participant in the KIWAY alchemy.
Definition kiway.h:156
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:39
#define PR_NO_ABORT