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>
45#include <gestfich.h>
46#include <paths.h>
47#include <wx/dir.h>
48#include <wx/filedlg.h>
50#include "dialog_pcm.h"
51
53
55 TOOL_INTERACTIVE( "kicad.Control" ),
56 m_frame( nullptr )
57{
58}
59
60
62{
63 m_frame = getEditFrame<KICAD_MANAGER_FRAME>();
64}
65
66
67wxFileName KICAD_MANAGER_CONTROL::newProjectDirectory( wxString* aFileName, bool isRepo )
68{
69 wxString default_filename = aFileName ? *aFileName : wxString();
70
71 wxString default_dir = m_frame->GetMruPath();
72 wxFileDialog dlg( m_frame, _( "Create New Project" ), default_dir, default_filename,
73 ( isRepo ? wxString( "" ) : FILEEXT::ProjectFileWildcard() ),
74 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
75
76 // Add a "Create a new directory" checkbox
77 FILEDLG_NEW_PROJECT newProjectHook;
78 dlg.SetCustomizeHook( newProjectHook );
79
80 if( dlg.ShowModal() == wxID_CANCEL )
81 return wxFileName();
82
83 wxFileName pro( dlg.GetPath() );
84
85 // wxFileName automatically extracts an extension. But if it isn't
86 // a .pro extension, we should keep it as part of the filename
87 if( !pro.GetExt().IsEmpty() && pro.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
88 pro.SetName( pro.GetName() + wxT( "." ) + pro.GetExt() );
89
90 pro.SetExt( FILEEXT::ProjectFileExtension ); // enforce extension
91
92 if( !pro.IsAbsolute() )
93 pro.MakeAbsolute();
94
95 // Append a new directory with the same name of the project file.
96 bool createNewDir = false;
97
98 createNewDir = newProjectHook.GetCreateNewDir();
99
100 if( createNewDir )
101 pro.AppendDir( pro.GetName() );
102
103 // Check if the project directory is empty if it already exists.
104 wxDir directory( pro.GetPath() );
105
106 if( !pro.DirExists() )
107 {
108 if( !pro.Mkdir() )
109 {
110 wxString msg;
111 msg.Printf( _( "Folder '%s' could not be created.\n\n"
112 "Make sure you have write permissions and try again." ),
113 pro.GetPath() );
115 return wxFileName();
116 }
117 }
118 else if( directory.HasFiles() )
119 {
120 wxString msg = _( "The selected folder is not empty. It is recommended that you "
121 "create projects in their own empty folder.\n\n"
122 "Do you want to continue?" );
123
124 if( !IsOK( m_frame, msg ) )
125 return wxFileName();
126 }
127
128 return pro;
129}
130
131
133{
134
135 wxFileName pro = newProjectDirectory();
136
137 if( !pro.IsOk() )
138 return -1;
139
141 m_frame->LoadProject( pro );
142
143 return 0;
144}
145
146
148{
149 DIALOG_GIT_REPOSITORY dlg( m_frame, nullptr );
150
151 dlg.SetTitle( _( "Clone Project from Git Repository" ) );
152
153 int ret = dlg.ShowModal();
154
155 if( ret != wxID_OK )
156 return -1;
157
158 wxString project_name = dlg.GetRepoName();
159 wxFileName pro = newProjectDirectory( &project_name, true );
160
161 if( !pro.IsOk() )
162 return -1;
163
164 GIT_CLONE_HANDLER cloneHandler;
165
166 cloneHandler.SetURL( dlg.GetRepoURL() );
167 cloneHandler.SetClonePath( pro.GetPath() );
168 cloneHandler.SetConnType( dlg.GetRepoType() );
169 cloneHandler.SetUsername( dlg.GetUsername() );
170 cloneHandler.SetPassword( dlg.GetPassword() );
171 cloneHandler.SetSSHKey( dlg.GetRepoSSHPath() );
172
173 cloneHandler.SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>( m_frame, _( "Cloning Repository" ), 1 ) );
174
175 if( !cloneHandler.PerformClone() )
176 {
177 DisplayErrorMessage( m_frame, cloneHandler.GetErrorString() );
178 return -1;
179 }
180
181 std::vector<wxString> projects = cloneHandler.GetProjectDirs();
182
183 if( projects.empty() )
184 {
185 DisplayErrorMessage( m_frame, _( "No project files were found in the repository." ) );
186 return -1;
187 }
188
189 // Currently, we pick the first project file we find in the repository.
190 // TODO: Look into spare checkout to allow the user to pick a partial repository
191 wxString dest = pro.GetPath() + wxFileName::GetPathSeparator() + projects.front();
192 m_frame->LoadProject( dest );
193
197
201 Prj().GetLocalSettings().m_GitRepoType = "https";
202 else
203 Prj().GetLocalSettings().m_GitRepoType = "local";
204
205 return 0;
206}
207
208
210{
211 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
212 wxFileDialog dlg( m_frame, _( "Create New Jobset" ), default_dir, wxEmptyString,
214 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
215
216 if( dlg.ShowModal() == wxID_CANCEL )
217 return -1;
218
219 wxFileName jobsetFn( dlg.GetPath() );
220
221 m_frame->OpenJobsFile( jobsetFn.GetFullPath(), true );
222
223 return 0;
224}
225
226
228{
230 KICAD_SETTINGS* settings = mgr.GetAppSettings<KICAD_SETTINGS>( "kicad" );
231 std::map<wxString, wxFileName> titleDirMap;
232
233 wxFileName templatePath;
234
235 // KiCad system template path.
236 std::optional<wxString> v = ENV_VAR::GetVersionedEnvVarValue( Pgm().GetLocalEnvVariables(),
237 wxT( "TEMPLATE_DIR" ) );
238
239 if( v && !v->IsEmpty() )
240 {
241 templatePath.AssignDir( *v );
242 titleDirMap.emplace( _( "System Templates" ), templatePath );
243 }
244
245 // User template path.
246 ENV_VAR_MAP_CITER it = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
247
248 if( it != Pgm().GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString )
249 {
250 templatePath.AssignDir( it->second.GetValue() );
251 titleDirMap.emplace( _( "User Templates" ), templatePath );
252 }
253
255 settings->m_TemplateWindowSize, titleDirMap );
256
257 // Show the project template selector dialog
258 int result = ps.ShowModal();
259
260 settings->m_TemplateWindowPos = ps.GetPosition();
261 settings->m_TemplateWindowSize = ps.GetSize();
262
263 if( result != wxID_OK )
264 return -1;
265
266 if( !ps.GetSelectedTemplate() )
267 {
268 wxMessageBox( _( "No project template was selected. Cannot generate new project." ),
269 _( "Error" ), wxOK | wxICON_ERROR, m_frame );
270
271 return -1;
272 }
273
274 // Get project destination folder and project file name.
275 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
276 wxString title = _( "New Project Folder" );
277 wxFileDialog dlg( m_frame, title, default_dir, wxEmptyString, FILEEXT::ProjectFileWildcard(),
278 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
279
280 // Add a "Create a new directory" checkbox
281 FILEDLG_NEW_PROJECT newProjectHook;
282 dlg.SetCustomizeHook( newProjectHook );
283
284 if( dlg.ShowModal() == wxID_CANCEL )
285 return -1;
286
287 wxFileName fn( dlg.GetPath() );
288
289 // wxFileName automatically extracts an extension. But if it isn't a .kicad_pro extension,
290 // we should keep it as part of the filename
291 if( !fn.GetExt().IsEmpty() && fn.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
292 fn.SetName( fn.GetName() + wxT( "." ) + fn.GetExt() );
293
295
296 if( !fn.IsAbsolute() )
297 fn.MakeAbsolute();
298
299 bool createNewDir = false;
300 createNewDir = newProjectHook.GetCreateNewDir();
301
302 // Append a new directory with the same name of the project file.
303 if( createNewDir )
304 fn.AppendDir( fn.GetName() );
305
306 // Check if the project directory is empty if it already exists.
307
308 if( !fn.DirExists() )
309 {
310 if( !fn.Mkdir() )
311 {
312 wxString msg;
313 msg.Printf( _( "Folder '%s' could not be created.\n\n"
314 "Make sure you have write permissions and try again." ),
315 fn.GetPath() );
317 return -1;
318 }
319 }
320
321 if( !fn.IsDirWritable() )
322 {
323 wxString msg;
324
325 msg.Printf( _( "Insufficient permissions to write to folder '%s'." ), fn.GetPath() );
326 wxMessageDialog msgDlg( m_frame, msg, _( "Error" ), wxICON_ERROR | wxOK | wxCENTER );
327 msgDlg.ShowModal();
328 return -1;
329 }
330
331 // Make sure we are not overwriting anything in the destination folder.
332 std::vector< wxFileName > destFiles;
333
334 if( ps.GetSelectedTemplate()->GetDestinationFiles( fn, destFiles ) )
335 {
336 std::vector<wxFileName> overwrittenFiles;
337
338 for( const wxFileName& file : destFiles )
339 {
340 if( file.FileExists() )
341 overwrittenFiles.push_back( file );
342 }
343
344 if( !overwrittenFiles.empty() )
345 {
346 wxString extendedMsg = _( "Overwriting files:" ) + "\n";
347
348 for( const wxFileName& file : overwrittenFiles )
349 extendedMsg += "\n" + file.GetFullName();
350
351 KIDIALOG msgDlg( m_frame,
352 _( "Similar files already exist in the destination folder." ),
353 _( "Confirmation" ),
354 wxOK | wxCANCEL | wxICON_WARNING );
355 msgDlg.SetExtendedMessage( extendedMsg );
356 msgDlg.SetOKLabel( _( "Overwrite" ) );
357 msgDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
358
359 if( msgDlg.ShowModal() == wxID_CANCEL )
360 return -1;
361 }
362 }
363
364 wxString errorMsg;
365
366 // The selected template widget contains the template we're attempting to use to
367 // create a project
368 if( !ps.GetSelectedTemplate()->CreateProject( fn, &errorMsg ) )
369 {
370 wxMessageDialog createDlg( m_frame,
371 _( "A problem occurred creating new project from template." ),
372 _( "Error" ),
373 wxOK | wxICON_ERROR );
374
375 if( !errorMsg.empty() )
376 createDlg.SetExtendedMessage( errorMsg );
377
378 createDlg.ShowModal();
379 return -1;
380 }
381
382 m_frame->CreateNewProject( fn.GetFullPath() );
383 m_frame->LoadProject( fn );
384 return 0;
385}
386
387
388int KICAD_MANAGER_CONTROL::openProject( const wxString& aDefaultDir )
389{
390 wxString wildcard = FILEEXT::AllProjectFilesWildcard()
393
394 wxFileDialog dlg( m_frame, _( "Open Existing Project" ), aDefaultDir, wxEmptyString, wildcard,
395 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
396
397 if( dlg.ShowModal() == wxID_CANCEL )
398 return -1;
399
400 wxFileName pro( dlg.GetPath() );
401
402 if( !pro.IsAbsolute() )
403 pro.MakeAbsolute();
404
405 if( !pro.FileExists() )
406 return -1;
407
408 m_frame->LoadProject( pro );
409
410 return 0;
411}
412
413
415{
417}
418
419
421{
422 return openProject( m_frame->GetMruPath() );
423}
424
425
427{
428 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
429 wxFileDialog dlg( m_frame, _( "Open Jobset" ), default_dir, wxEmptyString,
430 FILEEXT::JobsetFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
431
432 if( dlg.ShowModal() == wxID_CANCEL )
433 return -1;
434
435 wxFileName jobsetFn( dlg.GetPath() );
436
437 m_frame->OpenJobsFile( jobsetFn.GetFullPath(), true );
438
439 return 0;
440}
441
442
444{
445 m_frame->CloseProject( true );
446 return 0;
447}
448
449
451{
452 if( aEvent.Parameter<wxString*>() )
453 m_frame->LoadProject( wxFileName( *aEvent.Parameter<wxString*>() ) );
454 return 0;
455}
456
458{
459 if( aEvent.Parameter<wxString*>() )
460 wxExecute( *aEvent.Parameter<wxString*>(), wxEXEC_ASYNC );
461 return 0;
462}
463
464class SAVE_AS_TRAVERSER : public wxDirTraverser
465{
466public:
468 const wxString& aSrcProjectDirPath,
469 const wxString& aSrcProjectName,
470 const wxString& aNewProjectDirPath,
471 const wxString& aNewProjectName ) :
472 m_frame( aFrame ),
473 m_projectDirPath( aSrcProjectDirPath ),
474 m_projectName( aSrcProjectName ),
475 m_newProjectDirPath( aNewProjectDirPath ),
476 m_newProjectName( aNewProjectName )
477 {
478 }
479
480 virtual wxDirTraverseResult OnFile( const wxString& aSrcFilePath ) override
481 {
482 // Recursion guard for a Save As to a location inside the source project.
483 if( aSrcFilePath.StartsWith( m_newProjectDirPath + wxFileName::GetPathSeparator() ) )
484 return wxDIR_CONTINUE;
485
486 wxFileName destFile( aSrcFilePath );
487 wxString ext = destFile.GetExt();
488 bool atRoot = destFile.GetPath() == m_projectDirPath;
489
493 {
494 wxString destPath = destFile.GetPath();
495
496 if( destPath.StartsWith( m_projectDirPath ) )
497 {
498 destPath.Replace( m_projectDirPath, m_newProjectDirPath, false );
499 destFile.SetPath( destPath );
500 }
501
502 if( destFile.GetName() == m_projectName )
503 {
504 destFile.SetName( m_newProjectName );
505
506 if( atRoot && ext != FILEEXT::ProjectLocalSettingsFileExtension )
507 m_newProjectFile = destFile;
508 }
509
511 {
512 // All paths in the settings file are relative so we can just do a straight copy
513 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), m_errors );
514 }
515 else if( ext == FILEEXT::ProjectFileExtension )
516 {
517 PROJECT_FILE projectFile( aSrcFilePath );
518 projectFile.LoadFromFile();
519 projectFile.SaveAs( destFile.GetPath(), destFile.GetName() );
520 }
522 {
523 PROJECT_LOCAL_SETTINGS projectLocalSettings( nullptr, aSrcFilePath );
524 projectLocalSettings.LoadFromFile();
525 projectLocalSettings.SaveAs( destFile.GetPath(), destFile.GetName() );
526 }
527 }
537 || destFile.GetName() == FILEEXT::SymbolLibraryTableFileName )
538 {
541 m_newProjectName, aSrcFilePath, m_errors );
542 }
543 else if( ext == FILEEXT::KiCadPcbFileExtension
549 || destFile.GetName() == FILEEXT::FootprintLibraryTableFileName )
550 {
553 m_newProjectName, aSrcFilePath, m_errors );
554 }
555 else if( ext == FILEEXT::DrawingSheetFileExtension )
556 {
559 m_newProjectName, aSrcFilePath, m_errors );
560 }
561 else if( ext == FILEEXT::GerberJobFileExtension
564 {
567 m_newProjectName, aSrcFilePath, m_errors );
568 }
569 else if( destFile.GetName().StartsWith( FILEEXT::LockFilePrefix )
571 {
572 // Ignore lock files
573 }
574 else
575 {
576 // Everything we don't recognize just gets a straight copy.
577 wxString destPath = destFile.GetPathWithSep();
578 wxString destName = destFile.GetName();
579 wxUniChar pathSep = wxFileName::GetPathSeparator();
580
581 wxString srcProjectFootprintLib = pathSep + m_projectName + ".pretty" + pathSep;
582 wxString newProjectFootprintLib = pathSep + m_newProjectName + ".pretty" + pathSep;
583
584 if( destPath.StartsWith( m_projectDirPath ) )
585 destPath.Replace( m_projectDirPath, m_newProjectDirPath, false );
586
587 destPath.Replace( srcProjectFootprintLib, newProjectFootprintLib, true );
588
589 if( destName == m_projectName && ext != wxT( "zip" ) /* don't rename archives */ )
590 destFile.SetName( m_newProjectName );
591
592 destFile.SetPath( destPath );
593
594 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), m_errors );
595 }
596
597 return wxDIR_CONTINUE;
598 }
599
600 virtual wxDirTraverseResult OnDir( const wxString& aSrcDirPath ) override
601 {
602 // Recursion guard for a Save As to a location inside the source project.
603 if( aSrcDirPath.StartsWith( m_newProjectDirPath ) )
604 return wxDIR_CONTINUE;
605
606 wxFileName destDir( aSrcDirPath );
607 wxString destDirPath = destDir.GetPathWithSep();
608 wxUniChar pathSep = wxFileName::GetPathSeparator();
609
610 if( destDirPath.StartsWith( m_projectDirPath + pathSep )
611 || destDirPath.StartsWith( m_projectDirPath + PROJECT_BACKUPS_DIR_SUFFIX ) )
612 {
613 destDirPath.Replace( m_projectDirPath, m_newProjectDirPath, false );
614 destDir.SetPath( destDirPath );
615 }
616
617 if( destDir.GetName() == m_projectName )
618 {
619 if( destDir.GetExt() == "pretty" )
620 destDir.SetName( m_newProjectName );
621#if 0
622 // WAYNE STAMBAUGH TODO:
623 // If we end up with a symbol equivalent to ".pretty" we'll want to handle it here....
624 else if( destDir.GetExt() == "sym_lib_dir_extension" )
625 destDir.SetName( m_newProjectName );
626#endif
627 }
628
629 if( !wxMkdir( destDir.GetFullPath() ) )
630 {
631 wxString msg;
632
633 if( !m_errors.empty() )
634 m_errors += "\n";
635
636 msg.Printf( _( "Cannot copy folder '%s'." ), destDir.GetFullPath() );
637 m_errors += msg;
638 }
639
640 return wxDIR_CONTINUE;
641 }
642
643 wxString GetErrors() { return m_errors; }
644
645 wxFileName GetNewProjectFile() { return m_newProjectFile; }
646
647private:
649
654
656 wxString m_errors;
657};
658
659
661{
662 wxString msg;
663
664 wxFileName currentProjectFile( Prj().GetProjectFullName() );
665 wxString currentProjectDirPath = currentProjectFile.GetPath();
666 wxString currentProjectName = Prj().GetProjectName();
667
668 wxString default_dir = m_frame->GetMruPath();
669
670 Prj().GetProjectFile().SaveToFile( currentProjectDirPath );
671 Prj().GetLocalSettings().SaveToFile( currentProjectDirPath );
672
673 if( default_dir == currentProjectDirPath
674 || default_dir == currentProjectDirPath + wxFileName::GetPathSeparator() )
675 {
676 // Don't start within the current project
677 wxFileName default_dir_fn( default_dir );
678 default_dir_fn.RemoveLastDir();
679 default_dir = default_dir_fn.GetPath();
680 }
681
682 wxFileDialog dlg( m_frame, _( "Save Project To" ), default_dir, wxEmptyString, wxEmptyString,
683 wxFD_SAVE );
684
685 if( dlg.ShowModal() == wxID_CANCEL )
686 return -1;
687
688 wxFileName newProjectDir( dlg.GetPath(), wxEmptyString );
689
690 if( !newProjectDir.IsAbsolute() )
691 newProjectDir.MakeAbsolute();
692
693 if( wxDirExists( newProjectDir.GetFullPath() ) )
694 {
695 msg.Printf( _( "'%s' already exists." ), newProjectDir.GetFullPath() );
697 return -1;
698 }
699
700 if( !wxMkdir( newProjectDir.GetFullPath() ) )
701 {
702 msg.Printf( _( "Folder '%s' could not be created.\n\n"
703 "Please make sure you have write permissions and try again." ),
704 newProjectDir.GetPath() );
706 return -1;
707 }
708
709 if( !newProjectDir.IsDirWritable() )
710 {
711 msg.Printf( _( "Insufficient permissions to write to folder '%s'." ),
712 newProjectDir.GetFullPath() );
713 wxMessageDialog msgDlg( m_frame, msg, _( "Error!" ), wxICON_ERROR | wxOK | wxCENTER );
714 msgDlg.ShowModal();
715 return -1;
716 }
717
718 const wxString& newProjectDirPath = newProjectDir.GetFullPath();
719 const wxString& newProjectName = newProjectDir.GetDirs().Last();
720 wxDir currentProjectDir( currentProjectDirPath );
721
722 SAVE_AS_TRAVERSER traverser( m_frame, currentProjectDirPath, currentProjectName,
723 newProjectDirPath, newProjectName );
724
725 currentProjectDir.Traverse( traverser );
726
727 if( !traverser.GetErrors().empty() )
728 DisplayErrorMessage( m_frame, traverser.GetErrors() );
729
730 if( !traverser.GetNewProjectFile().FileExists() )
732
733 m_frame->LoadProject( traverser.GetNewProjectFile() );
734
735 return 0;
736}
737
738
740{
742 return 0;
743}
744
745
747{
748 ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
749 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
750 SELECTION dummySel;
751
752 if( conditionalMenu )
753 conditionalMenu->Evaluate( dummySel );
754
755 if( actionMenu )
756 actionMenu->UpdateAll();
757
758 return 0;
759}
760
761
763{
764 FRAME_T playerType = aEvent.Parameter<FRAME_T>();
765 KIWAY_PLAYER* player;
766
767 if( playerType == FRAME_SCH && !m_frame->IsProjectActive() )
768 {
769 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a schematic." ),
770 wxEmptyString );
771 return -1;
772 }
773 else if( playerType == FRAME_PCB_EDITOR && !m_frame->IsProjectActive() )
774 {
775 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a pcb." ),
776 wxEmptyString );
777 return -1;
778 }
779
780 // Prevent multiple KIWAY_PLAYER loading at one time
781 if( !m_loading.try_lock() )
782 return -1;
783
784 const std::lock_guard<std::mutex> lock( m_loading, std::adopt_lock );
785
786 try
787 {
788 player = m_frame->Kiway().Player( playerType, true );
789 }
790 catch( const IO_ERROR& err )
791 {
792 wxLogError( _( "Application failed to load:\n" ) + err.What() );
793 return -1;
794 }
795
796 if ( !player )
797 {
798 wxLogError( _( "Application cannot start." ) );
799 return -1;
800 }
801
802 if( !player->IsVisible() ) // A hidden frame might not have the document loaded.
803 {
804 wxString filepath;
805
806 if( playerType == FRAME_SCH )
807 {
808 wxFileName kicad_schematic( m_frame->SchFileName() );
809 wxFileName legacy_schematic( m_frame->SchLegacyFileName() );
810
811 if( !legacy_schematic.FileExists() || kicad_schematic.FileExists() )
812 filepath = kicad_schematic.GetFullPath();
813 else
814 filepath = legacy_schematic.GetFullPath();
815 }
816 else if( playerType == FRAME_PCB_EDITOR )
817 {
818 wxFileName kicad_board( m_frame->PcbFileName() );
819 wxFileName legacy_board( m_frame->PcbLegacyFileName() );
820
821 if( !legacy_board.FileExists() || kicad_board.FileExists() )
822 filepath = kicad_board.GetFullPath();
823 else
824 filepath = legacy_board.GetFullPath();
825 }
826
827 if( !filepath.IsEmpty() )
828 {
829 std::vector<wxString> file_list{ filepath };
830
831 if( !player->OpenProjectFiles( file_list ) )
832 {
833 player->Destroy();
834 return -1;
835 }
836 }
837
838 wxBusyCursor busy;
839 player->Show( true );
840 }
841
842 // Needed on Windows, other platforms do not use it, but it creates no issue
843 if( player->IsIconized() )
844 player->Iconize( false );
845
846 player->Raise();
847
848 // Raising the window does not set the focus on Linux. This should work on
849 // any platform.
850 if( wxWindow::FindFocus() != player )
851 player->SetFocus();
852
853 // Save window state to disk now. Don't wait around for a crash.
854 if( Pgm().GetCommonSettings()->m_Session.remember_open_files
855 && !player->GetCurrentFileName().IsEmpty()
856 && !Prj().GetLocalSettings().WasMigrated() )
857 {
858 wxFileName rfn( player->GetCurrentFileName() );
859 rfn.MakeRelativeTo( Prj().GetProjectPath() );
860
861 WINDOW_SETTINGS windowSettings;
862 player->SaveWindowSettings( &windowSettings );
863
864 Prj().GetLocalSettings().SaveFileState( rfn.GetFullPath(), &windowSettings, true );
865 Prj().GetLocalSettings().SaveToFile( Prj().GetProjectPath() );
866 }
867
868 return 0;
869}
870
871
872class TERMINATE_HANDLER : public wxProcess
873{
874public:
875 TERMINATE_HANDLER( const wxString& appName )
876 { }
877
878 void OnTerminate( int pid, int status ) override
879 {
880 delete this;
881 }
882};
883
884
886{
887 wxString execFile;
888 wxString param;
889
891 execFile = GERBVIEW_EXE;
893 execFile = BITMAPCONVERTER_EXE;
895 execFile = PCB_CALCULATOR_EXE;
897 execFile = PL_EDITOR_EXE;
899 execFile = Pgm().GetTextEditor();
901 execFile = EESCHEMA_EXE;
903 execFile = PCBNEW_EXE;
904 else
905 wxFAIL_MSG( "Execute(): unexpected request" );
906
907 if( execFile.IsEmpty() )
908 return 0;
909
910 if( aEvent.Parameter<wxString*>() )
911 param = *aEvent.Parameter<wxString*>();
913 param = m_frame->Prj().GetProjectPath();
914
915 TERMINATE_HANDLER* callback = new TERMINATE_HANDLER( execFile );
916
917 long pid = ExecuteFile( execFile, param, callback );
918
919 if( pid > 0 )
920 {
921#ifdef __WXMAC__
922 wxString script = wxString::Format( wxS( "tell application \"System Events\"\n"
923 " set frontmost of the first process whose unix id is %l to true\n"
924 "end tell" ), pid );
925
926 // This non-parameterized use of wxExecute is fine because script is not derived
927 // from user input.
928 wxExecute( wxString::Format( "osascript -e '%s'", script ) );
929#endif
930 }
931 else
932 {
933 delete callback;
934 }
935
936 return 0;
937}
938
939
941{
944 {
945 // policy disables the plugin manager
946 return 0;
947 }
948
949 // For some reason, after a click or a double click the bitmap button calling
950 // PCM keeps the focus althougt the focus was not set to this button.
951 // This hack force removing the focus from this button
952 m_frame->SetFocus();
953 wxSafeYield();
954
955 if( !m_frame->GetPcm() )
957
958 DIALOG_PCM pcm( m_frame, m_frame->GetPcm() );
959 pcm.ShowModal();
960
961 const std::unordered_set<PCM_PACKAGE_TYPE>& changed = pcm.GetChangedPackageTypes();
962
963 if( changed.count( PCM_PACKAGE_TYPE::PT_PLUGIN ) || changed.count( PCM_PACKAGE_TYPE::PT_FAB ) )
964 {
965 std::string payload = "";
967 }
968
970 KICAD_SETTINGS* settings = mgr.GetAppSettings<KICAD_SETTINGS>( "kicad" );
971
972 if( changed.count( PCM_PACKAGE_TYPE::PT_LIBRARY )
973 && ( settings->m_PcmLibAutoAdd || settings->m_PcmLibAutoRemove ) )
974 {
975 // Reset project tables
977 Prj().SetElem( PROJECT::ELEM::FPTBL, nullptr );
979
980 KIWAY& kiway = m_frame->Kiway();
981
982 // Reset state containing global lib tables
983 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_SCH, false ) )
984 kiface->Reset();
985
986 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_PCB, false ) )
987 kiface->Reset();
988
989 // Reload lib tables
990 std::string payload = "";
991
994 kiway.ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload );
997 }
998
999 if( changed.count( PCM_PACKAGE_TYPE::PT_COLORTHEME ) )
1001
1002 return 0;
1003}
1004
1005
1007{
1019
1022
1032
1035
1037}
static TOOL_ACTION zoomRedraw
Definition: actions.h:124
static TOOL_ACTION saveAs
Definition: actions.h:52
static TOOL_ACTION updateMenu
Definition: actions.h:220
Define the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
void UpdateAll()
Run update handlers for the menu and its submenus.
KIGIT_COMMON::GIT_CONN_TYPE GetRepoType() const
wxString GetRepoSSHPath() const
wxString GetUsername() const
wxString GetRepoName() const
wxString GetPassword() const
Implementing pcm main dialog.
Definition: dialog_pcm.h:36
const std::unordered_set< PCM_PACKAGE_TYPE > & GetChangedPackageTypes() const
Definition: dialog_pcm.h:77
int ShowModal() override
PROJECT_TEMPLATE * GetSelectedTemplate()
wxString GetMruPath() const
bool GetCreateNewDir() const
void SetURL(const wxString &aURL)
void SetClonePath(const wxString &aPath)
void SetProgressReporter(std::unique_ptr< WX_PROGRESS_REPORTER > aProgressReporter)
Definition: git_progress.h:40
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
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 editPCB
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 openProject
static TOOL_ACTION closeProject
static TOOL_ACTION convertImage
static TOOL_ACTION editDrawingSheet
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 newFromTemplate
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 SaveProjectAs(const TOOL_EVENT &aEvent)
int NewProject(const TOOL_EVENT &aEvent)
int ViewDroppedViewers(const TOOL_EVENT &aEvent)
Imports a non kicad project from a sch/pcb dropped file.
int NewFromTemplate(const TOOL_EVENT &aEvent)
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 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.
void CreateNewProject(const wxFileName &aProjectFileName, bool aCreateStubFiles=true)
Creates a new project by setting up and initial project, schematic, and board files.
const wxString SchLegacyFileName()
const wxString SchFileName()
void OpenJobsFile(const wxFileName &aFileName, bool aCreate=false, bool aResaveProjectPreferences=true)
void LoadProject(const wxFileName &aProjectFileName)
std::shared_ptr< PLUGIN_CONTENT_MANAGER > GetPcm()
const wxString PcbLegacyFileName()
bool CloseProject(bool aSave)
Closes the project, and saves it if aSave is true;.
const wxString PcbFileName()
wxSize m_TemplateWindowSize
wxPoint m_TemplateWindowPos
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: kidialog.h:43
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition: kidialog.cpp:51
int ShowModal() override
Definition: kidialog.cpp:95
virtual void Reset() override
Reloads global state.
Definition: kiface_base.h:55
void SetConnType(GIT_CONN_TYPE aConnType)
void SetSSHKey(const wxString &aSSHKey)
void SetUsername(const wxString &aUsername)
std::vector< wxString > GetProjectDirs()
Return a vector of project files in the repository.
void SetPassword(const wxString &aPassword)
wxString GetErrorString()
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:55
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:65
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:285
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:406
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition: kiway.cpp:201
@ FACE_SCH
eeschema DSO
Definition: kiway.h:292
@ FACE_PL_EDITOR
Definition: kiway.h:296
@ FACE_PCB
pcbnew DSO
Definition: kiway.h:293
@ FACE_GERBVIEW
Definition: kiway.h:295
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr)
Send aPayload to aDestination from aSource.
Definition: kiway.cpp:527
static wxString GetStockDemosPath()
Gets the stock (install) demos path.
Definition: paths.cpp:398
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.cpp:935
virtual const wxString & GetTextEditor(bool aCanShowFileChooser=true)
Return the path to the preferred text editor application.
Definition: pgm_base.cpp:196
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:125
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:72
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)
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.
virtual void SetElem(PROJECT::ELEM aIndex, _ELEM *aElem)
Definition: project.cpp:359
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:146
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition: project.cpp:158
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition: project.h:206
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:200
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
T * GetAppSettings(const wxString &aFilename)
Return a handle to the a given settings by type.
void ReloadColorSettings()
Re-scan the color themes directory, reloading any changes it finds.
void OnTerminate(int pid, int status) override
TERMINATE_HANDLER(const wxString &appName)
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
Generic, UI-independent tool event.
Definition: tool_event.h:168
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:465
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).
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:250
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:195
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
int ExecuteFile(const wxString &aEditorName, const wxString &aFileName, wxProcess *aCallback, bool aFileForKicad)
Call the executable file aEditorName with the parameter aFileName.
Definition: gestfich.cpp:143
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 KiCadPcbFileExtension
static wxString ProjectFileWildcard()
static bool IsGerberFileExtension(const wxString &ext)
static wxString JobsetFileWildcard()
static wxString LegacyProjectFileWildcard()
static wxString AllProjectFilesWildcard()
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
PROJECT & Prj()
Definition: kicad.cpp:597
This file is part of the common library.
@ MAIL_RELOAD_PLUGINS
Definition: mail_type.h:57
@ MAIL_RELOAD_LIB
Definition: mail_type.h:56
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:83
PBOOL GetPolicyBool(const wxString &aKey)
Definition: unix/policy.cpp:26
bool StoreSecret(const wxString &aService, const wxString &aKey, const wxString &aSecret)
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:1073
see class PGM_BASE
#define POLICY_KEY_PCM
Definition: policy_keys.h:31
#define PROJECT_BACKUPS_DIR_SUFFIX
Project settings path will be <projectname> + this.
Implement a participant in the KIWAY alchemy.
Definition: kiway.h:152
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:217
Store the common settings that are saved and loaded for each window / frame.
Definition: app_settings.h:74
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)
Definition of file extensions used in Kicad.