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:38
const std::unordered_set< PCM_PACKAGE_TYPE > & GetChangedPackageTypes() const
Definition dialog_pcm.h:81
int ShowModal() override
wxString GetBrowsedTemplatesPath() const
Last directory chosen via the "Browse..." button so the caller can persist it.
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
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:311
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:496
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:318
@ FACE_PCB
pcbnew DSO
Definition kiway.h:319
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:799
virtual const wxString & GetTextEditor(bool aCanShowFileChooser=true)
Return the path to the preferred text editor application.
Definition pgm_base.cpp:218
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:124
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:195
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition project.h:206
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:200
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:357
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:469
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:721
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: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:728
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: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: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:152
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