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 (C) 2019-2023 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 <policy_keys.h>
26#include <kiway.h>
27#include <kicad_manager_frame.h>
28#include <kiplatform/policy.h>
29#include <confirm.h>
30#include <eda_tools.h>
35#include <tool/selection.h>
36#include <tool/tool_event.h>
42#include <gestfich.h>
43#include <paths.h>
44#include <wx/checkbox.h>
45#include <wx/dir.h>
46#include <wx/filedlg.h>
47#include "dialog_pcm.h"
48#include <macros.h>
49#include <sch_io/sch_io_mgr.h>
50#include <pcb_io/pcb_io_mgr.h>
51#include <import_proj.h>
52
54
56 TOOL_INTERACTIVE( "kicad.Control" ),
57 m_frame( nullptr )
58{
59}
60
61
63{
64 m_frame = getEditFrame<KICAD_MANAGER_FRAME>();
65}
66
67
68wxFileName KICAD_MANAGER_CONTROL::newProjectDirectory( wxString* aFileName, bool isRepo )
69{
70 wxString default_filename = aFileName ? *aFileName : wxString();
71
72 wxString default_dir = m_frame->GetMruPath();
73 wxFileDialog dlg( m_frame, _( "Create New Project" ), default_dir, default_filename,
74 ( isRepo ? wxString( "" ) : FILEEXT::ProjectFileWildcard() ),
75 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
76
77 // Add a "Create a new directory" checkbox
78 FILEDLG_NEW_PROJECT newProjectHook;
79 dlg.SetCustomizeHook( newProjectHook );
80
81 if( dlg.ShowModal() == wxID_CANCEL )
82 return wxFileName();
83
84 wxFileName pro( dlg.GetPath() );
85
86 // wxFileName automatically extracts an extension. But if it isn't
87 // a .pro extension, we should keep it as part of the filename
88 if( !pro.GetExt().IsEmpty() && pro.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
89 pro.SetName( pro.GetName() + wxT( "." ) + pro.GetExt() );
90
91 pro.SetExt( FILEEXT::ProjectFileExtension ); // enforce extension
92
93 if( !pro.IsAbsolute() )
94 pro.MakeAbsolute();
95
96 // Append a new directory with the same name of the project file.
97 bool createNewDir = false;
98
99 createNewDir = newProjectHook.GetCreateNewDir();
100
101 if( createNewDir )
102 pro.AppendDir( pro.GetName() );
103
104 // Check if the project directory is empty if it already exists.
105 wxDir directory( pro.GetPath() );
106
107 if( !pro.DirExists() )
108 {
109 if( !pro.Mkdir() )
110 {
111 wxString msg;
112 msg.Printf( _( "Folder '%s' could not be created.\n\n"
113 "Make sure you have write permissions and try again." ),
114 pro.GetPath() );
116 return wxFileName();
117 }
118 }
119 else if( directory.HasFiles() )
120 {
121 wxString msg = _( "The selected folder is not empty. It is recommended that you "
122 "create projects in their own empty folder.\n\n"
123 "Do you want to continue?" );
124
125 if( !IsOK( m_frame, msg ) )
126 return wxFileName();
127 }
128
129 return pro;
130}
131
132
134{
135
136 wxFileName pro = newProjectDirectory();
137
138 if( !pro.IsOk() )
139 return -1;
140
142 m_frame->LoadProject( pro );
143
144 return 0;
145}
146
147
149{
150 DIALOG_GIT_REPOSITORY dlg( m_frame, nullptr );
151
152 dlg.SetTitle( _( "Clone Project from Git Repository" ) );
153
154 int ret = dlg.ShowModal();
155
156 if( ret != wxID_OK )
157 return -1;
158
159 wxString project_name = dlg.GetRepoName();
160 wxFileName pro = newProjectDirectory( &project_name, true );
161
162 if( !pro.IsOk() )
163 return -1;
164
165 GIT_CLONE_HANDLER cloneHandler;
166
167 cloneHandler.SetURL( dlg.GetRepoURL() );
168 cloneHandler.SetClonePath( pro.GetPath() );
169 cloneHandler.SetConnType( dlg.GetRepoType() );
170 cloneHandler.SetUsername( dlg.GetUsername() );
171 cloneHandler.SetPassword( dlg.GetPassword() );
172 cloneHandler.SetSSHKey( dlg.GetRepoSSHPath() );
173
174 cloneHandler.SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>( m_frame, _( "Cloning Repository" ), 1 ) );
175
176 if( !cloneHandler.PerformClone() )
177 {
178 DisplayErrorMessage( m_frame, cloneHandler.GetErrorString() );
179 return -1;
180 }
181
182 std::vector<wxString> projects = cloneHandler.GetProjectDirs();
183
184 if( projects.empty() )
185 {
186 DisplayErrorMessage( m_frame, _( "No project files were found in the repository." ) );
187 return -1;
188 }
189
190 // Currently, we pick the first project file we find in the repository.
191 // TODO: Look into spare checkout to allow the user to pick a partial repository
192 wxString dest = pro.GetPath() + wxFileName::GetPathSeparator() + projects.front();
193 m_frame->LoadProject( dest );
194
198
202 Prj().GetLocalSettings().m_GitRepoType = "https";
203 else
204 Prj().GetLocalSettings().m_GitRepoType = "local";
205
206 return 0;
207}
208
209
211{
213
214 wxFileName templatePath;
215
216 // KiCad system template path.
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 ps->AddTemplatesPage( _( "System Templates" ), templatePath );
224 }
225
226 // User template path.
227 ENV_VAR_MAP_CITER it = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
228
229 if( it != Pgm().GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString )
230 {
231 templatePath.AssignDir( it->second.GetValue() );
232 ps->AddTemplatesPage( _( "User Templates" ), templatePath );
233 }
234
235 // Show the project template selector dialog
236 if( ps->ShowModal() != wxID_OK )
237 return -1;
238
239 if( !ps->GetSelectedTemplate() )
240 {
241 wxMessageBox( _( "No project template was selected. Cannot generate new project." ),
242 _( "Error" ), wxOK | wxICON_ERROR, m_frame );
243
244 return -1;
245 }
246
247 // Get project destination folder and project file name.
248 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
249 wxString title = _( "New Project Folder" );
250 wxFileDialog dlg( m_frame, title, default_dir, wxEmptyString, FILEEXT::ProjectFileWildcard(),
251 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
252
253 // Add a "Create a new directory" checkbox
254 FILEDLG_NEW_PROJECT newProjectHook;
255 dlg.SetCustomizeHook( newProjectHook );
256
257 if( dlg.ShowModal() == wxID_CANCEL )
258 return -1;
259
260 wxFileName fn( dlg.GetPath() );
261
262 // wxFileName automatically extracts an extension. But if it isn't a .kicad_pro extension,
263 // we should keep it as part of the filename
264 if( !fn.GetExt().IsEmpty() && fn.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
265 fn.SetName( fn.GetName() + wxT( "." ) + fn.GetExt() );
266
268
269 if( !fn.IsAbsolute() )
270 fn.MakeAbsolute();
271
272 bool createNewDir = false;
273 createNewDir = newProjectHook.GetCreateNewDir();
274
275 // Append a new directory with the same name of the project file.
276 if( createNewDir )
277 fn.AppendDir( fn.GetName() );
278
279 // Check if the project directory is empty if it already exists.
280
281 if( !fn.DirExists() )
282 {
283 if( !fn.Mkdir() )
284 {
285 wxString msg;
286 msg.Printf( _( "Folder '%s' could not be created.\n\n"
287 "Make sure you have write permissions and try again." ),
288 fn.GetPath() );
290 return -1;
291 }
292 }
293
294 if( !fn.IsDirWritable() )
295 {
296 wxString msg;
297
298 msg.Printf( _( "Insufficient permissions to write to folder '%s'." ), fn.GetPath() );
299 wxMessageDialog msgDlg( m_frame, msg, _( "Error" ), wxICON_ERROR | wxOK | wxCENTER );
300 msgDlg.ShowModal();
301 return -1;
302 }
303
304 // Make sure we are not overwriting anything in the destination folder.
305 std::vector< wxFileName > destFiles;
306
307 if( ps->GetSelectedTemplate()->GetDestinationFiles( fn, destFiles ) )
308 {
309 std::vector<wxFileName> overwrittenFiles;
310
311 for( const wxFileName& file : destFiles )
312 {
313 if( file.FileExists() )
314 overwrittenFiles.push_back( file );
315 }
316
317 if( !overwrittenFiles.empty() )
318 {
319 wxString extendedMsg = _( "Overwriting files:" ) + "\n";
320
321 for( const wxFileName& file : overwrittenFiles )
322 extendedMsg += "\n" + file.GetFullName();
323
324 KIDIALOG msgDlg( m_frame,
325 _( "Similar files already exist in the destination folder." ),
326 _( "Confirmation" ),
327 wxOK | wxCANCEL | wxICON_WARNING );
328 msgDlg.SetExtendedMessage( extendedMsg );
329 msgDlg.SetOKLabel( _( "Overwrite" ) );
330 msgDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
331
332 if( msgDlg.ShowModal() == wxID_CANCEL )
333 return -1;
334 }
335 }
336
337 wxString errorMsg;
338
339 // The selected template widget contains the template we're attempting to use to
340 // create a project
341 if( !ps->GetSelectedTemplate()->CreateProject( fn, &errorMsg ) )
342 {
343 wxMessageDialog createDlg( m_frame,
344 _( "A problem occurred creating new project from template." ),
345 _( "Error" ),
346 wxOK | wxICON_ERROR );
347
348 if( !errorMsg.empty() )
349 createDlg.SetExtendedMessage( errorMsg );
350
351 createDlg.ShowModal();
352 return -1;
353 }
354
355 m_frame->CreateNewProject( fn.GetFullPath() );
356 m_frame->LoadProject( fn );
357 return 0;
358}
359
360
361int KICAD_MANAGER_CONTROL::openProject( const wxString& aDefaultDir )
362{
363 wxString wildcard = FILEEXT::AllProjectFilesWildcard()
366
367 wxFileDialog dlg( m_frame, _( "Open Existing Project" ), aDefaultDir, wxEmptyString, wildcard,
368 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
369
370 if( dlg.ShowModal() == wxID_CANCEL )
371 return -1;
372
373 wxFileName pro( dlg.GetPath() );
374
375 if( !pro.IsAbsolute() )
376 pro.MakeAbsolute();
377
378 if( !pro.FileExists() )
379 return -1;
380
381 m_frame->LoadProject( pro );
382
383 return 0;
384}
385
386
388{
390}
391
392
394{
395 return openProject( m_frame->GetMruPath() );
396}
397
398
400{
401 m_frame->CloseProject( true );
402 return 0;
403}
404
405
407{
408 if( aEvent.Parameter<wxString*>() )
409 m_frame->LoadProject( wxFileName( *aEvent.Parameter<wxString*>() ) );
410 return 0;
411}
412
414{
415 if( aEvent.Parameter<wxString*>() )
416 wxExecute( *aEvent.Parameter<wxString*>(), wxEXEC_ASYNC );
417 return 0;
418}
419
420class SAVE_AS_TRAVERSER : public wxDirTraverser
421{
422public:
424 const wxString& aSrcProjectDirPath,
425 const wxString& aSrcProjectName,
426 const wxString& aNewProjectDirPath,
427 const wxString& aNewProjectName ) :
428 m_frame( aFrame ),
429 m_projectDirPath( aSrcProjectDirPath ),
430 m_projectName( aSrcProjectName ),
431 m_newProjectDirPath( aNewProjectDirPath ),
432 m_newProjectName( aNewProjectName )
433 {
434 }
435
436 virtual wxDirTraverseResult OnFile( const wxString& aSrcFilePath ) override
437 {
438 // Recursion guard for a Save As to a location inside the source project.
439 if( aSrcFilePath.StartsWith( m_newProjectDirPath + wxFileName::GetPathSeparator() ) )
440 return wxDIR_CONTINUE;
441
442 wxFileName destFile( aSrcFilePath );
443 wxString ext = destFile.GetExt();
444 bool atRoot = destFile.GetPath() == m_projectDirPath;
445
449 {
450 wxString destPath = destFile.GetPath();
451
452 if( destPath.StartsWith( m_projectDirPath ) )
453 {
454 destPath.Replace( m_projectDirPath, m_newProjectDirPath, false );
455 destFile.SetPath( destPath );
456 }
457
458 if( destFile.GetName() == m_projectName )
459 {
460 destFile.SetName( m_newProjectName );
461
462 if( atRoot && ext != FILEEXT::ProjectLocalSettingsFileExtension )
463 m_newProjectFile = destFile;
464 }
465
467 {
468 // All paths in the settings file are relative so we can just do a straight copy
469 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), m_errors );
470 }
471 else if( ext == FILEEXT::ProjectFileExtension )
472 {
473 PROJECT_FILE projectFile( aSrcFilePath );
474 projectFile.LoadFromFile();
475 projectFile.SaveAs( destFile.GetPath(), destFile.GetName() );
476 }
478 {
479 PROJECT_LOCAL_SETTINGS projectLocalSettings( nullptr, aSrcFilePath );
480 projectLocalSettings.LoadFromFile();
481 projectLocalSettings.SaveAs( destFile.GetPath(), destFile.GetName() );
482 }
483 }
493 || destFile.GetName() == "sym-lib-table" )
494 {
497 m_newProjectName, aSrcFilePath, m_errors );
498 }
499 else if( ext == FILEEXT::KiCadPcbFileExtension
505 || destFile.GetName() == "fp-lib-table" )
506 {
509 m_newProjectName, aSrcFilePath, m_errors );
510 }
511 else if( ext == FILEEXT::DrawingSheetFileExtension )
512 {
515 m_newProjectName, aSrcFilePath, m_errors );
516 }
517 else if( ext == FILEEXT::GerberJobFileExtension
520 {
523 m_newProjectName, aSrcFilePath, m_errors );
524 }
525 else if( destFile.GetName().StartsWith( FILEEXT::LockFilePrefix )
527 {
528 // Ignore lock files
529 }
530 else
531 {
532 // Everything we don't recognize just gets a straight copy.
533 wxString destPath = destFile.GetPathWithSep();
534 wxString destName = destFile.GetName();
535 wxUniChar pathSep = wxFileName::GetPathSeparator();
536
537 wxString srcProjectFootprintLib = pathSep + m_projectName + ".pretty" + pathSep;
538 wxString newProjectFootprintLib = pathSep + m_newProjectName + ".pretty" + pathSep;
539
540 if( destPath.StartsWith( m_projectDirPath ) )
541 destPath.Replace( m_projectDirPath, m_newProjectDirPath, false );
542
543 destPath.Replace( srcProjectFootprintLib, newProjectFootprintLib, true );
544
545 if( destName == m_projectName && ext != wxT( "zip" ) /* don't rename archives */ )
546 destFile.SetName( m_newProjectName );
547
548 destFile.SetPath( destPath );
549
550 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), m_errors );
551 }
552
553 return wxDIR_CONTINUE;
554 }
555
556 virtual wxDirTraverseResult OnDir( const wxString& aSrcDirPath ) override
557 {
558 // Recursion guard for a Save As to a location inside the source project.
559 if( aSrcDirPath.StartsWith( m_newProjectDirPath ) )
560 return wxDIR_CONTINUE;
561
562 wxFileName destDir( aSrcDirPath );
563 wxString destDirPath = destDir.GetPathWithSep();
564 wxUniChar pathSep = wxFileName::GetPathSeparator();
565
566 if( destDirPath.StartsWith( m_projectDirPath + pathSep )
567 || destDirPath.StartsWith( m_projectDirPath + PROJECT_BACKUPS_DIR_SUFFIX ) )
568 {
569 destDirPath.Replace( m_projectDirPath, m_newProjectDirPath, false );
570 destDir.SetPath( destDirPath );
571 }
572
573 if( destDir.GetName() == m_projectName )
574 {
575 if( destDir.GetExt() == "pretty" )
576 destDir.SetName( m_newProjectName );
577#if 0
578 // WAYNE STAMBAUGH TODO:
579 // If we end up with a symbol equivalent to ".pretty" we'll want to handle it here....
580 else if( destDir.GetExt() == "sym_lib_dir_extension" )
581 destDir.SetName( m_newProjectName );
582#endif
583 }
584
585 if( !wxMkdir( destDir.GetFullPath() ) )
586 {
587 wxString msg;
588
589 if( !m_errors.empty() )
590 m_errors += "\n";
591
592 msg.Printf( _( "Cannot copy folder '%s'." ), destDir.GetFullPath() );
593 m_errors += msg;
594 }
595
596 return wxDIR_CONTINUE;
597 }
598
599 wxString GetErrors() { return m_errors; }
600
601 wxFileName GetNewProjectFile() { return m_newProjectFile; }
602
603private:
605
610
612 wxString m_errors;
613};
614
615
617{
618 wxString msg;
619
620 wxFileName currentProjectFile( Prj().GetProjectFullName() );
621 wxString currentProjectDirPath = currentProjectFile.GetPath();
622 wxString currentProjectName = Prj().GetProjectName();
623
624 wxString default_dir = m_frame->GetMruPath();
625
626 Prj().GetProjectFile().SaveToFile( currentProjectDirPath );
627 Prj().GetLocalSettings().SaveToFile( currentProjectDirPath );
628
629 if( default_dir == currentProjectDirPath
630 || default_dir == currentProjectDirPath + wxFileName::GetPathSeparator() )
631 {
632 // Don't start within the current project
633 wxFileName default_dir_fn( default_dir );
634 default_dir_fn.RemoveLastDir();
635 default_dir = default_dir_fn.GetPath();
636 }
637
638 wxFileDialog dlg( m_frame, _( "Save Project To" ), default_dir, wxEmptyString, wxEmptyString,
639 wxFD_SAVE );
640
641 if( dlg.ShowModal() == wxID_CANCEL )
642 return -1;
643
644 wxFileName newProjectDir( dlg.GetPath(), wxEmptyString );
645
646 if( !newProjectDir.IsAbsolute() )
647 newProjectDir.MakeAbsolute();
648
649 if( wxDirExists( newProjectDir.GetFullPath() ) )
650 {
651 msg.Printf( _( "'%s' already exists." ), newProjectDir.GetFullPath() );
653 return -1;
654 }
655
656 if( !wxMkdir( newProjectDir.GetFullPath() ) )
657 {
658 msg.Printf( _( "Folder '%s' could not be created.\n\n"
659 "Please make sure you have write permissions and try again." ),
660 newProjectDir.GetPath() );
662 return -1;
663 }
664
665 if( !newProjectDir.IsDirWritable() )
666 {
667 msg.Printf( _( "Insufficient permissions to write to folder '%s'." ),
668 newProjectDir.GetFullPath() );
669 wxMessageDialog msgDlg( m_frame, msg, _( "Error!" ), wxICON_ERROR | wxOK | wxCENTER );
670 msgDlg.ShowModal();
671 return -1;
672 }
673
674 const wxString& newProjectDirPath = newProjectDir.GetFullPath();
675 const wxString& newProjectName = newProjectDir.GetDirs().Last();
676 wxDir currentProjectDir( currentProjectDirPath );
677
678 SAVE_AS_TRAVERSER traverser( m_frame, currentProjectDirPath, currentProjectName,
679 newProjectDirPath, newProjectName );
680
681 currentProjectDir.Traverse( traverser );
682
683 if( !traverser.GetErrors().empty() )
684 DisplayErrorMessage( m_frame, traverser.GetErrors() );
685
686 if( !traverser.GetNewProjectFile().FileExists() )
688
689 m_frame->LoadProject( traverser.GetNewProjectFile() );
690
691 return 0;
692}
693
694
696{
698 return 0;
699}
700
701
703{
704 ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
705 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
706 SELECTION dummySel;
707
708 if( conditionalMenu )
709 conditionalMenu->Evaluate( dummySel );
710
711 if( actionMenu )
712 actionMenu->UpdateAll();
713
714 return 0;
715}
716
717
719{
720 FRAME_T playerType = aEvent.Parameter<FRAME_T>();
721 KIWAY_PLAYER* player;
722
723 if( playerType == FRAME_SCH && !m_frame->IsProjectActive() )
724 {
725 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a schematic." ),
726 wxEmptyString );
727 return -1;
728 }
729 else if( playerType == FRAME_PCB_EDITOR && !m_frame->IsProjectActive() )
730 {
731 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a pcb." ),
732 wxEmptyString );
733 return -1;
734 }
735
736 // Prevent multiple KIWAY_PLAYER loading at one time
737 if( !m_loading.try_lock() )
738 return -1;
739
740 const std::lock_guard<std::mutex> lock( m_loading, std::adopt_lock );
741
742 try
743 {
744 player = m_frame->Kiway().Player( playerType, true );
745 }
746 catch( const IO_ERROR& err )
747 {
748 wxLogError( _( "Application failed to load:\n" ) + err.What() );
749 return -1;
750 }
751
752 if ( !player )
753 {
754 wxLogError( _( "Application cannot start." ) );
755 return -1;
756 }
757
758 if( !player->IsVisible() ) // A hidden frame might not have the document loaded.
759 {
760 wxString filepath;
761
762 if( playerType == FRAME_SCH )
763 {
764 wxFileName kicad_schematic( m_frame->SchFileName() );
765 wxFileName legacy_schematic( m_frame->SchLegacyFileName() );
766
767 if( !legacy_schematic.FileExists() || kicad_schematic.FileExists() )
768 filepath = kicad_schematic.GetFullPath();
769 else
770 filepath = legacy_schematic.GetFullPath();
771 }
772 else if( playerType == FRAME_PCB_EDITOR )
773 {
774 wxFileName kicad_board( m_frame->PcbFileName() );
775 wxFileName legacy_board( m_frame->PcbLegacyFileName() );
776
777 if( !legacy_board.FileExists() || kicad_board.FileExists() )
778 filepath = kicad_board.GetFullPath();
779 else
780 filepath = legacy_board.GetFullPath();
781 }
782
783 if( !filepath.IsEmpty() )
784 {
785 std::vector<wxString> file_list{ filepath };
786
787 if( !player->OpenProjectFiles( file_list ) )
788 {
789 player->Destroy();
790 return -1;
791 }
792 }
793
794 wxBusyCursor busy;
795 player->Show( true );
796 }
797
798 // Needed on Windows, other platforms do not use it, but it creates no issue
799 if( player->IsIconized() )
800 player->Iconize( false );
801
802 player->Raise();
803
804 // Raising the window does not set the focus on Linux. This should work on
805 // any platform.
806 if( wxWindow::FindFocus() != player )
807 player->SetFocus();
808
809 // Save window state to disk now. Don't wait around for a crash.
810 if( Pgm().GetCommonSettings()->m_Session.remember_open_files
811 && !player->GetCurrentFileName().IsEmpty() )
812 {
813 wxFileName rfn( player->GetCurrentFileName() );
814 rfn.MakeRelativeTo( Prj().GetProjectPath() );
815
816 WINDOW_SETTINGS windowSettings;
817 player->SaveWindowSettings( &windowSettings );
818
819 Prj().GetLocalSettings().SaveFileState( rfn.GetFullPath(), &windowSettings, true );
820 Prj().GetLocalSettings().SaveToFile( Prj().GetProjectPath() );
821 }
822
823 return 0;
824}
825
826
827class TERMINATE_HANDLER : public wxProcess
828{
829public:
830 TERMINATE_HANDLER( const wxString& appName )
831 { }
832
833 void OnTerminate( int pid, int status ) override
834 {
835 delete this;
836 }
837};
838
839
841{
842 wxString execFile;
843 wxString param;
844
846 execFile = GERBVIEW_EXE;
848 execFile = BITMAPCONVERTER_EXE;
850 execFile = PCB_CALCULATOR_EXE;
852 execFile = PL_EDITOR_EXE;
854 execFile = Pgm().GetTextEditor();
856 execFile = EESCHEMA_EXE;
858 execFile = PCBNEW_EXE;
859 else
860 wxFAIL_MSG( "Execute(): unexpected request" );
861
862 if( execFile.IsEmpty() )
863 return 0;
864
865 if( aEvent.Parameter<wxString*>() )
866 param = *aEvent.Parameter<wxString*>();
868 param = m_frame->Prj().GetProjectPath();
869
870 TERMINATE_HANDLER* callback = new TERMINATE_HANDLER( execFile );
871
872 long pid = ExecuteFile( execFile, param, callback );
873
874 if( pid > 0 )
875 {
876#ifdef __WXMAC__
877 wxString script = wxString::Format( wxS( "tell application \"System Events\"\n"
878 " set frontmost of the first process whose unix id is %l to true\n"
879 "end tell" ), pid );
880
881 // This non-parameterized use of wxExecute is fine because script is not derived
882 // from user input.
883 wxExecute( wxString::Format( "osascript -e '%s'", script ) );
884#endif
885 }
886 else
887 {
888 delete callback;
889 }
890
891 return 0;
892}
893
894
896{
899 {
900 // policy disables the plugin manager
901 return 0;
902 }
903
904 // For some reason, after a click or a double click the bitmap button calling
905 // PCM keeps the focus althougt the focus was not set to this button.
906 // This hack force removing the focus from this button
907 m_frame->SetFocus();
908 wxSafeYield();
909
910 if( !m_frame->GetPcm() )
912
913 DIALOG_PCM pcm( m_frame, m_frame->GetPcm() );
914 pcm.ShowModal();
915
916 const std::unordered_set<PCM_PACKAGE_TYPE>& changed = pcm.GetChangedPackageTypes();
917
918 if( changed.count( PCM_PACKAGE_TYPE::PT_PLUGIN ) )
919 {
920 std::string payload = "";
922 }
923
924 KICAD_SETTINGS* settings = Pgm().GetSettingsManager().GetAppSettings<KICAD_SETTINGS>();
925
926 if( changed.count( PCM_PACKAGE_TYPE::PT_LIBRARY )
927 && ( settings->m_PcmLibAutoAdd || settings->m_PcmLibAutoRemove ) )
928 {
929 // Reset project tables
931 Prj().SetElem( PROJECT::ELEM_FPTBL, nullptr );
932
933 KIWAY& kiway = m_frame->Kiway();
934
935 // Reset state containing global lib tables
936 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_SCH, false ) )
937 kiface->Reset();
938
939 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_PCB, false ) )
940 kiface->Reset();
941
942 // Reload lib tables
943 std::string payload = "";
944
947 kiway.ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload );
950 }
951
952 if( changed.count( PCM_PACKAGE_TYPE::PT_COLORTHEME ) )
953 Pgm().GetSettingsManager().ReloadColorSettings();
954
955 return 0;
956}
957
958
960{
970
973
983
986
988}
static TOOL_ACTION zoomRedraw
Definition: actions.h:114
static TOOL_ACTION saveAs
Definition: actions.h:52
static TOOL_ACTION updateMenu
Definition: actions.h:200
Defines 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
void AddTemplatesPage(const wxString &aTitle, wxFileName &aPath)
Add a new page with aTitle, populated with templates from aPath.
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 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)
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)
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 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()
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:47
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: confirm.cpp:56
int ShowModal() override
Definition: confirm.cpp:100
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:53
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:67
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:279
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:432
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition: kiway.cpp:202
@ FACE_SCH
eeschema DSO
Definition: kiway.h:286
@ FACE_PL_EDITOR
Definition: kiway.h:290
@ FACE_PCB
pcbnew DSO
Definition: kiway.h:287
@ FACE_GERBVIEW
Definition: kiway.h:289
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr)
Send aPayload to aDestination from aSource.
Definition: kiway.cpp:553
static wxString GetStockDemosPath()
Gets the stock (install) demos path.
Definition: paths.cpp:340
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:70
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 const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition: project.cpp:147
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition: project.h:172
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:166
virtual void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:309
@ ELEM_SYMBOL_LIB_TABLE
Definition: project.h:228
@ ELEM_FPTBL
Definition: project.h:223
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 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:167
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:460
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:360
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:332
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:305
This file is part of the common library.
#define _(s)
Enums and utilities for different EDA tools.
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:297
int ExecuteFile(const wxString &aEditorName, const wxString &aFileName, wxProcess *aCallback)
Call the executable file aEditorName with the parameter aFileName.
Definition: gestfich.cpp:140
static const std::string LegacySchematicFileExtension
static const std::string NetlistFileExtension
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 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 LegacyProjectFileWildcard()
static wxString AllProjectFilesWildcard()
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
PROJECT & Prj()
Definition: kicad.cpp:591
This file contains miscellaneous commonly used macros and functions.
@ MAIL_RELOAD_PLUGINS
Definition: mail_type.h:57
@ MAIL_RELOAD_LIB
Definition: mail_type.h:56
std::optional< wxString > GetVersionedEnvVarValue(const std::map< wxString, ENV_VAR_ITEM > &aMap, const wxString &aBaseName)
Attempts 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: gtk/policy.cpp:26
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.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:119
Implement a participant in the KIWAY alchemy.
Definition: kiway.h:151
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:216
Stores 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.