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 <env_vars.h>
23#include <executable_names.h>
24#include <pgm_base.h>
25#include <pgm_kicad.h>
26#include <policy_keys.h>
27#include <kiway.h>
28#include <kicad_manager_frame.h>
29#include <kiplatform/policy.h>
30#include <kiplatform/secrets.h>
31#include <confirm.h>
32#include <kidialog.h>
37#include <tool/selection.h>
38#include <tool/tool_event.h>
39#include <tool/tool_manager.h>
40#include <tool/common_control.h>
47#include <gestfich.h>
48#include <paths.h>
49#include <wx/dir.h>
50#include <wx/filedlg.h>
51#include <wx/ffile.h>
53#include "dialog_pcm.h"
55#include <project_tree_pane.h>
56#include <project_tree.h>
57#include <launch_ext.h>
58
60
62 TOOL_INTERACTIVE( "kicad.Control" ),
63 m_frame( nullptr ),
64 m_inShowPlayer( false )
65{
66}
67
68
73
74
75wxFileName KICAD_MANAGER_CONTROL::newProjectDirectory( wxString* aFileName, bool isRepo )
76{
77 wxString default_filename = aFileName ? *aFileName : wxString();
78
79 wxString default_dir = m_frame->GetMruPath();
80 wxFileDialog dlg( m_frame, _( "Create New Project" ), default_dir, default_filename,
81 ( isRepo ? wxString( "" ) : FILEEXT::ProjectFileWildcard() ),
82 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
83
84 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
85
86 // Add a "Create a new directory" checkbox
87 FILEDLG_NEW_PROJECT newProjectHook;
88 dlg.SetCustomizeHook( newProjectHook );
89
90 if( dlg.ShowModal() == wxID_CANCEL )
91 return wxFileName();
92
93 wxFileName pro( dlg.GetPath() );
94
95 // wxFileName automatically extracts an extension. But if it isn't
96 // a .pro extension, we should keep it as part of the filename
97 if( !pro.GetExt().IsEmpty() && pro.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
98 pro.SetName( pro.GetName() + wxT( "." ) + pro.GetExt() );
99
100 pro.SetExt( FILEEXT::ProjectFileExtension ); // enforce extension
101
102 if( !pro.IsAbsolute() )
103 pro.MakeAbsolute();
104
105 // Append a new directory with the same name of the project file.
106 bool createNewDir = false;
107
108 createNewDir = newProjectHook.GetCreateNewDir();
109
110 if( createNewDir )
111 pro.AppendDir( pro.GetName() );
112
113 // Check if the project directory is empty if it already exists.
114 wxDir directory( pro.GetPath() );
115
116 if( !pro.DirExists() )
117 {
118 if( !pro.Mkdir() )
119 {
120 wxString msg;
121 msg.Printf( _( "Folder '%s' could not be created.\n\n"
122 "Make sure you have write permissions and try again." ),
123 pro.GetPath() );
125 return wxFileName();
126 }
127 }
128 else if( directory.HasFiles() )
129 {
130 wxString msg = _( "The selected folder is not empty. It is recommended that you "
131 "create projects in their own empty folder.\n\n"
132 "Do you want to continue?" );
133
134 if( !IsOK( m_frame, msg ) )
135 return wxFileName();
136 }
137
138 return pro;
139}
140
141
143{
144 ENV_VAR_MAP_CITER it = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
145
146 if( it == Pgm().GetLocalEnvVariables().end() || it->second.GetValue() == wxEmptyString )
147 return wxFileName();
148
149 wxFileName templatePath;
150 templatePath.AssignDir( it->second.GetValue() );
151 templatePath.AppendDir( "default" );
152
153 if( templatePath.DirExists() )
154 return templatePath;
155
156 if( !templatePath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
157 return wxFileName();
158
159 wxFileName metaDir = templatePath;
160 metaDir.AppendDir( METADIR );
161
162 if( !metaDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
163 return wxFileName();
164
165 wxFileName infoFile = metaDir;
166 infoFile.SetFullName( METAFILE_INFO_HTML );
167 wxFFile info( infoFile.GetFullPath(), wxT( "w" ) );
168
169 if( !info.IsOpened() )
170 return wxFileName();
171
172 info.Write( wxT( "<html><head><title>Default</title></head><body></body></html>" ) );
173 info.Close();
174
175 wxFileName proFile = templatePath;
176 proFile.SetFullName( wxT( "default.kicad_pro" ) );
177 wxFFile proj( proFile.GetFullPath(), wxT( "w" ) );
178
179 if( !proj.IsOpened() )
180 return wxFileName();
181
182 proj.Write( wxT( "{}" ) );
183 proj.Close();
184
185 return templatePath;
186}
187
189{
190 wxFileName defaultTemplate = ensureDefaultProjectTemplate();
191
192 if( !defaultTemplate.IsOk() )
193 {
194 wxFileName pro = newProjectDirectory();
195
196 if( !pro.IsOk() )
197 return -1;
198
199 m_frame->CreateNewProject( pro );
200 m_frame->LoadProject( pro );
201
202 return 0;
203 }
204
205 KICAD_SETTINGS* settings = GetAppSettings<KICAD_SETTINGS>( "kicad" );
206 std::vector<std::pair<wxString, wxFileName>> titleDirList;
207 wxFileName templatePath;
208
209 ENV_VAR_MAP_CITER itUser = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
210
211 if( itUser != Pgm().GetLocalEnvVariables().end() && itUser->second.GetValue() != wxEmptyString )
212 {
213 templatePath.AssignDir( itUser->second.GetValue() );
214 titleDirList.emplace_back( _( "User Templates" ), templatePath );
215 }
216
217 std::optional<wxString> v = ENV_VAR::GetVersionedEnvVarValue( Pgm().GetLocalEnvVariables(),
218 wxT( "TEMPLATE_DIR" ) );
219
220 if( v && !v->IsEmpty() )
221 {
222 templatePath.AssignDir( *v );
223 titleDirList.emplace_back( _( "System Templates" ), templatePath );
224 }
225
227 titleDirList, defaultTemplate );
228
229 int result = ps.ShowModal();
230
231 settings->m_TemplateWindowPos = ps.GetPosition();
232 settings->m_TemplateWindowSize = ps.GetSize();
233
234 if( result != wxID_OK )
235 return -1;
236
237 PROJECT_TEMPLATE* selectedTemplate = ps.GetSelectedTemplate();
238
239 if( !selectedTemplate )
240 selectedTemplate = ps.GetDefaultTemplate();
241
242 if( !selectedTemplate )
243 {
244 wxMessageBox( _( "No project template was selected. Cannot generate new project." ), _( "Error" ),
245 wxOK | wxICON_ERROR, m_frame );
246
247 return -1;
248 }
249
250 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
251 wxString title = _( "New Project Folder" );
252 wxFileDialog dlg( m_frame, title, default_dir, wxEmptyString, FILEEXT::ProjectFileWildcard(),
253 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
254
255 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
256
257 FILEDLG_NEW_PROJECT newProjectHook;
258 dlg.SetCustomizeHook( newProjectHook );
259
260 if( dlg.ShowModal() == wxID_CANCEL )
261 return -1;
262
263 wxFileName fn( dlg.GetPath() );
264
265 if( !fn.GetExt().IsEmpty() && fn.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
266 fn.SetName( fn.GetName() + wxT( "." ) + fn.GetExt() );
267
269
270 if( !fn.IsAbsolute() )
271 fn.MakeAbsolute();
272
273 bool createNewDir = false;
274 createNewDir = newProjectHook.GetCreateNewDir();
275
276 if( createNewDir )
277 fn.AppendDir( fn.GetName() );
278
279 if( !fn.DirExists() && !fn.Mkdir() )
280 {
281 DisplayErrorMessage( m_frame, wxString::Format( _( "Folder '%s' could not be created.\n\n"
282 "Make sure you have write permissions and try again." ),
283 fn.GetPath() ) );
284 return -1;
285 }
286
287 if( !fn.IsDirWritable() )
288 {
289 DisplayErrorMessage( m_frame, wxString::Format( _( "Insufficient permissions to write to folder '%s'." ),
290 fn.GetPath() ) );
291 return -1;
292 }
293
294 std::vector< wxFileName > destFiles;
295
296 if( selectedTemplate->GetDestinationFiles( fn, destFiles ) )
297 {
298 std::vector<wxFileName> overwrittenFiles;
299
300 for( const wxFileName& file : destFiles )
301 {
302 if( file.FileExists() )
303 overwrittenFiles.push_back( file );
304 }
305
306 if( !overwrittenFiles.empty() )
307 {
308 wxString extendedMsg = _( "Overwriting files:" ) + "\n";
309
310 for( const wxFileName& file : overwrittenFiles )
311 extendedMsg += "\n" + file.GetFullName();
312
313 KIDIALOG msgDlg( m_frame, _( "Similar files already exist in the destination folder." ),
314 _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
315 msgDlg.SetExtendedMessage( extendedMsg );
316 msgDlg.SetOKLabel( _( "Overwrite" ) );
317 msgDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
318
319 if( msgDlg.ShowModal() == wxID_CANCEL )
320 return -1;
321 }
322 }
323
324 wxString errorMsg;
325
326 if( !selectedTemplate->CreateProject( fn, &errorMsg ) )
327 {
328 DisplayErrorMessage( m_frame, _( "A problem occurred creating new project from template." ), errorMsg );
329 return -1;
330 }
331
332 m_frame->CreateNewProject( fn.GetFullPath() );
333 m_frame->LoadProject( fn );
334 return 0;
335}
336
337
339{
340 DIALOG_GIT_REPOSITORY dlg( m_frame, nullptr );
341
342 dlg.SetTitle( _( "Clone Project from Git Repository" ) );
343
344 int ret = dlg.ShowModal();
345
346 if( ret != wxID_OK )
347 return -1;
348
349 wxString project_name = dlg.GetRepoName();
350 wxFileName pro = newProjectDirectory( &project_name, true );
351
352 if( !pro.IsOk() )
353 return -1;
354
355 PROJECT_TREE_PANE *pane = static_cast<PROJECT_TREE_PANE*>( m_frame->GetToolCanvas() );
356
357
358 GIT_CLONE_HANDLER cloneHandler( pane->m_TreeProject->GitCommon() );
359
360 cloneHandler.SetRemote( dlg.GetFullURL() );
361 cloneHandler.SetClonePath( pro.GetPath() );
362 cloneHandler.SetUsername( dlg.GetUsername() );
363 cloneHandler.SetPassword( dlg.GetPassword() );
364 cloneHandler.SetSSHKey( dlg.GetRepoSSHPath() );
365
366 cloneHandler.SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>( m_frame, _( "Clone Repository" ), 1,
367 PR_NO_ABORT ) );
368
369 if( !cloneHandler.PerformClone() )
370 {
371 DisplayErrorMessage( m_frame, cloneHandler.GetErrorString() );
372 return -1;
373 }
374
375 std::vector<wxString> projects = cloneHandler.GetProjectDirs();
376
377 if( projects.empty() )
378 {
379 DisplayErrorMessage( m_frame, _( "No project files were found in the repository." ) );
380 return -1;
381 }
382
383 // Currently, we pick the first project file we find in the repository.
384 // TODO: Look into spare checkout to allow the user to pick a partial repository
385 wxString dest = pro.GetPath() + wxFileName::GetPathSeparator() + projects.front();
386 m_frame->LoadProject( dest );
387
391
395 Prj().GetLocalSettings().m_GitRepoType = "https";
396 else
397 Prj().GetLocalSettings().m_GitRepoType = "local";
398
399 return 0;
400}
401
402
404{
405 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
406 wxFileDialog dlg( m_frame, _( "Create New Jobset" ), default_dir, wxEmptyString, FILEEXT::JobsetFileWildcard(),
407 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
408
409 if( dlg.ShowModal() == wxID_CANCEL )
410 return -1;
411
412 wxFileName jobsetFn( dlg.GetPath() );
413
414 // Check if the file already exists
415 bool fileExists = wxFileExists( jobsetFn.GetFullPath() );
416
417 if( fileExists )
418 {
419 // Remove the existing file so that a new one can be created
420 if( !wxRemoveFile( jobsetFn.GetFullPath() ) )
421 {
422 return -1;
423 }
424 }
425
426 m_frame->OpenJobsFile( jobsetFn.GetFullPath(), true );
427
428 return 0;
429}
430
431
432
433
434int KICAD_MANAGER_CONTROL::openProject( const wxString& aDefaultDir )
435{
436 wxString wildcard = FILEEXT::AllProjectFilesWildcard()
439
440 wxFileDialog dlg( m_frame, _( "Open Existing Project" ), aDefaultDir, wxEmptyString, wildcard,
441 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
442
443 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
444
445 if( dlg.ShowModal() == wxID_CANCEL )
446 return -1;
447
448 wxFileName pro( dlg.GetPath() );
449
450 if( !pro.IsAbsolute() )
451 pro.MakeAbsolute();
452
453 // You'd think wxFD_FILE_MUST_EXIST and the wild-cards would enforce these. Sentry
454 // indicates otherwise (at least on MSW).
455 if( !pro.Exists() || ( pro.GetExt() != FILEEXT::ProjectFileExtension
456 && pro.GetExt() != FILEEXT::LegacyProjectFileExtension ) )
457 {
458 return -1;
459 }
460
461 m_frame->LoadProject( pro );
462
463 return 0;
464}
465
466
471
472
474{
475 return openProject( m_frame->GetMruPath() );
476}
477
478
480{
481 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
482 wxFileDialog dlg( m_frame, _( "Open Jobset" ), default_dir, wxEmptyString, FILEEXT::JobsetFileWildcard(),
483 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
484
485 if( dlg.ShowModal() == wxID_CANCEL )
486 return -1;
487
488 wxFileName jobsetFn( dlg.GetPath() );
489
490 m_frame->OpenJobsFile( jobsetFn.GetFullPath(), true );
491
492 return 0;
493}
494
495
497{
498 m_frame->CloseProject( true );
499 return 0;
500}
501
502
504{
505 if( aEvent.Parameter<wxString*>() )
506 m_frame->LoadProject( wxFileName( *aEvent.Parameter<wxString*>() ) );
507 return 0;
508}
509
510
512{
513 wxFileName fileName = m_frame->GetProjectFileName();
514
515 fileName.SetExt( FILEEXT::ArchiveFileExtension );
516
517 wxFileDialog dlg( m_frame, _( "Archive Project Files" ), fileName.GetPath(), fileName.GetFullName(),
518 FILEEXT::ZipFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
519
520 if( dlg.ShowModal() == wxID_CANCEL )
521 return 0;
522
523 wxFileName zipFile = dlg.GetPath();
524
525 wxString currdirname = fileName.GetPathWithSep();
526 wxDir dir( currdirname );
527
528 if( !dir.IsOpened() ) // wxWidgets display a error message on issue.
529 return 0;
530
531 STATUSBAR_REPORTER reporter( m_frame->GetStatusBar(), 1 );
532 PROJECT_ARCHIVER archiver;
533
534 archiver.Archive( currdirname, zipFile.GetFullPath(), reporter, true, true );
535 return 0;
536}
537
538
540{
541 m_frame->UnarchiveFiles();
542 return 0;
543}
544
545
547{
548 // Open project directory in host OS's file explorer
549 LaunchExternal( Prj().GetProjectPath() );
550 return 0;
551}
552
553
555{
556 if( aEvent.Parameter<wxString*>() )
557 wxExecute( *aEvent.Parameter<wxString*>(), wxEXEC_ASYNC );
558
559 return 0;
560}
561
562class SAVE_AS_TRAVERSER : public wxDirTraverser
563{
564public:
566 const wxString& aSrcProjectDirPath,
567 const wxString& aSrcProjectName,
568 const wxString& aNewProjectDirPath,
569 const wxString& aNewProjectName ) :
570 m_frame( aFrame ),
571 m_projectDirPath( aSrcProjectDirPath ),
572 m_projectName( aSrcProjectName ),
573 m_newProjectDirPath( aNewProjectDirPath ),
574 m_newProjectName( aNewProjectName )
575 {
576 }
577
578 virtual wxDirTraverseResult OnFile( const wxString& aSrcFilePath ) override
579 {
580 // Recursion guard for a Save As to a location inside the source project.
581 if( aSrcFilePath.StartsWith( m_newProjectDirPath + wxFileName::GetPathSeparator() ) )
582 return wxDIR_CONTINUE;
583
584 wxFileName destFile( aSrcFilePath );
585 wxString ext = destFile.GetExt();
586 bool atRoot = destFile.GetPath() == m_projectDirPath;
587
591 {
592 wxString destPath = destFile.GetPath();
593
594 if( destPath.StartsWith( m_projectDirPath ) )
595 {
596 destPath.Replace( m_projectDirPath, m_newProjectDirPath, false );
597 destFile.SetPath( destPath );
598 }
599
600 if( destFile.GetName() == m_projectName )
601 {
602 destFile.SetName( m_newProjectName );
603
604 if( atRoot && ext != FILEEXT::ProjectLocalSettingsFileExtension )
605 m_newProjectFile = destFile;
606 }
607
609 {
610 // All paths in the settings file are relative so we can just do a straight copy
611 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), m_errors );
612 }
613 else if( ext == FILEEXT::ProjectFileExtension )
614 {
615 PROJECT_FILE projectFile( aSrcFilePath );
616 projectFile.LoadFromFile();
617 projectFile.SaveAs( destFile.GetPath(), destFile.GetName() );
618 }
620 {
621 PROJECT_LOCAL_SETTINGS projectLocalSettings( nullptr, aSrcFilePath );
622 projectLocalSettings.LoadFromFile();
623 projectLocalSettings.SaveAs( destFile.GetPath(), destFile.GetName() );
624 }
625 }
635 || destFile.GetName() == FILEEXT::SymbolLibraryTableFileName )
636 {
637 KIFACE* eeschema = m_frame->Kiway().KiFACE( KIWAY::FACE_SCH );
639 m_newProjectName, aSrcFilePath, m_errors );
640 }
641 else if( ext == FILEEXT::KiCadPcbFileExtension
647 || destFile.GetName() == FILEEXT::FootprintLibraryTableFileName )
648 {
649 KIFACE* pcbnew = m_frame->Kiway().KiFACE( KIWAY::FACE_PCB );
651 m_newProjectName, aSrcFilePath, m_errors );
652 }
653 else if( ext == FILEEXT::DrawingSheetFileExtension )
654 {
655 KIFACE* pleditor = m_frame->Kiway().KiFACE( KIWAY::FACE_PL_EDITOR );
657 m_newProjectName, aSrcFilePath, m_errors );
658 }
659 else if( ext == FILEEXT::GerberJobFileExtension
662 {
663 KIFACE* gerbview = m_frame->Kiway().KiFACE( KIWAY::FACE_GERBVIEW );
665 m_newProjectName, aSrcFilePath, m_errors );
666 }
667 else if( destFile.GetName().StartsWith( FILEEXT::LockFilePrefix )
669 {
670 // Ignore lock files
671 }
672 else
673 {
674 // Everything we don't recognize just gets a straight copy.
675 wxString destPath = destFile.GetPathWithSep();
676 wxString destName = destFile.GetName();
677 wxUniChar pathSep = wxFileName::GetPathSeparator();
678
679 wxString srcProjectFootprintLib = pathSep + m_projectName + ".pretty" + pathSep;
680 wxString newProjectFootprintLib = pathSep + m_newProjectName + ".pretty" + pathSep;
681
682 if( destPath.StartsWith( m_projectDirPath ) )
683 destPath.Replace( m_projectDirPath, m_newProjectDirPath, false );
684
685 destPath.Replace( srcProjectFootprintLib, newProjectFootprintLib, true );
686
687 if( destName == m_projectName && ext != wxT( "zip" ) /* don't rename archives */ )
688 destFile.SetName( m_newProjectName );
689
690 destFile.SetPath( destPath );
691
692 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), m_errors );
693 }
694
695 return wxDIR_CONTINUE;
696 }
697
698 virtual wxDirTraverseResult OnDir( const wxString& aSrcDirPath ) override
699 {
700 // Recursion guard for a Save As to a location inside the source project.
701 if( aSrcDirPath.StartsWith( m_newProjectDirPath ) )
702 return wxDIR_CONTINUE;
703
704 wxFileName destDir( aSrcDirPath );
705 wxString destDirPath = destDir.GetPathWithSep();
706 wxUniChar pathSep = wxFileName::GetPathSeparator();
707
708 if( destDirPath.StartsWith( m_projectDirPath + pathSep )
709 || destDirPath.StartsWith( m_projectDirPath + PROJECT_BACKUPS_DIR_SUFFIX ) )
710 {
711 destDirPath.Replace( m_projectDirPath, m_newProjectDirPath, false );
712 destDir.SetPath( destDirPath );
713 }
714
715 if( destDir.GetName() == m_projectName )
716 {
717 if( destDir.GetExt() == "pretty" )
718 destDir.SetName( m_newProjectName );
719#if 0
720 // WAYNE STAMBAUGH TODO:
721 // If we end up with a symbol equivalent to ".pretty" we'll want to handle it here....
722 else if( destDir.GetExt() == "sym_lib_dir_extension" )
723 destDir.SetName( m_newProjectName );
724#endif
725 }
726
727 if( !wxMkdir( destDir.GetFullPath() ) )
728 {
729 wxString msg;
730
731 if( !m_errors.empty() )
732 m_errors += "\n";
733
734 msg.Printf( _( "Cannot copy folder '%s'." ), destDir.GetFullPath() );
735 m_errors += msg;
736 }
737
738 return wxDIR_CONTINUE;
739 }
740
741 wxString GetErrors() { return m_errors; }
742
743 wxFileName GetNewProjectFile() { return m_newProjectFile; }
744
745private:
747
752
754 wxString m_errors;
755};
756
757
759{
760 wxString msg;
761
762 wxFileName currentProjectFile( Prj().GetProjectFullName() );
763 wxString currentProjectDirPath = currentProjectFile.GetPath();
764 wxString currentProjectName = Prj().GetProjectName();
765
766 wxString default_dir = m_frame->GetMruPath();
767
768 Prj().GetProjectFile().SaveToFile( currentProjectDirPath );
769 Prj().GetLocalSettings().SaveToFile( currentProjectDirPath );
770
771 if( default_dir == currentProjectDirPath
772 || default_dir == currentProjectDirPath + wxFileName::GetPathSeparator() )
773 {
774 // Don't start within the current project
775 wxFileName default_dir_fn( default_dir );
776 default_dir_fn.RemoveLastDir();
777 default_dir = default_dir_fn.GetPath();
778 }
779
780 wxFileDialog dlg( m_frame, _( "Save Project To" ), default_dir, wxEmptyString, wxEmptyString, wxFD_SAVE );
781
782 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
783
784 if( dlg.ShowModal() == wxID_CANCEL )
785 return -1;
786
787 wxFileName newProjectDir( dlg.GetPath(), wxEmptyString );
788
789 if( !newProjectDir.IsAbsolute() )
790 newProjectDir.MakeAbsolute();
791
792 if( wxDirExists( newProjectDir.GetFullPath() ) )
793 {
794 msg.Printf( _( "'%s' already exists." ), newProjectDir.GetFullPath() );
796 return -1;
797 }
798
799 if( !wxMkdir( newProjectDir.GetFullPath() ) )
800 {
801 DisplayErrorMessage( m_frame, wxString::Format( _( "Folder '%s' could not be created.\n\n"
802 "Please make sure you have sufficient permissions." ),
803 newProjectDir.GetPath() ) );
804 return -1;
805 }
806
807 if( !newProjectDir.IsDirWritable() )
808 {
809 DisplayErrorMessage( m_frame, wxString::Format( _( "Insufficient permissions to write to folder '%s'." ),
810 newProjectDir.GetFullPath() ) );
811 return -1;
812 }
813
814 const wxString& newProjectDirPath = newProjectDir.GetFullPath();
815 const wxString& newProjectName = newProjectDir.GetDirs().Last();
816 wxDir currentProjectDir( currentProjectDirPath );
817
818 SAVE_AS_TRAVERSER traverser( m_frame, currentProjectDirPath, currentProjectName, newProjectDirPath,
819 newProjectName );
820
821 currentProjectDir.Traverse( traverser );
822
823 if( !traverser.GetErrors().empty() )
824 DisplayErrorMessage( m_frame, traverser.GetErrors() );
825
826 if( !traverser.GetNewProjectFile().FileExists() )
827 m_frame->CreateNewProject( traverser.GetNewProjectFile() );
828
829 m_frame->LoadProject( traverser.GetNewProjectFile() );
830
831 return 0;
832}
833
834
836{
837 m_frame->RefreshProjectTree();
838 return 0;
839}
840
841
843{
844 ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
845 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
846 SELECTION dummySel;
847
848 if( conditionalMenu )
849 conditionalMenu->Evaluate( dummySel );
850
851 if( actionMenu )
852 actionMenu->UpdateAll();
853
854 return 0;
855}
856
857
859{
860 FRAME_T playerType = aEvent.Parameter<FRAME_T>();
861 KIWAY_PLAYER* player;
862
863 if( playerType == FRAME_SCH && !m_frame->IsProjectActive() )
864 {
865 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a schematic." ), wxEmptyString );
866 return -1;
867 }
868 else if( playerType == FRAME_PCB_EDITOR && !m_frame->IsProjectActive() )
869 {
870 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a pcb." ), wxEmptyString );
871 return -1;
872 }
873
874 if( m_inShowPlayer )
875 return -1;
876
878
879 try
880 {
881 player = m_frame->Kiway().Player( playerType, true );
882 }
883 catch( const IO_ERROR& err )
884 {
885 wxLogError( _( "Application failed to load:\n" ) + err.What() );
886 return -1;
887 }
888
889 if ( !player )
890 {
891 wxLogError( _( "Application cannot start." ) );
892 return -1;
893 }
894
895 if( !player->IsVisible() ) // A hidden frame might not have the document loaded.
896 {
897 wxString filepath;
898
899 if( playerType == FRAME_SCH )
900 {
901 wxFileName kicad_schematic( m_frame->SchFileName() );
902 wxFileName legacy_schematic( m_frame->SchLegacyFileName() );
903
904 if( !legacy_schematic.FileExists() || kicad_schematic.FileExists() )
905 filepath = kicad_schematic.GetFullPath();
906 else
907 filepath = legacy_schematic.GetFullPath();
908 }
909 else if( playerType == FRAME_PCB_EDITOR )
910 {
911 wxFileName kicad_board( m_frame->PcbFileName() );
912 wxFileName legacy_board( m_frame->PcbLegacyFileName() );
913
914 if( !legacy_board.FileExists() || kicad_board.FileExists() )
915 filepath = kicad_board.GetFullPath();
916 else
917 filepath = legacy_board.GetFullPath();
918 }
919
920 if( !filepath.IsEmpty() )
921 {
922 std::vector<wxString> file_list{ filepath };
923
924 if( !player->OpenProjectFiles( file_list ) )
925 {
926 player->Destroy();
927 return -1;
928 }
929 }
930
931 wxBusyCursor busy;
932 player->Show( true );
933 }
934
935 // Needed on Windows, other platforms do not use it, but it creates no issue
936 if( player->IsIconized() )
937 player->Iconize( false );
938
939 player->Raise();
940
941 // Raising the window does not set the focus on Linux. This should work on
942 // any platform.
943 if( wxWindow::FindFocus() != player )
944 player->SetFocus();
945
946 // Save window state to disk now. Don't wait around for a crash.
947 if( Pgm().GetCommonSettings()->m_Session.remember_open_files
948 && !player->GetCurrentFileName().IsEmpty()
949 && Prj().GetLocalSettings().ShouldAutoSave() )
950 {
951 wxFileName rfn( player->GetCurrentFileName() );
952 rfn.MakeRelativeTo( Prj().GetProjectPath() );
953
954 WINDOW_SETTINGS windowSettings;
955 player->SaveWindowSettings( &windowSettings );
956
957 Prj().GetLocalSettings().SaveFileState( rfn.GetFullPath(), &windowSettings, true );
958 Prj().GetLocalSettings().SaveToFile( Prj().GetProjectPath() );
959 }
960
961 return 0;
962}
963
964
966{
967 wxString execFile;
968 wxString param;
969
971 execFile = GERBVIEW_EXE;
973 execFile = BITMAPCONVERTER_EXE;
975 execFile = PCB_CALCULATOR_EXE;
977 execFile = PL_EDITOR_EXE;
979 execFile = Pgm().GetTextEditor();
981 execFile = EESCHEMA_EXE;
983 execFile = PCBNEW_EXE;
984 else
985 wxFAIL_MSG( "Execute(): unexpected request" );
986
987 if( execFile.IsEmpty() )
988 return 0;
989
990 if( aEvent.Parameter<wxString*>() )
991 param = *aEvent.Parameter<wxString*>();
992 else if( aEvent.IsAction( &KICAD_MANAGER_ACTIONS::viewGerbers ) && m_frame->IsProjectActive() )
993 param = m_frame->Prj().GetProjectPath();
994
995 COMMON_CONTROL* commonControl = m_toolMgr->GetTool<COMMON_CONTROL>();
996 return commonControl->Execute( execFile, param );
997}
998
999
1001{
1003 {
1004 // policy disables the plugin manager
1005 return 0;
1006 }
1007
1008 // For some reason, after a click or a double click the bitmap button calling
1009 // PCM keeps the focus althougt the focus was not set to this button.
1010 // This hack force removing the focus from this button
1011 m_frame->SetFocus();
1012 wxSafeYield();
1013
1014 if( !m_frame->GetPcm() )
1015 m_frame->CreatePCM();
1016
1017 DIALOG_PCM pcm( m_frame, m_frame->GetPcm() );
1018 pcm.ShowModal();
1019
1020 const std::unordered_set<PCM_PACKAGE_TYPE>& changed = pcm.GetChangedPackageTypes();
1021
1022 if( changed.count( PCM_PACKAGE_TYPE::PT_PLUGIN ) || changed.count( PCM_PACKAGE_TYPE::PT_FAB ) )
1023 {
1024 std::string payload = "";
1025 m_frame->Kiway().ExpressMail( FRAME_PCB_EDITOR, MAIL_RELOAD_PLUGINS, payload );
1026 }
1027
1028 KICAD_SETTINGS* settings = GetAppSettings<KICAD_SETTINGS>( "kicad" );
1029
1030 if( changed.count( PCM_PACKAGE_TYPE::PT_LIBRARY )
1031 && ( settings->m_PcmLibAutoAdd || settings->m_PcmLibAutoRemove ) )
1032 {
1033 // Reset project tables
1035 Prj().SetElem( PROJECT::ELEM::FPTBL, nullptr );
1037
1038 KIWAY& kiway = m_frame->Kiway();
1039
1040 // Reset state containing global lib tables
1041 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_SCH, false ) )
1042 kiface->Reset();
1043
1044 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_PCB, false ) )
1045 kiface->Reset();
1046
1047 // Reload lib tables
1048 std::string payload = "";
1049
1052 kiway.ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload );
1054 kiway.ExpressMail( FRAME_SCH_VIEWER, MAIL_RELOAD_LIB, payload );
1055 }
1056
1057 if( changed.count( PCM_PACKAGE_TYPE::PT_COLORTHEME ) )
1059
1060 return 0;
1061}
1062
1063
1065{
1076
1080
1083
1093
1096
1098}
static TOOL_ACTION zoomRedraw
Definition actions.h:131
static TOOL_ACTION saveAs
Definition actions.h:59
static TOOL_ACTION updateMenu
Definition actions.h:271
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()
virtual bool LoadFromFile(const wxString &aDirectory="")
Loads the backing file from disk and then calls Load()
static TOOL_ACTION viewDroppedGerbers
static TOOL_ACTION openDemoProject
static TOOL_ACTION unarchiveProject
static TOOL_ACTION loadProject
static TOOL_ACTION editOtherPCB
static TOOL_ACTION newProject
static TOOL_ACTION editOtherSch
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 ArchiveProject(const TOOL_EVENT &aEvent)
bool m_inShowPlayer
Re-entrancy guard.
int SaveProjectAs(const TOOL_EVENT &aEvent)
int NewProject(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)
The main KiCad project manager frame.
wxSize m_TemplateWindowSize
wxPoint m_TemplateWindowPos
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
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:286
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition kiway.cpp:198
@ FACE_SCH
eeschema DSO
Definition kiway.h:293
@ FACE_PL_EDITOR
Definition kiway.h:297
@ FACE_PCB
pcbnew DSO
Definition kiway.h:294
@ FACE_GERBVIEW
Definition kiway.h:296
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr)
Send aPayload to aDestination from aSource.
Definition kiway.cpp:499
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition paths.cpp:136
static wxString GetStockDemosPath()
Gets the stock (install) demos path.
Definition paths.cpp:408
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition pgm_base.cpp:822
virtual const wxString & GetTextEditor(bool aCanShowFileChooser=true)
Return the path to the preferred text editor application.
Definition pgm_base.cpp:204
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:125
static bool Archive(const wxString &aSrcDir, const wxString &aDestFile, REPORTER &aReporter, bool aVerbose=true, bool aIncludeExtraFiles=false)
Create an archive of the project.
The backing store for a PROJECT, in JSON format.
bool SaveAs(const wxString &aDirectory, const wxString &aFile)
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Calls Store() and then writes the contents of the JSON document to a file.
The project local settings are things that are attached to a particular project, but also might be pa...
bool SaveAs(const wxString &aDirectory, const wxString &aFile)
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.
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
KIGIT_COMMON * GitCommon() const
virtual void SetElem(PROJECT::ELEM aIndex, _ELEM *aElem)
Definition project.cpp:375
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:174
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition project.h:210
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:204
@ SYMBOL_LIB_TABLE
Definition project.h:77
@ DESIGN_BLOCK_LIB_TABLE
Definition project.h:80
KICAD_MANAGER_FRAME * m_frame
virtual wxDirTraverseResult OnFile(const wxString &aSrcFilePath) override
SAVE_AS_TRAVERSER(KICAD_MANAGER_FRAME *aFrame, const wxString &aSrcProjectDirPath, const wxString &aSrcProjectName, const wxString &aNewProjectDirPath, const wxString &aNewProjectName)
virtual wxDirTraverseResult OnDir(const wxString &aSrcDirPath) override
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:297
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:220
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 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.
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:251
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:222
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:194
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
void KiCopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
Definition gestfich.cpp:290
static const std::string LegacySchematicFileExtension
static const std::string NetlistFileExtension
static const std::string SymbolLibraryTableFileName
static const std::string GerberJobFileExtension
static const std::string LockFileExtension
static const std::string ProjectFileExtension
static const std::string LegacyPcbFileExtension
static const std::string SchematicSymbolFileExtension
static const std::string LegacyProjectFileExtension
static const std::string ProjectLocalSettingsFileExtension
static const std::string KiCadSchematicFileExtension
static const std::string LegacySymbolLibFileExtension
static const std::string LockFilePrefix
static const std::string KiCadSymbolLibFileExtension
static const std::string FootprintLibraryTableFileName
static const std::string DrawingSheetFileExtension
static const std::string BackupFileSuffix
static const std::string LegacyFootprintLibPathExtension
static const std::string LegacySymbolDocumentFileExtension
static const std::string FootprintAssignmentFileExtension
static const std::string DrillFileExtension
static const std::string KiCadFootprintFileExtension
static const std::string ArchiveFileExtension
static const std::string KiCadPcbFileExtension
static wxString ProjectFileWildcard()
static bool IsGerberFileExtension(const wxString &ext)
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:612
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:58
@ MAIL_RELOAD_LIB
Definition mail_type.h:57
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)
@ PT_COLORTHEME
Definition pcm_data.h:47
@ 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.
Definition pgm_base.cpp:913
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)
#define PROJECT_BACKUPS_DIR_SUFFIX
Project settings path will be <projectname> + this.
Implement a participant in the KIWAY alchemy.
Definition kiway.h:153
virtual void SaveFileAs(const wxString &srcProjectBasePath, const wxString &srcProjectName, const wxString &newProjectBasePath, const wxString &newProjectName, const wxString &srcFilePath, wxString &aErrors)
Saving a file under a different name is delegated to the various KIFACEs because the project doesn't ...
Definition kiway.h:218
Store the common settings that are saved and loaded for each window / frame.
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.
Definition of file extensions used in Kicad.
#define PR_NO_ABORT