KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kicad_manager_control.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2019 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
22#include <common.h>
23#include <env_vars.h>
24#include <executable_names.h>
25#include <pgm_base.h>
26#include <pgm_kicad.h>
27#include <policy_keys.h>
28#include <kiway.h>
29#include <kicad_manager_frame.h>
30#include <core/json_serializers.h> // must precede any json+wxString use (job.h) in this TU
31#include <downgrade_target.h>
32#include <project_downgrade.h>
33#include <filesystem>
34#include <system_error>
35#include <wx/msgdlg.h>
36#include <kiplatform/policy.h>
38#include <kiplatform/secrets.h>
39#include <kiplatform/ui.h>
40#include <confirm.h>
41#include <kidialog.h>
47#include <tool/selection.h>
48#include <tool/tool_event.h>
49#include <tool/tool_manager.h>
50#include <tool/common_control.h>
59#include <gestfich.h>
60#include <paths.h>
61#include <wx/dir.h>
62#include <wx/ffile.h>
63#include <wx/filedlg.h>
64#include "dialog_pcm.h"
66#include <project_tree_pane.h>
67#include <project_tree.h>
69#include <launch_ext.h>
70
72
74 TOOL_INTERACTIVE( "kicad.Control" ),
75 m_frame( nullptr ),
76 m_inShowPlayer( false )
77{
78}
79
80
86
87
88wxFileName KICAD_MANAGER_CONTROL::newProjectDirectory( wxString* aFileName, bool isRepo )
89{
90 wxString default_filename = aFileName ? *aFileName : wxString();
91
92 wxString default_dir = m_frame->GetMruPath();
93 wxFileDialog dlg( m_frame, _( "Create New Project" ), default_dir, default_filename,
94 ( isRepo ? wxString( "" ) : FILEEXT::ProjectFileWildcard() ),
95 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
96
97 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
98
99 // Add a "Create a new directory" checkbox
100 FILEDLG_NEW_PROJECT newProjectHook;
101 dlg.SetCustomizeHook( newProjectHook );
102
104
105 if( dlg.ShowModal() == wxID_CANCEL )
106 return wxFileName();
107
108 wxFileName pro( dlg.GetPath() );
109
110 // wxFileName automatically extracts an extension. But if it isn't
111 // a .pro extension, we should keep it as part of the filename
112 if( !pro.GetExt().IsEmpty() && pro.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
113 pro.SetName( pro.GetName() + wxT( "." ) + pro.GetExt() );
114
115 pro.SetExt( FILEEXT::ProjectFileExtension ); // enforce extension
116
117 if( !pro.IsAbsolute() )
118 pro.MakeAbsolute();
119
120 // Append a new directory with the same name of the project file.
121 bool createNewDir = false;
122
123 createNewDir = newProjectHook.GetCreateNewDir();
124
125 if( createNewDir )
126 pro.AppendDir( pro.GetName() );
127
128 // Check if the project directory is empty if it already exists.
129 wxDir directory( pro.GetPath() );
130
131 if( !pro.DirExists() )
132 {
133 if( !pro.Mkdir() )
134 {
135 wxString msg;
136 msg.Printf( _( "Folder '%s' could not be created.\n\n"
137 "Make sure you have write permissions and try again." ),
138 pro.GetPath() );
140 return wxFileName();
141 }
142 }
143 else if( directory.HasFiles() )
144 {
145 wxString msg = _( "The selected folder is not empty. It is recommended that you "
146 "create projects in their own empty folder.\n\n"
147 "Do you want to continue?" );
148
149 if( !IsOK( m_frame, msg ) )
150 return wxFileName();
151 }
152
153 return pro;
154}
155
156
158{
159 // The built-in "default" template lives in the stable default user templates path so that it
160 // is always available regardless of how KICAD_USER_TEMPLATE_DIR is configured. Seeding it
161 // into KICAD_USER_TEMPLATE_DIR would hide the default whenever the user points that variable
162 // at a custom location of their own. See https://gitlab.com/kicad/code/kicad/-/issues/24343
163 wxFileName defaultTemplate = EnsureDefaultProjectTemplate( PATHS::GetUserTemplatesPath() );
164
165 KICAD_SETTINGS* settings = GetAppSettings<KICAD_SETTINGS>( "kicad" );
166
167 wxString userTemplatesPath;
168 wxString systemTemplatesPath;
169
170 auto resolveTemplateDir =
171 []( const wxString& aValue ) -> wxString
172 {
173 wxString resolved = ExpandEnvVarSubstitutions( aValue, nullptr );
174
175 // Skip values with unresolved references so we don't seed the selector with a
176 // bogus path that doesn't exist on disk.
177 if( resolved.Contains( wxT( "${" ) ) || resolved.Contains( wxT( "$(" ) ) )
178 return wxEmptyString;
179
180 wxFileName templatePath;
181 templatePath.AssignDir( resolved );
182 templatePath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
183 return templatePath.GetFullPath();
184 };
185
186 ENV_VAR_MAP_CITER itUser = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
187
188 if( itUser != Pgm().GetLocalEnvVariables().end() && itUser->second.GetValue() != wxEmptyString )
189 userTemplatesPath = resolveTemplateDir( itUser->second.GetValue() );
190
191 std::optional<wxString> v = ENV_VAR::GetVersionedEnvVarValue( Pgm().GetLocalEnvVariables(),
192 wxT( "TEMPLATE_DIR" ) );
193
194 if( v && !v->IsEmpty() )
195 systemTemplatesPath = resolveTemplateDir( *v );
196
197 // Point the selector at the seeded "default" template directory itself (not the whole user
198 // templates root) so that only the built-in default is offered as a built-in. Scanning the
199 // root would mislabel the user's own templates there as built-ins and disable editing them.
200 wxString defaultTemplatesPath;
201
202 if( defaultTemplate.IsOk() )
203 defaultTemplatesPath = resolveTemplateDir( defaultTemplate.GetPath() );
204
205 // The selector scans a directory containing a "meta" subdir as a single template, otherwise
206 // it iterates the immediate subdirectories. The default template's parent directory is the
207 // template root, so if KICAD_USER_TEMPLATE_DIR or the system template dir already point at
208 // that root the default is scanned there; skip the dedicated default scan to avoid duplicates.
209 if( !defaultTemplatesPath.IsEmpty() )
210 {
211 wxFileName defaultRootFn = defaultTemplate;
212 defaultRootFn.RemoveLastDir();
213 wxString defaultRoot = resolveTemplateDir( defaultRootFn.GetPath() );
214
215 if( defaultRoot == userTemplatesPath || defaultRoot == systemTemplatesPath )
216 defaultTemplatesPath = wxEmptyString;
217 }
218
219 // If we have no template source at all and could not seed the default, fall back to creating
220 // an empty project directory directly.
221 if( !defaultTemplate.IsOk() && userTemplatesPath.IsEmpty() && systemTemplatesPath.IsEmpty() )
222 {
223 wxFileName pro = newProjectDirectory();
224
225 if( !pro.IsOk() )
226 return -1;
227
228 m_frame->CreateNewProject( pro );
229 m_frame->LoadProject( pro );
230
231 return 0;
232 }
233
234 // Use RunMainStack to show the dialog on the main stack instead of the coroutine stack.
235 // This is necessary because the template selector uses a WebView which triggers WebKit's
236 // JavaScript VM initialization. WebKit's stack validation fails on coroutine stacks.
237 int result = wxID_CANCEL;
238 wxString selectedTemplatePath;
239 wxPoint templateWindowPos;
240 wxSize templateWindowSize;
241 wxString projectToEdit;
242 wxString browsedTemplatesPath;
243
245 [&]()
246 {
248 settings->m_TemplateWindowSize, userTemplatesPath,
249 systemTemplatesPath, defaultTemplatesPath,
250 settings->m_RecentTemplates,
251 settings->m_BrowsedTemplatesPath );
252
253 result = ps.ShowModal();
254 templateWindowPos = ps.GetPosition();
255 templateWindowSize = ps.GetSize();
256 projectToEdit = ps.GetProjectToEdit();
257 browsedTemplatesPath = ps.GetBrowsedTemplatesPath();
258
260
261 if( templ )
262 {
263 wxFileName htmlFile = templ->GetHtmlFile();
264 htmlFile.RemoveLastDir();
265 selectedTemplatePath = htmlFile.GetPath();
266 }
267 } );
268
269 settings->m_TemplateWindowPos = templateWindowPos;
270 settings->m_TemplateWindowSize = templateWindowSize;
271 settings->m_BrowsedTemplatesPath = browsedTemplatesPath;
272
273 // Check if user wants to edit a template instead of creating new project
274 if( result == wxID_APPLY )
275 {
276 if( !projectToEdit.IsEmpty() && wxFileExists( projectToEdit ) )
277 {
278 m_frame->LoadProject( wxFileName( projectToEdit ) );
279 return 0;
280 }
281 }
282
283 if( result != wxID_OK )
284 return -1;
285
286 if( selectedTemplatePath.IsEmpty() )
287 {
288 wxMessageBox( _( "No project template was selected. Cannot generate new project." ), _( "Error" ),
289 wxOK | wxICON_ERROR, m_frame );
290
291 return -1;
292 }
293
294 // Recreate the template object from the saved path
295 PROJECT_TEMPLATE selectedTemplate( selectedTemplatePath );
296
297 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
298 wxString title = _( "New Project Folder" );
299 wxFileDialog dlg( m_frame, title, default_dir, wxEmptyString, FILEEXT::ProjectFileWildcard(),
300 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
301
302 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
303
304 FILEDLG_NEW_PROJECT newProjectHook;
305 dlg.SetCustomizeHook( newProjectHook );
306
308
309 if( dlg.ShowModal() == wxID_CANCEL )
310 return -1;
311
312 wxFileName fn( dlg.GetPath() );
313
314 if( !fn.GetExt().IsEmpty() && fn.GetExt().ToStdString() != FILEEXT::ProjectFileExtension )
315 fn.SetName( fn.GetName() + wxT( "." ) + fn.GetExt() );
316
318
319 if( !fn.IsAbsolute() )
320 fn.MakeAbsolute();
321
322 bool createNewDir = false;
323 createNewDir = newProjectHook.GetCreateNewDir();
324
325 if( createNewDir )
326 fn.AppendDir( fn.GetName() );
327
328 if( !fn.DirExists() && !fn.Mkdir() )
329 {
330 DisplayErrorMessage( m_frame, wxString::Format( _( "Folder '%s' could not be created.\n\n"
331 "Make sure you have write permissions and try again." ),
332 fn.GetPath() ) );
333 return -1;
334 }
335
336 if( !fn.IsDirWritable() )
337 {
338 DisplayErrorMessage( m_frame, wxString::Format( _( "Insufficient permissions to write to folder '%s'." ),
339 fn.GetPath() ) );
340 return -1;
341 }
342
343 std::vector< wxFileName > destFiles;
344
345 if( selectedTemplate.GetDestinationFiles( fn, destFiles ) )
346 {
347 std::vector<wxFileName> overwrittenFiles;
348
349 for( const wxFileName& file : destFiles )
350 {
351 if( file.FileExists() )
352 overwrittenFiles.push_back( file );
353 }
354
355 if( !overwrittenFiles.empty() )
356 {
357 wxString extendedMsg = _( "Overwriting files:" ) + "\n";
358
359 for( const wxFileName& file : overwrittenFiles )
360 extendedMsg += "\n" + file.GetFullName();
361
362 KIDIALOG msgDlg( m_frame, _( "Similar files already exist in the destination folder." ),
363 _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
364 msgDlg.SetExtendedMessage( extendedMsg );
365 msgDlg.SetOKLabel( _( "Overwrite" ) );
366 msgDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
367
368 if( msgDlg.ShowModal() == wxID_CANCEL )
369 return -1;
370 }
371 }
372
373 wxString errorMsg;
374
375 if( !selectedTemplate.CreateProject( fn, &errorMsg ) )
376 {
377 DisplayErrorMessage( m_frame, _( "A problem occurred creating new project from template." ), errorMsg );
378 return -1;
379 }
380
381 // Update MRU list with the used template
382 wxFileName templateDir = selectedTemplate.GetHtmlFile();
383 templateDir.RemoveLastDir();
384 wxString templatePath = templateDir.GetPath();
385
386 settings->m_LastUsedTemplate = templatePath;
387
388 // Add to front of recent templates, remove duplicates, trim to 5
389 std::vector<wxString>& recentTemplates = settings->m_RecentTemplates;
390 recentTemplates.erase( std::remove( recentTemplates.begin(), recentTemplates.end(), templatePath ),
391 recentTemplates.end() );
392 recentTemplates.insert( recentTemplates.begin(), templatePath );
393
394 if( recentTemplates.size() > 5 )
395 recentTemplates.resize( 5 );
396
397 m_frame->CreateNewProject( fn.GetFullPath() );
398 m_frame->LoadProject( fn );
399 return 0;
400}
401
402
404{
405 DIALOG_GIT_REPOSITORY dlg( m_frame, nullptr );
406
407 dlg.SetTitle( _( "Clone Project from Git Repository" ) );
408
409 int ret = dlg.ShowModal();
410
411 if( ret != wxID_OK )
412 return -1;
413
414 wxString project_name = dlg.GetRepoName();
415 wxFileName pro = newProjectDirectory( &project_name, true );
416
417 if( !pro.IsOk() )
418 return -1;
419
420 // No open project owns the repository being cloned, so use a scratch session.
421 KIGIT_COMMON cloneCommon( nullptr );
422 bool retriedAfterTrust = false;
423
424 while( true )
425 {
426 bool cloned = false;
427 bool cancelled = false;
428 wxString error;
429 wxString details;
430
431 std::optional<KIGIT::HOST_KEY_FAILURE> hostKey;
432
433 // Scoped, so the progress window is gone before a prompt below
434 {
435 GIT_CLONE_HANDLER cloneHandler( &cloneCommon );
436
437 cloneHandler.SetRemote( dlg.GetRepoURL() );
438 cloneHandler.SetClonePath( pro.GetPath() );
439 cloneHandler.SetUsername( dlg.GetUsername() );
440 cloneHandler.SetPassword( dlg.GetPassword() );
441 cloneHandler.SetSSHKey( dlg.GetRepoSSHPath() );
442
443 cloneHandler.SetProgressReporter(
444 std::make_unique<WX_PROGRESS_REPORTER>( m_frame, _( "Clone Repository" ), 1, PR_CAN_ABORT ) );
445
446 cloned = cloneHandler.PerformClone();
447 cancelled = !cloned && cloneHandler.IsThisOperationCancelled();
448
449 if( !cloned )
450 {
451 KIGIT_ERROR_MESSAGE message = cloneHandler.PopError();
452 error = message.summary;
453 details = message.details;
454 hostKey = cloneHandler.GetHostKeyFailure();
455 }
456 }
457
458 if( cloned )
459 break;
460
461 // Cancelling from the progress dialog is not an error.
462 if( cancelled )
463 return -1;
464
465 if( hostKey )
466 {
467 if( !KIGIT::PromptToTrustHost( m_frame, *hostKey, retriedAfterTrust ) )
468 return -1;
469
470 retriedAfterTrust = true;
471 continue;
472 }
473
474 DisplayErrorMessage( m_frame, error, details );
475 return -1;
476 }
477
478 std::vector<wxString> projects = cloneCommon.GetProjectDirs();
479
480 // The project opens its own handle when it loads below, this one is done.
481 git_repository_free( cloneCommon.GetRepo() );
482 cloneCommon.SetRepo( nullptr );
483
484 if( projects.empty() )
485 {
486 DisplayErrorMessage( m_frame, wxString::Format( _( "The repository has no KiCad project to open. Its files "
487 "were cloned to '%s', which can be deleted if they are "
488 "not needed." ),
489 pro.GetPath() ) );
490 return -1;
491 }
492
493 // Currently, we pick the first project file we find in the repository.
494 // TODO: Look into spare checkout to allow the user to pick a partial repository
495 wxString dest = pro.GetPath() + wxFileName::GetPathSeparator() + projects.front();
496 m_frame->LoadProject( dest );
497
498 // A machine cloning for the first time usually has no git identity yet. Asking now makes
499 // the first commit work instead of failing.
500 struct IDENTITY_RESULT
501 {
502 bool read = false;
503 KIGIT::GIT_IDENTITY identity;
504 };
505
506 auto common = Prj().GetGitCommon();
507 auto identity = std::make_shared<IDENTITY_RESULT>();
508
509 m_identityQuery.Run(
510 common,
511 [identity]( KIGIT_COMMON& aCommon )
512 {
513 identity->identity = KIGIT::ReadGitIdentity( aCommon );
514 identity->read = true;
515 },
516 [this, common, identity]()
517 {
518 if( !identity->read || !m_frame || m_frame->IsBeingDeleted() || !common || common->IsShuttingDown()
519 || Prj().GetGitCommon() != common || !Pgm().GetCommonSettings()->m_Git.enableGit
520 || Prj().GetLocalSettings().m_GitIntegrationDisabled )
521 {
522 return;
523 }
524
525 KIGIT::EnsureGitIdentity( m_frame, m_frame, common, identity->identity );
526 } );
527
528 // Keyed like the attach-time lookup, which never sees credentials embedded in the address
530 dlg.GetPassword() );
533
534 // The session attached when the project loaded, so it takes nothing more from the settings.
535 if( common )
536 {
537 common->SetUsername( dlg.GetUsername() );
538 common->SetSSHKey( dlg.GetRepoSSHPath() );
539 }
540
544 Prj().GetLocalSettings().m_GitRepoType = "https";
545 else
546 Prj().GetLocalSettings().m_GitRepoType = "local";
547
548 return 0;
549}
550
551
553{
554 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
555 wxFileDialog dlg( m_frame, _( "Create New Jobset" ), default_dir, wxEmptyString, FILEEXT::JobsetFileWildcard(),
556 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
557
559
560 if( dlg.ShowModal() == wxID_CANCEL )
561 return -1;
562
563 wxFileName jobsetFn( dlg.GetPath() );
564
565 // Check if the file already exists
566 bool fileExists = wxFileExists( jobsetFn.GetFullPath() );
567
568 if( fileExists )
569 {
570 // Remove the existing file so that a new one can be created
571 if( !wxRemoveFile( jobsetFn.GetFullPath() ) )
572 {
573 return -1;
574 }
575 }
576
577 m_frame->OpenJobsFile( jobsetFn.GetFullPath(), true );
578
579 return 0;
580}
581
582
583
584
585int KICAD_MANAGER_CONTROL::openProject( const wxString& aDefaultDir )
586{
587 wxString wildcard = FILEEXT::AllProjectFilesWildcard()
590
591 wxFileDialog dlg( m_frame, _( "Open Existing Project" ), aDefaultDir, wxEmptyString, wildcard,
592 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
593
594 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
595
597
598 if( dlg.ShowModal() == wxID_CANCEL )
599 return -1;
600
601 wxFileName pro( dlg.GetPath() );
602
603 if( !pro.IsAbsolute() )
604 pro.MakeAbsolute();
605
606 // You'd think wxFD_FILE_MUST_EXIST and the wild-cards would enforce these. Sentry
607 // indicates otherwise (at least on MSW).
608 if( !pro.Exists() || ( pro.GetExt() != FILEEXT::ProjectFileExtension
609 && pro.GetExt() != FILEEXT::LegacyProjectFileExtension ) )
610 {
611 return -1;
612 }
613
614 m_frame->LoadProject( pro );
615
616 return 0;
617}
618
619
624
625
627{
628 return openProject( m_frame->GetMruPath() );
629}
630
631
633{
634 wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep();
635 wxFileDialog dlg( m_frame, _( "Open Jobset" ), default_dir, wxEmptyString, FILEEXT::JobsetFileWildcard(),
636 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
637
639
640 if( dlg.ShowModal() == wxID_CANCEL )
641 return -1;
642
643 wxFileName jobsetFn( dlg.GetPath() );
644
645 m_frame->OpenJobsFile( jobsetFn.GetFullPath(), true );
646
647 return 0;
648}
649
650
652{
653 m_frame->CloseProject( true );
654 return 0;
655}
656
657
659{
660 if( aEvent.Parameter<wxString*>() )
661 m_frame->LoadProject( wxFileName( *aEvent.Parameter<wxString*>() ) );
662 return 0;
663}
664
665
667{
668 wxFileName fileName = m_frame->GetProjectFileName();
669
670 fileName.SetExt( FILEEXT::ArchiveFileExtension );
671
672 wxFileDialog dlg( m_frame, _( "Archive Project Files" ), fileName.GetPath(), fileName.GetFullName(),
673 FILEEXT::ZipFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
674
676
677 if( dlg.ShowModal() == wxID_CANCEL )
678 return 0;
679
680 wxFileName zipFile = dlg.GetPath();
681
682 wxString currdirname = fileName.GetPathWithSep();
683 wxDir dir( currdirname );
684
685 if( !dir.IsOpened() ) // wxWidgets display a error message on issue.
686 return 0;
687
688 STATUSBAR_REPORTER reporter( m_frame->GetStatusBar(), 1 );
689 PROJECT_ARCHIVER archiver;
690
691 archiver.Archive( currdirname, zipFile.GetFullPath(), reporter, true, true );
692 return 0;
693}
694
695
697{
698 m_frame->UnarchiveFiles();
699 return 0;
700}
701
702
704{
705 wxFileName proFn( Prj().GetProjectFullName() );
706 wxString projectDir = proFn.GetPath();
707 wxString projectName = proFn.GetName();
708
709 // The export reads the files on disk, so it should match what is on screen.
710 KIWAY_PLAYER* schFrame = m_frame->Kiway().Player( FRAME_SCH, false );
711 KIWAY_PLAYER* pcbFrame = m_frame->Kiway().Player( FRAME_PCB_EDITOR, false );
712
713 if( ( schFrame && schFrame->IsContentModified() ) || ( pcbFrame && pcbFrame->IsContentModified() ) )
714 {
715 int answer =
716 wxMessageBox( _( "You have unsaved changes. Save them before exporting?" ),
717 _( "Export for Older KiCad Version" ), wxYES_NO | wxCANCEL | wxICON_WARNING, m_frame );
718
719 if( answer == wxCANCEL )
720 return 0;
721
722 if( answer == wxYES )
723 {
724 // The handlers set the payload only when the save actually happened. A failed or
725 // cancelled save must not export stale files behind a success message.
726 if( schFrame && schFrame->IsContentModified() )
727 {
728 std::string payload;
729 m_frame->Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_SAVE, payload );
730
731 if( payload != "success" )
732 {
733 wxMessageBox( _( "The schematic was not saved. Nothing was exported." ),
734 _( "Export for Older KiCad Version" ), wxOK | wxICON_ERROR, m_frame );
735 return 0;
736 }
737 }
738
739 if( pcbFrame && pcbFrame->IsContentModified() )
740 {
741 std::string payload;
742 m_frame->Kiway().ExpressMail( FRAME_PCB_EDITOR, MAIL_PCB_SAVE, payload );
743
744 if( payload != "success" )
745 {
746 wxMessageBox( _( "The board was not saved. Nothing was exported." ),
747 _( "Export for Older KiCad Version" ), wxOK | wxICON_ERROR, m_frame );
748 return 0;
749 }
750 }
751 }
752 }
753
754 // The export converts the saved project-local library files, which the library editors do
755 // not save through the mails above.
756 KIWAY_PLAYER* symFrame = m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, false );
757 KIWAY_PLAYER* fpFrame = m_frame->Kiway().Player( FRAME_FOOTPRINT_EDITOR, false );
758
759 if( ( symFrame && symFrame->IsContentModified() ) || ( fpFrame && fpFrame->IsContentModified() ) )
760 {
761 if( wxMessageBox( _( "A library editor has unsaved changes. The export uses the last saved "
762 "library files. Continue?" ),
763 _( "Export for Older KiCad Version" ), wxYES_NO | wxICON_WARNING, m_frame )
764 != wxYES )
765 {
766 return 0;
767 }
768 }
769
770 const std::vector<DOWNGRADE_TARGET>& targets = GetDowngradeTargets();
771 wxArrayString names;
772
773 for( const DOWNGRADE_TARGET& target : targets )
774 names.Add( target.m_name );
775
776 // Probe against the oldest target. It drops the most, so its variant list covers the
777 // picker no matter which target the user chooses.
778 const wxString& probeTarget = targets.back().m_name;
779 COMPATIBILITY_REPORT probeReport;
780 wxString error;
781 std::vector<wxString> foundVariants;
782
783 if( !ClassifyProjectForDowngrade( m_frame->Kiway(), projectDir, projectName, probeTarget, probeReport, error,
784 &foundVariants ) )
785 {
786 wxMessageBox( error, _( "Export for Older KiCad Version" ), wxOK | wxICON_ERROR, m_frame );
787 return 0;
788 }
789
790 wxArrayString variantNames;
791
792 for( const wxString& name : foundVariants )
793 variantNames.Add( name );
794
795 DIALOG_EXPORT_OLDER_VERSION setupDlg( m_frame, names, variantNames, m_frame->GetMruPath() );
796
797 if( setupDlg.ShowModal() != wxID_OK )
798 return 0;
799
800 wxString target = setupDlg.GetTarget();
801 bool dropInsteadOfApproximate = setupDlg.GetDropInsteadOfApproximate();
802 wxString variant = setupDlg.GetVariant();
803
804 // A self-contained subfolder so we never write into the folder the user picked directly.
805 wxString destDir = setupDlg.GetPath() + wxFileName::GetPathSeparator() + projectName;
806
807 // Early feedback only. The export enforces this again when it creates the folder.
808 std::error_code ec;
809
810 if( std::filesystem::exists( destDir.ToStdWstring(), ec )
811 && !std::filesystem::is_empty( destDir.ToStdWstring(), ec ) )
812 {
813 wxMessageBox( wxString::Format( _( "The folder '%s' is not empty. Choose a location where it "
814 "does not exist yet." ),
815 destDir ),
816 _( "Export for Older KiCad Version" ), wxOK | wxICON_ERROR, m_frame );
817 return 0;
818 }
819
821 foundVariants.clear();
822
823 // The probe used the base design and default approximation policy.
824 if( target == probeTarget && !dropInsteadOfApproximate && variant.IsEmpty() )
825 {
826 report = probeReport;
827 foundVariants.assign( variantNames.begin(), variantNames.end() );
828 }
829 else if( !ClassifyProjectForDowngrade( m_frame->Kiway(), projectDir, projectName, target, report, error,
830 &foundVariants, dropInsteadOfApproximate, variant ) )
831 {
832 wxMessageBox( error, _( "Export for Older KiCad Version" ), wxOK | wxICON_ERROR, m_frame );
833 return 0;
834 }
835
836 if( report.IsBlocked() || report.IsLossy() )
837 {
838 DIALOG_DOWNGRADE_REPORT reportDlg( m_frame, target, report );
839
840 if( reportDlg.ShowModal() != wxID_OK || report.IsBlocked() )
841 return 0;
842 }
843
844 if( !ExportProjectForDowngrade( m_frame->Kiway(), projectDir, projectName, target, destDir, error, variant,
845 dropInsteadOfApproximate ) )
846 {
847 wxMessageBox( error, _( "Export for Older KiCad Version" ), wxOK | wxICON_ERROR, m_frame );
848 return 0;
849 }
850
851 wxMessageBox( wxString::Format( _( "Exported to '%s'." ), destDir ), _( "Export for Older KiCad Version" ),
852 wxOK | wxICON_INFORMATION, m_frame );
853 return 0;
854}
855
856
858{
859 // Open project directory in host OS's file explorer
860 LaunchExternal( Prj().GetProjectPath() );
861 return 0;
862}
863
865{
866 m_frame->RestoreLocalHistory();
867 return 0;
868}
869
870
872{
873 m_frame->ToggleLocalHistory();
874 return 0;
875}
876
877
879{
880 m_frame->ToggleGitCommitPane();
881 return 0;
882}
883
884
886{
887 if( aEvent.Parameter<wxString*>() )
888 wxExecute( *aEvent.Parameter<wxString*>(), wxEXEC_ASYNC );
889
890 return 0;
891}
892
893
894
896{
897 wxString msg;
898
899 wxFileName currentProjectFile( Prj().GetProjectFullName() );
900 wxString currentProjectDirPath = currentProjectFile.GetPath();
901 wxString currentProjectName = Prj().GetProjectName();
902
903 wxString default_dir = m_frame->GetMruPath();
904
905 Prj().GetProjectFile().SaveToFile( currentProjectDirPath );
906 Prj().GetLocalSettings().SaveToFile( currentProjectDirPath );
907
908 if( default_dir == currentProjectDirPath
909 || default_dir == currentProjectDirPath + wxFileName::GetPathSeparator() )
910 {
911 // Don't start within the current project
912 wxFileName default_dir_fn( default_dir );
913 default_dir_fn.RemoveLastDir();
914 default_dir = default_dir_fn.GetPath();
915 }
916
917 wxFileDialog dlg( m_frame, _( "Save Project To" ), default_dir, wxEmptyString, wxEmptyString, wxFD_SAVE );
918
919 dlg.AddShortcut( PATHS::GetDefaultUserProjectsPath() );
920
922
923 if( dlg.ShowModal() == wxID_CANCEL )
924 return -1;
925
926 wxFileName newProjectDir( dlg.GetPath(), wxEmptyString );
927
928 if( !newProjectDir.IsAbsolute() )
929 newProjectDir.MakeAbsolute();
930
931 if( wxDirExists( newProjectDir.GetFullPath() ) )
932 {
933 msg.Printf( _( "'%s' already exists." ), newProjectDir.GetFullPath() );
935 return -1;
936 }
937
938 if( !wxMkdir( newProjectDir.GetFullPath() ) )
939 {
940 DisplayErrorMessage( m_frame, wxString::Format( _( "Folder '%s' could not be created.\n\n"
941 "Please make sure you have sufficient permissions." ),
942 newProjectDir.GetPath() ) );
943 return -1;
944 }
945
946 if( !newProjectDir.IsDirWritable() )
947 {
948 DisplayErrorMessage( m_frame, wxString::Format( _( "Insufficient permissions to write to folder '%s'." ),
949 newProjectDir.GetFullPath() ) );
950 return -1;
951 }
952
953 const wxString& newProjectDirPath = newProjectDir.GetFullPath();
954 const wxString& newProjectName = newProjectDir.GetDirs().Last();
955 wxDir currentProjectDir( currentProjectDirPath );
956
957 PROJECT_TREE_TRAVERSER traverser( m_frame, currentProjectDirPath, currentProjectName,
958 newProjectDirPath, newProjectName );
959
960 currentProjectDir.Traverse( traverser );
961
962 if( !traverser.GetErrors().empty() )
963 DisplayErrorMessage( m_frame, traverser.GetErrors() );
964
965 if( !traverser.GetNewProjectFile().FileExists() )
966 m_frame->CreateNewProject( traverser.GetNewProjectFile() );
967
968 m_frame->LoadProject( traverser.GetNewProjectFile() );
969
970 return 0;
971}
972
973
975{
976 m_frame->RefreshProjectTree();
977 return 0;
978}
979
980
982{
983 ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
984 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
985 SELECTION dummySel;
986
987 if( conditionalMenu )
988 conditionalMenu->Evaluate( dummySel );
989
990 if( actionMenu )
991 actionMenu->UpdateAll();
992
993 return 0;
994}
995
996
998{
999 FRAME_T playerType = aEvent.Parameter<FRAME_T>();
1000 KIWAY_PLAYER* player;
1001
1002 if( playerType == FRAME_SCH && !m_frame->IsProjectActive() )
1003 {
1004 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a schematic." ), wxEmptyString );
1005 return -1;
1006 }
1007 else if( playerType == FRAME_PCB_EDITOR && !m_frame->IsProjectActive() )
1008 {
1009 DisplayInfoMessage( m_frame, _( "Create (or open) a project to edit a pcb." ), wxEmptyString );
1010 return -1;
1011 }
1012
1013 if( m_inShowPlayer )
1014 return -1;
1015
1017
1018 try
1019 {
1020 player = m_frame->Kiway().Player( playerType, true );
1021 }
1022 catch( const IO_ERROR& err )
1023 {
1024 wxLogError( _( "Application failed to load:\n" ) + err.What() );
1025 return -1;
1026 }
1027
1028 if ( !player )
1029 {
1030 wxLogError( _( "Application cannot start." ) );
1031 return -1;
1032 }
1033
1034 if( !player->IsVisible() ) // A hidden frame might not have the document loaded.
1035 {
1036 wxString filepath;
1037
1038 if( playerType == FRAME_SCH )
1039 {
1040 wxFileName kicad_schematic( m_frame->SchFileName() );
1041 wxFileName legacy_schematic( m_frame->SchLegacyFileName() );
1042
1043 if( !legacy_schematic.FileExists() || kicad_schematic.FileExists() )
1044 filepath = kicad_schematic.GetFullPath();
1045 else
1046 filepath = legacy_schematic.GetFullPath();
1047 }
1048 else if( playerType == FRAME_PCB_EDITOR )
1049 {
1050 wxFileName kicad_board( m_frame->PcbFileName() );
1051 wxFileName legacy_board( m_frame->PcbLegacyFileName() );
1052
1053 if( !legacy_board.FileExists() || kicad_board.FileExists() )
1054 filepath = kicad_board.GetFullPath();
1055 else
1056 filepath = legacy_board.GetFullPath();
1057 }
1058
1059 if( !filepath.IsEmpty() )
1060 {
1061 std::vector<wxString> file_list{ filepath };
1062
1063 if( !player->OpenProjectFiles( file_list ) )
1064 {
1065 player->Destroy();
1066 return -1;
1067 }
1068 }
1069
1070 wxBusyCursor busy;
1071 player->Show( true );
1072 }
1073
1074 // Needed on Windows, other platforms do not use it, but it creates no issue
1075 if( player->IsIconized() )
1076 player->Iconize( false );
1077
1078 player->Raise();
1079
1080 // Raising the window does not set the focus on Linux. This should work on
1081 // any platform.
1082 if( wxWindow::FindFocus() != player )
1083 player->SetFocus();
1084
1085 // Save window state to disk now. Don't wait around for a crash.
1086 if( Pgm().GetCommonSettings()->m_Session.remember_open_files
1087 && !player->GetCurrentFileName().IsEmpty()
1088 && Prj().GetLocalSettings().ShouldAutoSave() )
1089 {
1090 wxFileName rfn( player->GetCurrentFileName() );
1091 rfn.MakeRelativeTo( Prj().GetProjectPath() );
1092
1093 WINDOW_SETTINGS windowSettings;
1094 player->SaveWindowSettings( &windowSettings );
1095
1096 Prj().GetLocalSettings().SaveFileState( rfn.GetFullPath(), &windowSettings, true );
1097 Prj().GetLocalSettings().SaveToFile( Prj().GetProjectPath() );
1098 }
1099
1100 return 0;
1101}
1102
1103
1105{
1106 wxString execFile;
1107 wxString param;
1108
1110 execFile = GERBVIEW_EXE;
1112 execFile = PCB_CALCULATOR_EXE;
1114 execFile = PL_EDITOR_EXE;
1116 execFile = Pgm().GetTextEditor();
1117 else if( aEvent.IsAction( &KICAD_MANAGER_ACTIONS::editOtherSch ) )
1118 execFile = EESCHEMA_EXE;
1119 else if( aEvent.IsAction( &KICAD_MANAGER_ACTIONS::editOtherPCB ) )
1120 execFile = PCBNEW_EXE;
1121 else
1122 wxFAIL_MSG( "Execute(): unexpected request" );
1123
1124 if( execFile.IsEmpty() )
1125 return 0;
1126
1127 if( aEvent.Parameter<wxString*>() )
1128 param = *aEvent.Parameter<wxString*>();
1129 else if( aEvent.IsAction( &KICAD_MANAGER_ACTIONS::viewGerbers ) && m_frame->IsProjectActive() )
1130 param = m_frame->Prj().GetProjectPath();
1131
1132 COMMON_CONTROL* commonControl = m_toolMgr->GetTool<COMMON_CONTROL>();
1133 return commonControl->Execute( execFile, param );
1134}
1135
1136
1138{
1140 {
1141 // policy disables the plugin manager
1142 return 0;
1143 }
1144
1145 // For some reason, after a click or a double click the bitmap button calling
1146 // PCM keeps the focus althougt the focus was not set to this button.
1147 // This hack force removing the focus from this button
1148 m_frame->SetFocus();
1149 wxSafeYield();
1150
1151 if( !m_frame->GetPcm() )
1152 m_frame->CreatePCM();
1153
1154 DIALOG_PCM pcm( m_frame, m_frame->GetPcm() );
1155 pcm.ShowModal();
1156
1157 const std::unordered_set<PCM_PACKAGE_TYPE>& changed = pcm.GetChangedPackageTypes();
1158
1159 if( changed.count( PCM_PACKAGE_TYPE::PT_PLUGIN ) || changed.count( PCM_PACKAGE_TYPE::PT_FAB ) )
1160 {
1161 std::string payload = "";
1162 m_frame->Kiway().ExpressMail( FRAME_PCB_EDITOR, MAIL_RELOAD_PLUGINS, payload );
1163 }
1164
1165 KICAD_SETTINGS* settings = GetAppSettings<KICAD_SETTINGS>( "kicad" );
1166
1167 if( changed.count( PCM_PACKAGE_TYPE::PT_LIBRARY )
1168 && ( settings->m_PcmLibAutoAdd || settings->m_PcmLibAutoRemove ) )
1169 {
1170 KIWAY& kiway = m_frame->Kiway();
1171
1172 // Reset state containing global lib tables
1173 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_SCH, false ) )
1174 kiface->Reset();
1175
1176 if( KIFACE* kiface = kiway.KiFACE( KIWAY::FACE_PCB, false ) )
1177 kiface->Reset();
1178
1179 // Reload lib tables
1180 std::string payload = "";
1181
1184 kiway.ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload );
1186 kiway.ExpressMail( FRAME_SCH_VIEWER, MAIL_RELOAD_LIB, payload );
1187 }
1188
1189 if( changed.count( PCM_PACKAGE_TYPE::PT_COLORTHEME ) )
1191
1192 return 0;
1193}
1194
1195
1197{
1208
1216
1219
1228
1231
1233}
const char * name
static TOOL_ACTION zoomRedraw
Definition actions.h:128
static TOOL_ACTION saveAs
Definition actions.h:55
static TOOL_ACTION showGitCommitPane
Definition actions.h:263
static TOOL_ACTION updateMenu
Definition actions.h:267
Define the structure of a menu based on ACTIONs.
Definition action_menu.h:43
void UpdateAll()
Run update handlers for the menu and its submenus.
Handle actions that are shared between different applications.
int Execute(const TOOL_EVENT &aEvent)
What an export to a given target will keep, approximate, drop, or block.
void Add(DOWNGRADE_BUCKET aBucket, const wxString &aFeature, const wxString &aDetail=wxEmptyString, int aCount=1)
bool IsLossy() const
True if anything is approximated or dropped. This is what triggers the lossy warning.
bool IsBlocked() const
True if some feature makes the target impossible. The user cannot export anyway.
Shows what an export will approximate, drop, or refuse.
wxString GetVariant() const
The variant to flatten, or empty for the base design.
KIGIT_COMMON::GIT_CONN_TYPE GetRepoType() const
wxString GetRepoSSHPath() const
Implementing pcm main dialog.
Definition dialog_pcm.h:39
const std::unordered_set< PCM_PACKAGE_TYPE > & GetChangedPackageTypes() const
Returns types of packages that were installed/uninstalled.
Definition dialog_pcm.h:82
int ShowModal() override
wxString GetBrowsedTemplatesPath() const
Last directory chosen via the "Browse..." button so the caller can persist it.
virtual bool IsContentModified() const
Get if the contents of the frame have been modified since the last save.
bool GetCreateNewDir() const
Gets the selected state of the create new directory checkbox.
void SetRemote(const wxString &aRemote)
void SetClonePath(const wxString &aPath)
void SetProgressReporter(std::unique_ptr< PROGRESS_REPORTER > aProgressReporter)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
static TOOL_ACTION viewDroppedGerbers
static TOOL_ACTION openDemoProject
static TOOL_ACTION unarchiveProject
static TOOL_ACTION loadProject
static TOOL_ACTION exportForOlderVersion
static TOOL_ACTION editOtherPCB
static TOOL_ACTION restoreLocalHistory
static TOOL_ACTION newProject
static TOOL_ACTION editOtherSch
static TOOL_ACTION showLocalHistory
static TOOL_ACTION editSchematic
static TOOL_ACTION openTextEditor
static TOOL_ACTION archiveProject
static TOOL_ACTION openProject
static TOOL_ACTION closeProject
static TOOL_ACTION 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
int ExportForOlderVersion(const TOOL_EVENT &aEvent)
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
Set up handlers for various events.
int OpenDemoProject(const TOOL_EVENT &aEvent)
int CloseProject(const TOOL_EVENT &aEvent)
int ToggleLocalHistory(const TOOL_EVENT &aEvent)
int ArchiveProject(const TOOL_EVENT &aEvent)
bool m_inShowPlayer
Re-entrancy guard.
int SaveProjectAs(const TOOL_EVENT &aEvent)
int NewProject(const TOOL_EVENT &aEvent)
int RestoreLocalHistory(const TOOL_EVENT &aEvent)
int UnarchiveProject(const TOOL_EVENT &aEvent)
int ViewDroppedViewers(const TOOL_EVENT &aEvent)
Imports a non kicad project from a sch/pcb dropped file.
int ShowPluginManager(const TOOL_EVENT &aEvent)
int UpdateMenu(const TOOL_EVENT &aEvent)
int OpenJobsetFile(const TOOL_EVENT &aEvent)
int ToggleGitCommitPane(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)
KIGIT_QUERY m_identityQuery
Read the identity after cloning. Closing or resetting the tool suppresses its prompt.
std::vector< wxString > m_RecentTemplates
wxSize m_TemplateWindowSize
wxString m_BrowsedTemplatesPath
wxPoint m_TemplateWindowPos
wxString m_LastUsedTemplate
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:51
int ShowModal() override
Definition kidialog.cpp:89
The project's git session.
std::vector< wxString > GetProjectDirs()
Return a vector of project files in the repository.
git_repository * GetRepo() const
static REMOTE_URL ParseRemoteURL(const wxString &aURL)
void SetRepo(git_repository *aRepo)
KIGIT_ERROR_MESSAGE PopError()
Take the newest error with its details. Both are empty when none is queued.
void SetPassword(const wxString &aPassword)
Set the password.
std::optional< KIGIT::HOST_KEY_FAILURE > GetHostKeyFailure() const
The host key this operation's transfer refused, for the UI to offer to trust or to report.
void SetUsername(const wxString &aUsername)
Set the username.
bool IsThisOperationCancelled() const
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:348
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr, bool aFromOtherThread=false)
Send aPayload to aDestination from aSource.
Definition kiway.cpp:499
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition kiway.cpp:214
@ FACE_SCH
eeschema DSO
Definition kiway.h:355
@ FACE_PCB
pcbnew DSO
Definition kiway.h:356
static wxString GetUserTemplatesPath()
Gets the user path for custom templates.
Definition paths.cpp:71
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition paths.cpp:137
static wxString GetStockDemosPath()
Gets the stock (install) demos path.
Definition paths.cpp:411
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition pgm_base.cpp:808
virtual const wxString & GetTextEditor(bool aCanShowFileChooser=true)
Return the path to the preferred text editor application.
Definition pgm_base.cpp:233
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:123
static bool Archive(const wxString &aSrcDir, const wxString &aDestFile, REPORTER &aReporter, bool aVerbose=true, bool aIncludeExtraFiles=false)
Create an archive of the project.
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Calls Store() and then writes the contents of the JSON document to a file.
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Calls Store() and then writes the contents of the JSON document to a file.
void SaveFileState(const wxString &aFileName, const WINDOW_SETTINGS *aWindowCfg, bool aOpen)
A class which provides project template functionality.
size_t GetDestinationFiles(const wxFileName &aNewProjectPath, std::vector< wxFileName > &aDestFiles)
Fetch the list of destination files to be copied when the new project is created.
wxFileName GetHtmlFile()
Get the full Html filename for the project template.
bool CreateProject(wxFileName &aNewProjectPath, wxString *aErrorMsg=nullptr)
Copies and renames all template files to create a new project.
Traverser class to duplicate/copy project or template files with proper renaming.
wxFileName GetNewProjectFile() const
virtual std::shared_ptr< KIGIT_COMMON > GetGitCommon() const
This project's Git session, created empty on first use.
Definition project.cpp:84
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:288
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition project.h:207
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:201
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:410
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:182
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:74
Generic, UI-independent tool event.
Definition tool_event.h:167
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:484
void RunMainStack(std::function< void()> aFunc)
Call a function using the main stack.
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_INTERACTIVE(TOOL_ID aId, const std::string &aName)
Create a tool with given id & name.
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject, bool aAllowEscapes)
Replace any environment variable & text variable references with their values.
Definition common.cpp:777
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:245
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
This file is part of the common library.
const std::vector< DOWNGRADE_TARGET > & GetDowngradeTargets()
Supported downgrade targets, newest first.
#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 PCBNEW_EXE
const wxString PCB_CALCULATOR_EXE
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition frame_type.h:29
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:41
@ FRAME_SCH_VIEWER
Definition frame_type.h:32
@ FRAME_SCH
Definition frame_type.h:30
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
@ FRAME_CVPCB
Definition frame_type.h:48
static const std::string ProjectFileExtension
static const std::string LegacyProjectFileExtension
static const std::string ArchiveFileExtension
static wxString ProjectFileWildcard()
static wxString JobsetFileWildcard()
static wxString LegacyProjectFileWildcard()
static wxString AllProjectFilesWildcard()
static wxString ZipFileWildcard()
std::string message
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
PROJECT & Prj()
Definition kicad.cpp:737
bool LaunchExternal(const wxString &aPath)
Launches the given file or folder in the host OS.
@ MAIL_SCH_SAVE
Definition mail_type.h:38
@ MAIL_RELOAD_PLUGINS
Definition mail_type.h:56
@ MAIL_PCB_SAVE
Definition mail_type.h:39
@ MAIL_RELOAD_LIB
Definition mail_type.h:55
KICOMMON_API std::optional< wxString > GetVersionedEnvVarValue(const std::map< wxString, ENV_VAR_ITEM > &aMap, const wxString &aBaseName)
Attempt to retrieve the value of a versioned environment variable, such as KICAD8_TEMPLATE_DIR.
Definition env_vars.cpp:103
GIT_IDENTITY ReadGitIdentity(KIGIT_COMMON &aCommon)
Read on a worker while holding the session's action lock.
bool EnsureGitIdentity(wxWindow *aParent, EDA_BASE_FRAME *aFrame, const std::shared_ptr< KIGIT_COMMON > &aCommon, const GIT_IDENTITY &aIdentity)
Open the same editor when the worker snapshot has no usable Git identity.
bool PromptToTrustHost(wxWindow *aParent, const HOST_KEY_FAILURE &aFailure, bool aRetriedAfterTrust)
Ask whether to trust a server seen for the first time, and remember its key when the user agrees.
PBOOL GetPolicyBool(const wxString &aKey)
bool StoreSecret(const wxString &aService, const wxString &aKey, const wxString &aSecret)
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:640
@ PT_COLORTHEME
Definition pcm_data.h:48
@ PT_PLUGIN
Definition pcm_data.h:44
@ PT_LIBRARY
Definition pcm_data.h:46
@ PT_FAB
Definition pcm_data.h:45
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
#define POLICY_KEY_PCM
Definition policy_keys.h:27
bool ExportProjectForDowngrade(KIWAY &aKiway, const wxString &aProjectDir, const wxString &aProjectName, const wxString &aTargetName, const wxString &aDestDir, wxString &aError, const wxString &aVariant, bool aDropInsteadOfApproximate)
Export a downgraded copy of the project into aDestDir.
bool ClassifyProjectForDowngrade(KIWAY &aKiway, const wxString &aProjectDir, const wxString &aProjectName, const wxString &aTargetName, COMPATIBILITY_REPORT &aReport, wxString &aError, std::vector< wxString > *aFoundVariants, bool aDropInsteadOfApproximate, const wxString &aVariant)
Run the board and schematic classification for a whole project without writing anything.
wxFileName EnsureDefaultProjectTemplate(const wxString &aBaseDir)
Seed the built-in "default" project template under aBaseDir, creating the directory tree and minimal ...
T * GetAppSettings(const char *aFilename)
An older KiCad release we can export a project back to.
Implement a participant in the KIWAY alchemy.
Definition kiway.h:153
Repository values and whether Git can use them to record a commit.
A summary the user can act on, with the raw text that explains it kept apart for the details.
Store the common settings that are saved and loaded for each window / frame.
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)
IbisParser parser & reporter
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition wx_filename.h:35
#define PR_CAN_ABORT