KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pgm_base.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) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
6 * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
33#include <wx/html/htmlwin.h>
34#include <wx/fs_zip.h>
35#include <wx/dir.h>
36#include <wx/filename.h>
37#include <wx/propgrid/propgrid.h>
38#include <wx/snglinst.h>
39#include <wx/stdpaths.h>
40#include <wx/sysopt.h>
41#include <wx/filedlg.h>
42#include <wx/ffile.h>
43#include <wx/tooltip.h>
44
45#include <advanced_config.h>
47#include <bitmaps.h>
48#include <build_version.h>
49#include <common.h>
50#include <confirm.h>
51#include <core/arraydim.h>
52#include <id.h>
54#include <kiplatform/policy.h>
55#include <macros.h>
57#include <paths.h>
58#include <pgm_base.h>
59#include <policy_keys.h>
60#include <python_scripting.h>
63#include <string_utils.h>
64#include <systemdirsappend.h>
65#include <core/thread_pool.h>
66#include <trace_helpers.h>
67
68#include <widgets/wx_splash.h>
69
70#ifdef KICAD_USE_SENTRY
71#include <boost/uuid/uuid_io.hpp>
72#include <boost/uuid/uuid_generators.hpp>
73#include <sentry.h>
74#include <build_version.h>
75#endif
76
86#undef _
87#define _(s) s
89{
90 { wxLANGUAGE_DEFAULT, ID_LANGUAGE_DEFAULT, _( "Default" ), false },
91// { wxLANGUAGE_INDONESIAN, ID_LANGUAGE_INDONESIAN, wxT( "Bahasa Indonesia" ), true },
92 { wxLANGUAGE_CZECH, ID_LANGUAGE_CZECH, wxT( "Čeština" ), true },
93 { wxLANGUAGE_DANISH, ID_LANGUAGE_DANISH, wxT( "Dansk" ), true },
94 { wxLANGUAGE_GERMAN, ID_LANGUAGE_GERMAN, wxT( "Deutsch" ), true },
95 { wxLANGUAGE_GREEK, ID_LANGUAGE_GREEK, wxT( "Ελληνικά" ), true },
96 { wxLANGUAGE_ENGLISH, ID_LANGUAGE_ENGLISH, wxT( "English" ), true },
97 { wxLANGUAGE_SPANISH, ID_LANGUAGE_SPANISH, wxT( "Español" ), true },
98 { wxLANGUAGE_SPANISH_MEXICAN, ID_LANGUAGE_SPANISH_MEXICAN,
99 wxT( "Español (Latinoamericano)" ), true },
100 { wxLANGUAGE_FRENCH, ID_LANGUAGE_FRENCH, wxT( "Français" ), true },
101 { wxLANGUAGE_KOREAN, ID_LANGUAGE_KOREAN, wxT( "한국어"), true },
102 { wxLANGUAGE_ITALIAN, ID_LANGUAGE_ITALIAN, wxT( "Italiano" ), true },
103 { wxLANGUAGE_LITHUANIAN, ID_LANGUAGE_LITHUANIAN, wxT( "Lietuvių" ), true },
104// { wxLANGUAGE_HUNGARIAN, ID_LANGUAGE_HUNGARIAN, wxT( "Magyar" ), true },
105 { wxLANGUAGE_DUTCH, ID_LANGUAGE_DUTCH, wxT( "Nederlands" ), true },
106 { wxLANGUAGE_JAPANESE, ID_LANGUAGE_JAPANESE, wxT( "日本語" ), true },
107 { wxLANGUAGE_THAI, ID_LANGUAGE_THAI, wxT( "ภาษาไทย" ), true },
108 { wxLANGUAGE_POLISH, ID_LANGUAGE_POLISH, wxT( "Polski" ), true },
109 { wxLANGUAGE_PORTUGUESE, ID_LANGUAGE_PORTUGUESE, wxT( "Português" ),true },
110 { wxLANGUAGE_PORTUGUESE_BRAZILIAN, ID_LANGUAGE_PORTUGUESE_BRAZILIAN,
111 wxT( "Português (Brasil)" ), true },
112 { wxLANGUAGE_RUSSIAN, ID_LANGUAGE_RUSSIAN, wxT( "Русский" ), true },
113// { wxLANGUAGE_SERBIAN, ID_LANGUAGE_SERBIAN, wxT( "Српски" ), true },
114 { wxLANGUAGE_FINNISH, ID_LANGUAGE_FINNISH, wxT( "Suomi" ), true },
115 { wxLANGUAGE_SWEDISH, ID_LANGUAGE_SWEDISH, wxT( "Svenska" ), true },
116// { wxLANGUAGE_VIETNAMESE, ID_LANGUAGE_VIETNAMESE, wxT( "Tiếng Việt" ), true },
117// { wxLANGUAGE_TURKISH, ID_LANGUAGE_TURKISH, wxT( "Türkçe" ), true },
118 { wxLANGUAGE_UKRAINIAN, ID_LANGUAGE_UKRANIAN, wxT( "Українська" ), true },
119 { wxLANGUAGE_CHINESE_SIMPLIFIED, ID_LANGUAGE_CHINESE_SIMPLIFIED,
120 wxT( "简体中文" ), true },
121 { wxLANGUAGE_CHINESE_TRADITIONAL, ID_LANGUAGE_CHINESE_TRADITIONAL,
122 wxT( "繁體中文" ), true },
123 { 0, 0, "", false } // Sentinel
124};
125#undef _
126#define _(s) wxGetTranslation((s))
127
128
130{
131 m_locale = nullptr;
132 m_Printing = false;
133 m_Quitting = false;
134 m_argcUtf8 = 0;
135 m_argvUtf8 = nullptr;
136 m_splash = nullptr;
137
138 setLanguageId( wxLANGUAGE_DEFAULT );
139
140 ForceSystemPdfBrowser( false );
141}
142
143
145{
146 HideSplash();
147 Destroy();
148
149 for( int n = 0; n < m_argcUtf8; n++ )
150 {
151 free( m_argvUtf8[n] );
152 }
153
154 delete[] m_argvUtf8;
155}
156
157
159{
161
162#ifdef KICAD_USE_SENTRY
163 sentry_close();
164#endif
165
166 // unlike a normal destructor, this is designed to be called more than once safely:
167 delete m_locale;
168 m_locale = nullptr;
169
170 m_pgm_checker.reset();
171}
172
173
175{
176 wxASSERT( wxTheApp );
177 return *wxTheApp;
178}
179
180
181void PGM_BASE::SetTextEditor( const wxString& aFileName )
182{
183 m_text_editor = aFileName;
185}
186
187
188const wxString& PGM_BASE::GetTextEditor( bool aCanShowFileChooser )
189{
190 wxString editorname = m_text_editor;
191
192 if( !editorname )
193 {
194 if( !wxGetEnv( wxT( "EDITOR" ), &editorname ) )
195 {
196 // If there is no EDITOR variable set, try the desktop default
197#ifdef __WXMAC__
198 editorname = wxT( "/usr/bin/open -e" );
199#elif __WXX11__
200 editorname = wxT( "/usr/bin/xdg-open" );
201#endif
202 }
203 }
204
205 // If we still don't have an editor name show a dialog asking the user to select one
206 if( !editorname && aCanShowFileChooser )
207 {
208 DisplayInfoMessage( nullptr, _( "No default editor found, you must choose one." ) );
209
210 editorname = AskUserForPreferredEditor();
211 }
212
213 // If we finally have a new editor name request it to be copied to m_text_editor and
214 // saved to the preferences file.
215 if( !editorname.IsEmpty() )
216 SetTextEditor( editorname );
217
218 // m_text_editor already has the same value that editorname, or empty if no editor was
219 // found/chosen.
220 return m_text_editor;
221}
222
223
224const wxString PGM_BASE::AskUserForPreferredEditor( const wxString& aDefaultEditor )
225{
226 // Create a mask representing the executable files in the current platform
227#ifdef __WINDOWS__
228 wxString mask( _( "Executable file" ) + wxT( " (*.exe)|*.exe" ) );
229#else
230 wxString mask( _( "Executable file" ) + wxT( " (*)|*" ) );
231#endif
232
233 // Extract the path, name and extension from the default editor (even if the editor's
234 // name was empty, this method will succeed and return empty strings).
235 wxString path, name, ext;
236 wxFileName::SplitPath( aDefaultEditor, &path, &name, &ext );
237
238 // Show the modal editor and return the file chosen (may be empty if the user cancels
239 // the dialog).
240 return wxFileSelector( _( "Select Preferred Editor" ), path, name, wxT( "." ) + ext,
241 mask, wxFD_OPEN | wxFD_FILE_MUST_EXIST, nullptr );
242}
243
244
245#ifdef KICAD_USE_SENTRY
246bool PGM_BASE::IsSentryOptedIn()
247{
248 KIPLATFORM::POLICY::PBOOL policyState =
251 {
252 return policyState == KIPLATFORM::POLICY::PBOOL::ENABLED;
253 }
254
255 return m_sentry_optin_fn.Exists();
256}
257
258
259void PGM_BASE::SetSentryOptIn( bool aOptIn )
260{
261 if( aOptIn )
262 {
263 if( !m_sentry_uid_fn.Exists() )
264 {
265 sentryCreateUid();
266 }
267
268 if( !m_sentry_optin_fn.Exists() )
269 {
270 wxFFile sentryInitFile( m_sentry_optin_fn.GetFullPath(), "w" );
271 sentryInitFile.Write( "" );
272 sentryInitFile.Close();
273 }
274 }
275 else
276 {
277 if( m_sentry_optin_fn.Exists() )
278 {
279 wxRemoveFile( m_sentry_optin_fn.GetFullPath() );
280 sentry_close();
281 }
282 }
283}
284
285
286wxString PGM_BASE::sentryCreateUid()
287{
288 boost::uuids::uuid uuid = boost::uuids::random_generator()();
289 wxString userGuid = boost::uuids::to_string( uuid );
290
291 wxFFile sentryInitFile( m_sentry_uid_fn.GetFullPath(), "w" );
292 sentryInitFile.Write( userGuid );
293 sentryInitFile.Close();
294
295 return userGuid;
296}
297
298
299void PGM_BASE::ResetSentryId()
300{
301 m_sentryUid = sentryCreateUid();
302}
303
304
305const wxString& PGM_BASE::GetSentryId()
306{
307 return m_sentryUid;
308}
309
310
311void PGM_BASE::sentryInit()
312{
313 m_sentry_optin_fn = wxFileName( PATHS::GetUserCachePath(), "sentry-opt-in" );
314 m_sentry_uid_fn = wxFileName( PATHS::GetUserCachePath(), "sentry-uid" );
315
316 if( IsSentryOptedIn() )
317 {
318 wxFFile sentryInitFile( m_sentry_uid_fn.GetFullPath() );
319 sentryInitFile.ReadAll( &m_sentryUid );
320 sentryInitFile.Close();
321
322 if( m_sentryUid.IsEmpty() || m_sentryUid.length() != 36 )
323 {
324 m_sentryUid = sentryCreateUid();
325 }
326
327 sentry_options_t* options = sentry_options_new();
328
329 #ifndef KICAD_SENTRY_DSN
330 # error "Project configuration error, missing KICAD_SENTRY_DSN"
331 #endif
332
333 sentry_options_set_dsn( options, KICAD_SENTRY_DSN );
334
335 wxFileName tmp;
336 tmp.AssignDir( PATHS::GetUserCachePath() );
337 tmp.AppendDir( "sentry" );
338
339#ifdef __WINDOWS__
340 sentry_options_set_database_pathw( options, tmp.GetPathWithSep().wc_str() );
341#else
342 sentry_options_set_database_path( options, tmp.GetPathWithSep().c_str() );
343#endif
344 sentry_options_set_symbolize_stacktraces( options, true );
345 sentry_options_set_auto_session_tracking( options, false );
346
347 sentry_options_set_release( options, GetCommitHash().ToStdString().c_str() );
348
349 // This just gives us more filtering within sentry, issues still get grouped across
350 // environments.
351 sentry_options_set_environment( options, GetMajorMinorVersion().c_str() );
352
353 sentry_init( options );
354
355 sentry_value_t user = sentry_value_new_object();
356 sentry_value_set_by_key( user, "id", sentry_value_new_string( m_sentryUid.c_str() ) );
357 sentry_set_user( user );
358
359 sentry_set_tag( "kicad.version", GetBuildVersion().ToStdString().c_str() );
360 }
361}
362
363
364void PGM_BASE::sentryPrompt()
365{
366 if( !IsGUI() )
367 return;
368
369 KIPLATFORM::POLICY::PBOOL policyState =
371
373 && !m_settings_manager->GetCommonSettings()->m_DoNotShowAgain.data_collection_prompt )
374 {
375 wxMessageDialog optIn = wxMessageDialog(
376 nullptr,
377 _( "KiCad can anonymously report crashes and special event "
378 "data to developers in order to aid identifying critical bugs "
379 "across the user base more effectively and help profile "
380 "functionality to guide improvements. \n"
381 "If you choose to voluntarily participate, KiCad will automatically "
382 "handle sending said reports when crashes or events occur. \n"
383 "Your design files such as schematic or PCB are not shared in this process." ),
384 _( "Data collection opt in request" ), wxYES_NO | wxCENTRE );
385
386 int result = optIn.ShowModal();
387
388 if( result == wxID_YES )
389 {
390 SetSentryOptIn( true );
391 sentryInit();
392 }
393 else
394 {
395 SetSentryOptIn( false );
396 }
397
398 m_settings_manager->GetCommonSettings()->m_DoNotShowAgain.data_collection_prompt = true;
399 }
400}
401#endif
402
403
405{
406 const wxArrayString& argArray = App().argv.GetArguments();
407 m_argcUtf8 = argArray.size();
408
409 m_argvUtf8 = new char*[m_argcUtf8 + 1];
410 for( int n = 0; n < m_argcUtf8; n++ )
411 {
412 m_argvUtf8[n] = wxStrdup( argArray[n].ToUTF8() );
413 }
414
415 m_argvUtf8[m_argcUtf8] = NULL; // null terminator at end of argv
416}
417
418
420{
421 // Disabling until we change to load each DSO at startup rather than lazy-load when needed.
422 // Note that once the splash screen is re-enabled, there are some remaining bugs to fix:
423 // Any wxWidgets error dialogs that appear during startup are hidden by the splash screen,
424 // so we either need to prevent these from happening (probably not feasible) or else change
425 // the error-handling path to make sure errors go on top of the splash.
426#if 0
427 if( m_splash )
428 return;
429
430 m_splash = new WX_SPLASH( KiBitmap( BITMAPS::splash ), wxSPLASH_CENTRE_ON_SCREEN, 0,
431 NULL, -1, wxDefaultPosition, wxDefaultSize,
432 wxBORDER_NONE | wxSTAY_ON_TOP );
433 wxYield();
434#endif
435}
436
437
439{
440 if( !m_splash )
441 return;
442
443 m_splash->Close( true );
444 m_splash->Destroy();
445 m_splash = nullptr;
446}
447
448
449bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit, bool aIsUnitTest )
450{
451#if defined( __WXMAC__ )
452 // Set the application locale to the system default
453 wxLogNull noLog;
454 wxLocale loc;
455 loc.Init();
456#endif
457
458 // Just make sure we init precreate any folders early for later code
459 // In particular, the user cache path is the most likely to be hit by startup code
461
463
464#ifdef KICAD_USE_SENTRY
465 sentryInit();
466#endif
467 wxString pgm_name;
468
470 if( App().argc == 0 )
471 pgm_name = wxT( "kicad" );
472 else
473 pgm_name = wxFileName( App().argv[0] ).GetName().Lower();
474
475#ifdef KICAD_USE_SENTRY
476 sentry_set_tag( "kicad.app", pgm_name.c_str() );
477#endif
478
479 wxInitAllImageHandlers();
480
481 // Without this the wxPropertyGridManager segfaults on Windows.
482 if( !wxPGGlobalVars )
483 wxPGInitResourceModule();
484
485#ifndef __WINDOWS__
486 if( wxString( wxGetenv( "HOME" ) ).IsEmpty() )
487 {
488 DisplayErrorMessage( nullptr, _( "Environment variable HOME is empty. "
489 "Unable to continue." ) );
490 return false;
491 }
492#endif
493
494 wxString instanceCheckerDir = PATHS::GetInstanceCheckerPath();
495 PATHS::EnsurePathExists( instanceCheckerDir );
496
497 wxString instanceCheckerName = wxString::Format( wxS( "%s-%s" ), pgm_name,
499
500 m_pgm_checker = std::make_unique<wxSingleInstanceChecker>();
501 m_pgm_checker->Create( instanceCheckerName, instanceCheckerDir );
502
503 // Init KiCad environment
504 // the environment variable KICAD (if exists) gives the kicad path:
505 // something like set KICAD=d:\kicad
506 bool isDefined = wxGetEnv( wxT( "KICAD" ), &m_kicad_env );
507
508 if( isDefined ) // ensure m_kicad_env ends by "/"
509 {
511
512 if( !m_kicad_env.IsEmpty() && m_kicad_env.Last() != '/' )
514 }
515
516 // Init parameters for configuration
517 App().SetVendorName( wxT( "KiCad" ) );
518 App().SetAppName( pgm_name );
519
520 // Install some image handlers, mainly for help
521 if( wxImage::FindHandler( wxBITMAP_TYPE_PNG ) == nullptr )
522 wxImage::AddHandler( new wxPNGHandler );
523
524 if( wxImage::FindHandler( wxBITMAP_TYPE_GIF ) == nullptr )
525 wxImage::AddHandler( new wxGIFHandler );
526
527 if( wxImage::FindHandler( wxBITMAP_TYPE_JPEG ) == nullptr )
528 wxImage::AddHandler( new wxJPEGHandler );
529
530 wxFileSystem::AddHandler( new wxZipFSHandler );
531
532 // Analyze the command line & initialize the binary path
533 wxString tmp;
535 SetDefaultLanguage( tmp );
536
537#ifdef _MSC_VER
538 // We need to set this because the internal fontconfig logic
539 // seems to search relative to the dll rather the other logic it
540 // has to look for the /etc folder above the dll
541 wxSetEnv( "FONTCONFIG_PATH", PATHS::GetWindowsFontConfigDir() );
542#endif
543
544 m_settings_manager = std::make_unique<SETTINGS_MANAGER>( aHeadless );
545 m_background_jobs_monitor = std::make_unique<BACKGROUND_JOBS_MONITOR>();
546 m_notifications_manager = std::make_unique<NOTIFICATIONS_MANAGER>();
547
548 // Our unit test mocks break if we continue
549 // A bug caused InitPgm to terminate early in unit tests and the mocks are...simplistic
550 // TODO fix the unit tests so this can be removed
551 if( aIsUnitTest )
552 return false;
553
554 // Something got in the way of settings load: can't continue
555 if( !m_settings_manager->IsOK() )
556 return false;
557
558 // Set up built-in environment variables (and override them from the system environment if set)
560
561 // Load color settings after env is initialized
562 m_settings_manager->ReloadColorSettings();
563
564 // Load common settings from disk after setting up env vars
566
567 // Init user language *before* calling loadSettings, because
568 // env vars could be incorrectly initialized on Linux
569 // (if the value contains some non ASCII7 chars, the env var is not initialized)
570 SetLanguage( tmp, true );
571
572 // Now that translations are available, inform the user if the OS is unsupported
574
576
577#ifdef KICAD_USE_SENTRY
578 sentryPrompt();
579#endif
580
581 ReadPdfBrowserInfos(); // needs GetCommonSettings()
582
584
585 // Create the python scripting stuff
586 // Skip it fot applications that do not use it
587 if( !aSkipPyInit )
588 m_python_scripting = std::make_unique<SCRIPTING>();
589
590 // TODO(JE): Remove this if apps are refactored to not assume Prj() always works
591 // Need to create a project early for now (it can have an empty path for the moment)
593
594 // This sets the maximum tooltip display duration to 10s (up from 5) but only affects
595 // Windows as other platforms display tooltips while the mouse is not moving
596 if( !aHeadless )
597 {
598 wxToolTip::Enable( true );
599 wxToolTip::SetAutoPop( 10000 );
600 }
601
602 if( ADVANCED_CFG::GetCfg().m_UpdateUIEventInterval != 0 )
603 wxUpdateUIEvent::SetUpdateInterval( ADVANCED_CFG::GetCfg().m_UpdateUIEventInterval );
604
605 // Now the application can safely start, show the splash screen
606 if( !aHeadless )
607 ShowSplash();
608
609 return true;
610}
611
612
614{
616
617 for( const std::pair<wxString, ENV_VAR_ITEM> it : GetCommonSettings()->m_Env.vars )
618 {
619 wxLogTrace( traceEnvVars, wxT( "PGM_BASE::loadSettings: Found entry %s = %s" ),
620 it.first, it.second.GetValue() );
621
622 // Do not store the env var PROJECT_VAR_NAME ("KIPRJMOD") definition if for some reason
623 // it is found in config. (It is reserved and defined as project path)
624 if( it.first == PROJECT_VAR_NAME )
625 continue;
626
627 // Don't set bogus empty entries in the environment
628 if( it.first.IsEmpty() )
629 continue;
630
631 // Do not overwrite vars set by the system environment with values from the settings file
632 if( it.second.GetDefinedExternally() )
633 continue;
634
635 SetLocalEnvVariable( it.first, it.second.GetValue() );
636 }
637}
638
639
641{
642 // GetCommonSettings() is not initialized until fairly late in the
643 // process startup: InitPgm(), so test before using:
644 if( GetCommonSettings() )
645 GetCommonSettings()->m_System.working_dir = wxGetCwd();
646}
647
648
650{
651 return m_settings_manager ? m_settings_manager->GetCommonSettings() : nullptr;
652}
653
654
655bool PGM_BASE::SetLanguage( wxString& aErrMsg, bool first_time )
656{
657 // Suppress wxWidgets error popups if locale is not found
658 wxLogNull doNotLog;
659
660 if( first_time )
661 {
662 setLanguageId( wxLANGUAGE_DEFAULT );
663
664 // First time SetLanguage is called, the user selected language id is set
665 // from common user config settings
666 wxString languageSel = GetCommonSettings()->m_System.language;
667
668 // Search for the current selection
669 for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
670 {
671 if( LanguagesList[ii].m_Lang_Label == languageSel )
672 {
673 setLanguageId( LanguagesList[ii].m_WX_Lang_Identifier );
674 break;
675 }
676 }
677 }
678
679 // dictionary file name without extend (full name is kicad.mo)
680 wxString dictionaryName( wxT( "kicad" ) );
681
682 delete m_locale;
683 m_locale = new wxLocale;
684
685 // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return
686 // false just because it failed to load wxstd catalog
687 if( !m_locale->Init( m_language_id ) )
688 {
689 wxLogTrace( traceLocale, wxT( "This language is not supported by the system." ) );
690
691 setLanguageId( wxLANGUAGE_DEFAULT );
692 delete m_locale;
693
694 m_locale = new wxLocale;
695 m_locale->Init( wxLANGUAGE_DEFAULT );
696
697 aErrMsg = _( "This language is not supported by the operating system." );
698 return false;
699 }
700 else if( !first_time )
701 {
702 wxLogTrace( traceLocale, wxT( "Search for dictionary %s.mo in %s" ) ,
703 dictionaryName, m_locale->GetName() );
704 }
705
706 if( !first_time )
707 {
708 // If we are here, the user has selected another language.
709 // Therefore the new preferred language name is stored in common config.
710 // Do NOT store the wxWidgets language Id, it can change between wxWidgets
711 // versions, for a given language
712 wxString languageSel;
713
714 // Search for the current selection language name
715 for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
716 {
717 if( LanguagesList[ii].m_WX_Lang_Identifier == m_language_id )
718 {
719 languageSel = LanguagesList[ii].m_Lang_Label;
720 break;
721 }
722 }
723
725 cfg->m_System.language = languageSel;
726 cfg->SaveToFile( GetSettingsManager().GetPathForSettingsFile( cfg ) );
727 }
728
729 // Try adding the dictionary if it is not currently loaded
730 if( !m_locale->IsLoaded( dictionaryName ) )
731 m_locale->AddCatalog( dictionaryName );
732
733 // Verify the Kicad dictionary was loaded properly
734 // However, for the English language, the dictionary is not mandatory, as
735 // all messages are already in English, just restricted to ASCII7 chars,
736 // the verification is skipped.
737 if( !m_locale->IsLoaded( dictionaryName ) && m_language_id != wxLANGUAGE_ENGLISH )
738 {
739 wxLogTrace( traceLocale, wxT( "Unable to load dictionary %s.mo in %s" ),
740 dictionaryName, m_locale->GetName() );
741
742 setLanguageId( wxLANGUAGE_DEFAULT );
743 delete m_locale;
744
745 m_locale = new wxLocale;
746 m_locale->Init( wxLANGUAGE_DEFAULT );
747
748 aErrMsg = _( "The KiCad language file for this language is not installed." );
749 return false;
750 }
751
752 return true;
753}
754
755
756bool PGM_BASE::SetDefaultLanguage( wxString& aErrMsg )
757{
758 // Suppress error popups from wxLocale
759 wxLogNull doNotLog;
760
761 setLanguageId( wxLANGUAGE_DEFAULT );
762
763 // dictionary file name without extend (full name is kicad.mo)
764 wxString dictionaryName( wxT( "kicad" ) );
765
766 delete m_locale;
767 m_locale = new wxLocale;
768 m_locale->Init();
769
770 // Try adding the dictionary if it is not currently loaded
771 if( !m_locale->IsLoaded( dictionaryName ) )
772 m_locale->AddCatalog( dictionaryName );
773
774 // Verify the Kicad dictionary was loaded properly
775 // However, for the English language, the dictionary is not mandatory, as
776 // all messages are already in English, just restricted to ASCII7 chars,
777 // the verification is skipped.
778 if( !m_locale->IsLoaded( dictionaryName ) && m_language_id != wxLANGUAGE_ENGLISH )
779 {
780 wxLogTrace( traceLocale, wxT( "Unable to load dictionary %s.mo in %s" ),
781 dictionaryName, m_locale->GetName() );
782
783 setLanguageId( wxLANGUAGE_DEFAULT );
784 delete m_locale;
785
786 m_locale = new wxLocale;
787 m_locale->Init();
788
789 aErrMsg = _( "The KiCad language file for this language is not installed." );
790 return false;
791 }
792
793 return true;
794}
795
796
798{
799 wxLogTrace( traceLocale, wxT( "Select language ID %d from %d possible languages." ),
800 menu_id, (int)arrayDim( LanguagesList )-1 );
801
802 for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
803 {
804 if( menu_id == LanguagesList[ii].m_KI_Lang_Identifier )
805 {
806 setLanguageId( LanguagesList[ii].m_WX_Lang_Identifier );
807 break;
808 }
809 }
810}
811
812
814{
815 const wxLanguageInfo* langInfo = wxLocale::GetLanguageInfo( m_language_id );
816
817 if( !langInfo )
818 return "";
819 else
820 {
821 wxString str = langInfo->GetCanonicalWithRegion();
822 str.Replace( "_", "-" );
823
824 return str;
825 }
826}
827
828
830{
831#ifdef _MSC_VER
832 wxLocale::AddCatalogLookupPathPrefix( PATHS::GetWindowsBaseSharePath()
833 + wxT( "locale" ) );
834#endif
835 wxLocale::AddCatalogLookupPathPrefix( PATHS::GetLocaleDataPath() );
836
837 if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
838 {
839 wxFileName fn( Pgm().GetExecutablePath() );
840 fn.RemoveLastDir();
841 fn.AppendDir( wxT( "translation" ) );
842 wxLocale::AddCatalogLookupPathPrefix( fn.GetPath() );
843 }
844}
845
846
847bool PGM_BASE::SetLocalEnvVariable( const wxString& aName, const wxString& aValue )
848{
849 wxString env;
850
851 if( aName.IsEmpty() )
852 {
853 wxLogTrace( traceEnvVars,
854 wxT( "PGM_BASE::SetLocalEnvVariable: Attempt to set empty variable to "
855 "value %s" ),
856 aValue );
857 return false;
858 }
859
860 // Check to see if the environment variable is already set.
861 if( wxGetEnv( aName, &env ) )
862 {
863 wxLogTrace( traceEnvVars,
864 wxT( "PGM_BASE::SetLocalEnvVariable: Environment variable %s already set "
865 "to %s" ),
866 aName, env );
867 return env == aValue;
868 }
869
870 wxLogTrace( traceEnvVars,
871 wxT( "PGM_BASE::SetLocalEnvVariable: Setting local environment variable %s to %s" ),
872 aName, aValue );
873
874 return wxSetEnv( aName, aValue );
875}
876
877
879{
880 // Overwrites externally defined environment variable until the next time the application
881 // is run.
882 for( const std::pair<wxString, ENV_VAR_ITEM> m_local_env_var : GetCommonSettings()->m_Env.vars )
883 {
884 wxLogTrace( traceEnvVars,
885 wxT( "PGM_BASE::SetLocalEnvVariables: Setting local environment variable %s "
886 "to %s" ),
887 m_local_env_var.first,
888 m_local_env_var.second.GetValue() );
889 wxSetEnv( m_local_env_var.first, m_local_env_var.second.GetValue() );
890 }
891}
892
893
895{
896 return GetCommonSettings()->m_Env.vars;
897}
898
899
901{
902 if( !wxTheApp )
903 return false;
904
905 return wxTheApp->IsGUI();
906}
907
908
909void PGM_BASE::HandleException( std::exception_ptr aPtr )
910{
911 try
912 {
913 if( aPtr )
914 std::rethrow_exception( aPtr );
915 }
916 catch( const IO_ERROR& ioe )
917 {
918 wxLogError( ioe.What() );
919 }
920 catch( const std::exception& e )
921 {
922#ifdef KICAD_USE_SENTRY
923 if( IsSentryOptedIn() )
924 {
925 sentry_value_t exc = sentry_value_new_exception( "exception", e.what() );
926 sentry_value_set_stacktrace( exc, NULL, 0 );
927
928 sentry_value_t sentryEvent = sentry_value_new_event();
929 sentry_event_add_exception( sentryEvent, exc );
930 sentry_capture_event( sentryEvent );
931 }
932#endif
933
934 wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
935 From_UTF8( typeid( e ).name() ), From_UTF8( e.what() ) );
936 }
937 catch( ... )
938 {
939 wxLogError( wxT( "Unhandled exception of unknown type" ) );
940 }
941}
942
943
944#ifdef KICAD_USE_SENTRY
945struct SENTRY_ASSERT_CACHE_KEY
946{
947 wxString file;
948 int line;
949 wxString func;
950 wxString cond;
951 wxString msg;
952};
953
954
955bool operator<( const SENTRY_ASSERT_CACHE_KEY& aKey1, const SENTRY_ASSERT_CACHE_KEY& aKey2 )
956{
957 return aKey1.file < aKey2.file ||
958 aKey1.line < aKey2.line ||
959 aKey1.func < aKey2.func ||
960 aKey1.cond < aKey2.cond ||
961 aKey1.msg < aKey2.msg;
962}
963#endif
964
965
966void PGM_BASE::HandleAssert( const wxString& aFile, int aLine, const wxString& aFunc,
967 const wxString& aCond, const wxString& aMsg )
968{
969 wxString assertStr;
970
971 // Log the assertion details to standard log
972 if( !aMsg.empty() )
973 {
974 assertStr = wxString::Format( "Assertion failed at %s:%d in %s: %s - %s", aFile, aLine,
975 aFunc, aCond, aMsg );
976 }
977 else
978 {
979 assertStr = wxString::Format( "Assertion failed at %s:%d in %s: %s", aFile, aLine, aFunc,
980 aCond );
981 }
982
983#ifndef NDEBUG
984 wxLogError( assertStr );
985#endif
986
987#ifdef KICAD_USE_SENTRY
988 if( IsSentryOptedIn() )
989 {
990 static std::set<SENTRY_ASSERT_CACHE_KEY> assertCache;
991
992 SENTRY_ASSERT_CACHE_KEY key = { aFile, aLine, aFunc, aCond, aMsg };
993
994 if( assertCache.find( key ) == assertCache.end() )
995 {
996 sentry_value_t exc = sentry_value_new_exception( "assert", assertStr );
997 sentry_value_set_stacktrace( exc, NULL, 0 );
998
999 sentry_value_t sentryEvent = sentry_value_new_event();
1000 sentry_event_add_exception( sentryEvent, exc );
1001 sentry_capture_event( sentryEvent );
1002 assertCache.insert( key );
1003 }
1004 }
1005#endif
1006}
1007
1008
1009const wxString& PGM_BASE::GetExecutablePath() const
1010{
1011 return PATHS::GetExecutablePath();
1012}
1013
1014
1016{
1017 SetPdfBrowserName( GetCommonSettings()->m_System.pdf_viewer_name );
1019}
1020
1021
1023{
1026}
const char * name
Definition: DXF_plotter.cpp:57
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:104
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
wxString GetCommitHash()
Get the commit hash as a string.
wxString GetBuildVersion()
Get the full KiCad version string.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void InitializeEnvironment()
Creates the built-in environment variables and sets their default values.
ENVIRONMENT m_Env
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 SaveToFile(const wxString &aDirectory="", bool aForce=false)
Calls Store() and then writes the contents of the JSON document to a file.
static void Cleanup()
Call curl_global_cleanup for the application.
Definition: kicad_curl.cpp:42
static void Init()
Call curl_global_init for the application.
Definition: kicad_curl.cpp:33
void Load()
Loads notifications stored from disk.
static wxString GetInstanceCheckerPath()
Gets the path used for wxSingleInstanceChecker lock files.
Definition: paths.cpp:388
static void EnsureUserPathsExist()
Ensures/creates user default paths.
Definition: paths.cpp:418
static bool EnsurePathExists(const wxString &aPath)
Attempts to create a given path if it does not exist.
Definition: paths.cpp:398
static wxString GetUserCachePath()
Gets the stock (install) 3d viewer plugins path.
Definition: paths.cpp:351
static wxString GetLocaleDataPath()
Gets the locales translation data path.
Definition: paths.cpp:264
static const wxString & GetExecutablePath()
Definition: paths.cpp:543
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition: pgm_base.cpp:649
virtual wxApp & App()
Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:174
std::unique_ptr< NOTIFICATIONS_MANAGER > m_notifications_manager
Definition: pgm_base.h:396
int m_argcUtf8
argv parameters converted to utf8 form, because wxwidgets has opinions and will return argv as either...
Definition: pgm_base.h:423
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.cpp:894
bool m_Printing
wxWidgets on MSW tends to crash if you spool up more than one print job at a time.
Definition: pgm_base.h:374
void setLanguageId(int aId)
Trap all changes in here, simplifies debugging.
Definition: pgm_base.h:385
std::unique_ptr< SETTINGS_MANAGER > m_settings_manager
Definition: pgm_base.h:394
void loadCommonSettings()
Loads internal settings from COMMON_SETTINGS.
Definition: pgm_base.cpp:613
virtual void SetPdfBrowserName(const wxString &aFileName)
Definition: pgm_base.h:177
wxLocale * m_locale
The KICAD system environment variable.
Definition: pgm_base.h:406
void Destroy()
Definition: pgm_base.cpp:158
wxSplashScreen * m_splash
Definition: pgm_base.h:425
bool InitPgm(bool aHeadless=false, bool aSkipPyInit=false, bool aIsUnitTest=false)
Initialize this program.
Definition: pgm_base.cpp:449
char ** m_argvUtf8
Definition: pgm_base.h:420
virtual void ReadPdfBrowserInfos()
Read the PDF browser choice from the common configuration.
Definition: pgm_base.cpp:1015
bool IsGUI()
Determine if the application is running with a GUI.
Definition: pgm_base.cpp:900
bool m_use_system_pdf_browser
Definition: pgm_base.h:409
bool m_Quitting
Definition: pgm_base.h:378
virtual NOTIFICATIONS_MANAGER & GetNotificationsManager() const
Definition: pgm_base.h:142
void BuildArgvUtf8()
Builds the UTF8 based argv variable.
Definition: pgm_base.cpp:404
virtual const wxString & GetPdfBrowserName() const
Definition: pgm_base.h:175
virtual void SetTextEditor(const wxString &aFileName)
Definition: pgm_base.cpp:181
std::unique_ptr< wxSingleInstanceChecker > m_pgm_checker
Checks if there is another copy of Kicad running at the same time.
Definition: pgm_base.h:401
virtual bool SetLocalEnvVariable(const wxString &aName, const wxString &aValue)
Sets the environment variable aName to aValue.
Definition: pgm_base.cpp:847
wxString m_kicad_env
Definition: pgm_base.h:404
virtual void ForceSystemPdfBrowser(bool aFlg)
Force the use of system PDF browser, even if a preferred PDF browser is set.
Definition: pgm_base.h:192
virtual void SetLocalEnvVariables()
Updates the local environment with the contents of the current ENV_VAR_MAP stored in the COMMON_SETTI...
Definition: pgm_base.cpp:878
virtual void SetLanguagePath()
Definition: pgm_base.cpp:829
bool SetDefaultLanguage(wxString &aErrMsg)
Set the default language without reference to any preferences.
Definition: pgm_base.cpp:756
void ShowSplash()
Definition: pgm_base.cpp:419
wxString m_text_editor
Filename of the app selected for browsing PDFs.
Definition: pgm_base.h:412
virtual ~PGM_BASE()
Definition: pgm_base.cpp:144
std::unique_ptr< SCRIPTING > m_python_scripting
Definition: pgm_base.h:398
virtual void SetLanguageIdentifier(int menu_id)
Set in .m_language_id member the wxWidgets language identifier ID from the KiCad menu id (internal me...
Definition: pgm_base.cpp:797
int m_language_id
Definition: pgm_base.h:407
std::unique_ptr< BACKGROUND_JOBS_MONITOR > m_background_jobs_monitor
Definition: pgm_base.h:395
void HandleException(std::exception_ptr aPtr)
A exception handler to be used at the top level if exceptions bubble up that for.
Definition: pgm_base.cpp:909
void HandleAssert(const wxString &aFile, int aLine, const wxString &aFunc, const wxString &aCond, const wxString &aMsg)
A common assert handler to be used between single_top and kicad.
Definition: pgm_base.cpp:966
virtual wxString GetLanguageTag()
Definition: pgm_base.cpp:813
virtual const wxString & GetTextEditor(bool aCanShowFileChooser=true)
Return the path to the preferred text editor application.
Definition: pgm_base.cpp:188
virtual const wxString & GetExecutablePath() const
Definition: pgm_base.cpp:1009
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:136
void HideSplash()
Definition: pgm_base.cpp:438
virtual void WritePdfBrowserInfos()
Save the PDF browser choice to the common configuration.
Definition: pgm_base.cpp:1022
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition: pgm_base.cpp:640
virtual const wxString AskUserForPreferredEditor(const wxString &aDefaultEditor=wxEmptyString)
Shows a dialog that instructs the user to select a new preferred editor.
Definition: pgm_base.cpp:224
virtual bool SetLanguage(wxString &aErrMsg, bool first_time=false)
Set the dictionary file name for internationalization.
Definition: pgm_base.cpp:655
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Loads a project or sets up a new project with a specified path.
bool WarnUserIfOperatingSystemUnsupported()
Checks if the operating system is explicitly unsupported and displays a disclaimer message box.
Definition: common.cpp:689
The common library.
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)
bool operator<(const FOOTPRINT_INFO &lhs, const FOOTPRINT_INFO &rhs)
#define WIN_STRING_DIR_SEP
Definition: gestfich.h:36
#define UNIX_STRING_DIR_SEP
Definition: gestfich.h:35
const wxChar *const traceLocale
Flag to enable locale debug output.
const wxChar *const traceEnvVars
Flag to enable debug output of environment variable operations.
@ ID_LANGUAGE_SWEDISH
Definition: id.h:139
@ ID_LANGUAGE_CHINESE_SIMPLIFIED
Definition: id.h:129
@ ID_LANGUAGE_GERMAN
Definition: id.h:113
@ ID_LANGUAGE_DUTCH
Definition: id.h:131
@ ID_LANGUAGE_GREEK
Definition: id.h:114
@ ID_LANGUAGE_LITHUANIAN
Definition: id.h:135
@ ID_LANGUAGE_PORTUGUESE_BRAZILIAN
Definition: id.h:118
@ ID_LANGUAGE_DEFAULT
Definition: id.h:107
@ ID_LANGUAGE_POLISH
Definition: id.h:125
@ ID_LANGUAGE_THAI
Definition: id.h:138
@ ID_LANGUAGE_JAPANESE
Definition: id.h:132
@ ID_LANGUAGE_ITALIAN
Definition: id.h:121
@ ID_LANGUAGE_KOREAN
Definition: id.h:127
@ ID_LANGUAGE_RUSSIAN
Definition: id.h:116
@ ID_LANGUAGE_CZECH
Definition: id.h:126
@ ID_LANGUAGE_UKRANIAN
Definition: id.h:140
@ ID_LANGUAGE_SPANISH
Definition: id.h:111
@ ID_LANGUAGE_PORTUGUESE
Definition: id.h:117
@ ID_LANGUAGE_ENGLISH
Definition: id.h:108
@ ID_LANGUAGE_SPANISH_MEXICAN
Definition: id.h:112
@ ID_LANGUAGE_CHINESE_TRADITIONAL
Definition: id.h:130
@ ID_LANGUAGE_FINNISH
Definition: id.h:110
@ ID_LANGUAGE_DANISH
Definition: id.h:106
@ ID_LANGUAGE_FRENCH
Definition: id.h:109
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
This file contains miscellaneous commonly used macros and functions.
PBOOL GetPolicyBool(const wxString &aKey)
Definition: gtk/policy.cpp:26
LANGUAGE_DESCR LanguagesList[]
An array containing all the languages that KiCad supports.
Definition: pgm_base.cpp:88
#define _(s)
Current list of languages supported by KiCad.
Definition: pgm_base.cpp:126
see class PGM_BASE
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: single_top.cpp:119
LANGUAGE_DESCR LanguagesList[]
An array containing all the languages that KiCad supports.
Definition: pgm_base.cpp:88
#define POLICY_KEY_DATACOLLECTION
Definition: policy_keys.h:30
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
Definition: project.h:39
APIIMPORT wxPGGlobalVarsClass * wxPGGlobalVars
wxString From_UTF8(const char *cstring)
A small class to handle the list of existing translations.
Definition: pgm_base.h:62
int m_KI_Lang_Identifier
KiCad identifier used in menu selection (See id.h)
Definition: pgm_base.h:67
wxString m_Lang_Label
Labels used in menus.
Definition: pgm_base.h:70
System directories search utilities.
wxLogTrace helper definitions.