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-2021 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>
46#include <cli/cli_names.h> // Needed for the pre wx 3.2 cli workaround
47#include <common.h>
48#include <config_params.h>
49#include <confirm.h>
50#include <core/arraydim.h>
51#include <eda_base_frame.h>
52#include <eda_draw_frame.h>
53#include <gestfich.h>
54#include <id.h>
56#include <kiplatform/policy.h>
57#include <macros.h>
58#include <menus_helpers.h>
59#include <paths.h>
60#include <pgm_base.h>
61#include <policy_keys.h>
62#include <python_scripting.h>
65#include <systemdirsappend.h>
66#include <thread_pool.h>
67#include <trace_helpers.h>
68
69#ifdef KICAD_USE_SENTRY
70#include <boost/uuid/uuid_io.hpp>
71#include <boost/uuid/uuid_generators.hpp>
72#include <sentry.h>
73#include <build_version.h>
74#endif
75
85#undef _
86#define _(s) s
88{
89 { wxLANGUAGE_DEFAULT, ID_LANGUAGE_DEFAULT, _( "Default" ), false },
90// { wxLANGUAGE_INDONESIAN, ID_LANGUAGE_INDONESIAN, wxT( "Bahasa Indonesia" ), true },
91 { wxLANGUAGE_CZECH, ID_LANGUAGE_CZECH, wxT( "Čeština" ), true },
92 { wxLANGUAGE_DANISH, ID_LANGUAGE_DANISH, wxT( "Dansk" ), true },
93 { wxLANGUAGE_GERMAN, ID_LANGUAGE_GERMAN, wxT( "Deutsch" ), true },
94 { wxLANGUAGE_GREEK, ID_LANGUAGE_GREEK, wxT( "Ελληνικά" ), true },
95 { wxLANGUAGE_ENGLISH, ID_LANGUAGE_ENGLISH, wxT( "English" ), true },
96 { wxLANGUAGE_SPANISH, ID_LANGUAGE_SPANISH, wxT( "Español" ), true },
97 { wxLANGUAGE_SPANISH_MEXICAN, ID_LANGUAGE_SPANISH_MEXICAN, wxT( "Español (Latinoamericano)" ), true },
98 { wxLANGUAGE_FRENCH, ID_LANGUAGE_FRENCH, wxT( "Français" ), true },
99 { wxLANGUAGE_KOREAN, ID_LANGUAGE_KOREAN, wxT( "한국어"), true },
100 { wxLANGUAGE_ITALIAN, ID_LANGUAGE_ITALIAN, wxT( "Italiano" ), true },
101 { wxLANGUAGE_LITHUANIAN, ID_LANGUAGE_LITHUANIAN, wxT( "Lietuvių" ), true },
102// { wxLANGUAGE_HUNGARIAN, ID_LANGUAGE_HUNGARIAN, wxT( "Magyar" ), true },
103 { wxLANGUAGE_DUTCH, ID_LANGUAGE_DUTCH, wxT( "Nederlandse" ), true },
104 { wxLANGUAGE_JAPANESE, ID_LANGUAGE_JAPANESE, wxT( "日本語" ), true },
105 { wxLANGUAGE_THAI, ID_LANGUAGE_THAI, wxT( "ภาษาไทย" ), true },
106 { wxLANGUAGE_POLISH, ID_LANGUAGE_POLISH, wxT( "Polski" ), true },
107 { wxLANGUAGE_PORTUGUESE, ID_LANGUAGE_PORTUGUESE, wxT( "Português" ),true },
108 { wxLANGUAGE_PORTUGUESE_BRAZILIAN, ID_LANGUAGE_PORTUGUESE_BRAZILIAN, wxT( "Português (Brasil)" ), true },
109 { wxLANGUAGE_RUSSIAN, ID_LANGUAGE_RUSSIAN, wxT( "Русский" ), true },
110// { wxLANGUAGE_SERBIAN, ID_LANGUAGE_SERBIAN, wxT( "Српски" ), true },
111 { wxLANGUAGE_FINNISH, ID_LANGUAGE_FINNISH, wxT( "Suomi" ), true },
112 { wxLANGUAGE_SWEDISH, ID_LANGUAGE_SWEDISH, wxT( "Svenska" ), true },
113// { wxLANGUAGE_VIETNAMESE, ID_LANGUAGE_VIETNAMESE, wxT( "Tiếng Việt" ), true },
114// { wxLANGUAGE_TURKISH, ID_LANGUAGE_TURKISH, wxT( "Türkçe" ), true },
115 { wxLANGUAGE_UKRAINIAN, ID_LANGUAGE_UKRANIAN, wxT( "Українська" ), true },
116 { wxLANGUAGE_CHINESE_SIMPLIFIED, ID_LANGUAGE_CHINESE_SIMPLIFIED,
117 wxT( "简体中文" ), true },
118 { wxLANGUAGE_CHINESE_TRADITIONAL, ID_LANGUAGE_CHINESE_TRADITIONAL,
119 wxT( "繁體中文" ), false },
120 { 0, 0, "", false } // Sentinel
121};
122#undef _
123#define _(s) wxGetTranslation((s))
124
125
127{
128 m_locale = nullptr;
129 m_Printing = false;
130 m_Quitting = false;
131 m_argcUtf8 = 0;
132 m_argvUtf8 = nullptr;
133
134 setLanguageId( wxLANGUAGE_DEFAULT );
135
136 ForceSystemPdfBrowser( false );
137}
138
139
141{
142 Destroy();
143
144 for( int n = 0; n < m_argcUtf8; n++ )
145 {
146 free( m_argvUtf8[n] );
147 }
148
149 delete[] m_argvUtf8;
150}
151
152
154{
156
157#ifdef KICAD_USE_SENTRY
158 sentry_close();
159#endif
160
161 // unlike a normal destructor, this is designed to be called more than once safely:
162 delete m_locale;
163 m_locale = nullptr;
164}
165
166
168{
169 wxASSERT( wxTheApp );
170 return *wxTheApp;
171}
172
173
174void PGM_BASE::SetTextEditor( const wxString& aFileName )
175{
176 m_text_editor = aFileName;
178}
179
180
181const wxString& PGM_BASE::GetTextEditor( bool aCanShowFileChooser )
182{
183 wxString editorname = m_text_editor;
184
185 if( !editorname )
186 {
187 if( !wxGetEnv( wxT( "EDITOR" ), &editorname ) )
188 {
189 // If there is no EDITOR variable set, try the desktop default
190#ifdef __WXMAC__
191 editorname = wxT( "/usr/bin/open -e" );
192#elif __WXX11__
193 editorname = wxT( "/usr/bin/xdg-open" );
194#endif
195 }
196 }
197
198 // If we still don't have an editor name show a dialog asking the user to select one
199 if( !editorname && aCanShowFileChooser )
200 {
201 DisplayInfoMessage( nullptr, _( "No default editor found, you must choose one." ) );
202
203 editorname = AskUserForPreferredEditor();
204 }
205
206 // If we finally have a new editor name request it to be copied to m_text_editor and
207 // saved to the preferences file.
208 if( !editorname.IsEmpty() )
209 SetTextEditor( editorname );
210
211 // m_text_editor already has the same value that editorname, or empty if no editor was
212 // found/chosen.
213 return m_text_editor;
214}
215
216
217const wxString PGM_BASE::AskUserForPreferredEditor( const wxString& aDefaultEditor )
218{
219 // Create a mask representing the executable files in the current platform
220#ifdef __WINDOWS__
221 wxString mask( _( "Executable file" ) + wxT( " (*.exe)|*.exe" ) );
222#else
223 wxString mask( _( "Executable file" ) + wxT( " (*)|*" ) );
224#endif
225
226 // Extract the path, name and extension from the default editor (even if the editor's
227 // name was empty, this method will succeed and return empty strings).
228 wxString path, name, ext;
229 wxFileName::SplitPath( aDefaultEditor, &path, &name, &ext );
230
231 // Show the modal editor and return the file chosen (may be empty if the user cancels
232 // the dialog).
233 return wxFileSelector( _( "Select Preferred Editor" ), path, name, wxT( "." ) + ext,
234 mask, wxFD_OPEN | wxFD_FILE_MUST_EXIST, nullptr );
235}
236
237
238#ifdef KICAD_USE_SENTRY
239bool PGM_BASE::IsSentryOptedIn()
240{
241 KIPLATFORM::POLICY::STATE policyState =
244 {
245 return policyState == KIPLATFORM::POLICY::STATE::ENABLED;
246 }
247
248 return m_sentry_optin_fn.Exists();
249}
250
251
252void PGM_BASE::SetSentryOptIn( bool aOptIn )
253{
254 if( aOptIn )
255 {
256 if( !m_sentry_uid_fn.Exists() )
257 {
258 sentryCreateUid();
259 }
260
261 if( !m_sentry_optin_fn.Exists() )
262 {
263 wxFFile sentryInitFile( m_sentry_optin_fn.GetFullPath(), "w" );
264 sentryInitFile.Write( "" );
265 sentryInitFile.Close();
266 }
267 }
268 else
269 {
270 if( m_sentry_optin_fn.Exists() )
271 {
272 wxRemoveFile( m_sentry_optin_fn.GetFullPath() );
273 sentry_close();
274 }
275 }
276}
277
278
279wxString PGM_BASE::sentryCreateUid()
280{
281 boost::uuids::uuid uuid = boost::uuids::random_generator()();
282 wxString userGuid = boost::uuids::to_string( uuid );
283
284 wxFFile sentryInitFile( m_sentry_uid_fn.GetFullPath(), "w" );
285 sentryInitFile.Write( userGuid );
286 sentryInitFile.Close();
287
288 return userGuid;
289}
290
291
292void PGM_BASE::ResetSentryId()
293{
294 m_sentryUid = sentryCreateUid();
295}
296
297
298const wxString& PGM_BASE::GetSentryId()
299{
300 return m_sentryUid;
301}
302
303
304void PGM_BASE::sentryInit()
305{
306 m_sentry_optin_fn = wxFileName( PATHS::GetUserCachePath(), "sentry-opt-in" );
307 m_sentry_uid_fn = wxFileName( PATHS::GetUserCachePath(), "sentry-uid" );
308
309 if( IsSentryOptedIn() )
310 {
311 wxFFile sentryInitFile( m_sentry_uid_fn.GetFullPath() );
312 sentryInitFile.ReadAll( &m_sentryUid );
313 sentryInitFile.Close();
314
315 if( m_sentryUid.IsEmpty() || m_sentryUid.length() != 36 )
316 {
317 m_sentryUid = sentryCreateUid();
318 }
319
320 sentry_options_t* options = sentry_options_new();
321
322 sentry_options_set_dsn(
323 options,
324 "https://[email protected]/6266565" );
325
326 wxFileName tmp;
327 tmp.AssignDir( PATHS::GetUserCachePath() );
328 tmp.AppendDir( "sentry" );
329
330 sentry_options_set_database_pathw( options, tmp.GetPathWithSep().wc_str() );
331 sentry_options_set_symbolize_stacktraces( options, true );
332 sentry_options_set_auto_session_tracking( options, false );
333
334 sentry_options_set_release( options, GetCommitHash().ToStdString().c_str() );
335
336 sentry_init( options );
337
338 sentry_value_t user = sentry_value_new_object();
339 sentry_value_set_by_key( user, "id", sentry_value_new_string( m_sentryUid.c_str() ) );
340 sentry_set_user( user );
341
342 sentry_set_tag( "kicad.version", GetBuildVersion().ToStdString().c_str() );
343 }
344}
345
346
347void PGM_BASE::sentryPrompt()
348{
349 if( !IsGUI() )
350 return;
351
352 KIPLATFORM::POLICY::STATE policyState =
354
356 && !m_settings_manager->GetCommonSettings()->m_DoNotShowAgain.data_collection_prompt )
357 {
358 wxMessageDialog optIn = wxMessageDialog(
359 nullptr,
360 _( "KiCad can anonymously report crashes and special event "
361 "data to developers in order to aid identifying critical bugs "
362 "across the user base more effectively and help profile "
363 "functionality to guide improvements. \n"
364 "If you choose to voluntarily participate, KiCad will automatically "
365 "handle sending said reports when crashes or events occur. \n"
366 "Your design files such as schematic or PCB are not shared in this process." ),
367 _( "Data collection opt in request" ), wxYES_NO | wxCENTRE );
368
369 int result = optIn.ShowModal();
370
371 if( result == wxID_YES )
372 {
373 SetSentryOptIn( true );
374 sentryInit();
375 }
376 else
377 {
378 SetSentryOptIn( false );
379 }
380
381 m_settings_manager->GetCommonSettings()->m_DoNotShowAgain.data_collection_prompt = true;
382 }
383}
384#endif
385
386
388{
389 const wxArrayString& argArray = App().argv.GetArguments();
390 m_argcUtf8 = argArray.size();
391
392 m_argvUtf8 = new char*[m_argcUtf8 + 1];
393 for( int n = 0; n < m_argcUtf8; n++ )
394 {
395 m_argvUtf8[n] = wxStrdup( argArray[n].ToUTF8() );
396 }
397
398 m_argvUtf8[m_argcUtf8] = NULL; // null terminator at end of argv
399}
400
401
402bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit, bool aIsUnitTest )
403{
404#if defined( __WXMAC__ )
405 // Set the application locale to the system default
406 wxLogNull noLog;
407 wxLocale loc;
408 loc.Init();
409#endif
410
411 // Just make sure we init precreate any folders early for later code
412 // In particular, the user cache path is the most likely to be hit by startup code
414
416
417#ifdef KICAD_USE_SENTRY
418 sentryInit();
419#endif
420 wxString pgm_name;
421
423 if( App().argc == 0 )
424 pgm_name = wxT( "kicad" );
425 else
426 pgm_name = wxFileName( App().argv[0] ).GetName().Lower();
427
428#ifdef KICAD_USE_SENTRY
429 sentry_set_tag( "kicad.app", pgm_name.c_str() );
430#endif
431
432 wxInitAllImageHandlers();
433
434 // Without this the wxPropertyGridManager segfaults on Windows.
435 if( !wxPGGlobalVars )
436 wxPGInitResourceModule();
437
438#ifndef __WINDOWS__
439 if( wxString( wxGetenv( "HOME" ) ).IsEmpty() )
440 {
441 DisplayErrorMessage( nullptr, _( "Environment variable HOME is empty. "
442 "Unable to continue." ) );
443 return false;
444 }
445#endif
446
447 // Init KiCad environment
448 // the environment variable KICAD (if exists) gives the kicad path:
449 // something like set KICAD=d:\kicad
450 bool isDefined = wxGetEnv( wxT( "KICAD" ), &m_kicad_env );
451
452 if( isDefined ) // ensure m_kicad_env ends by "/"
453 {
455
456 if( !m_kicad_env.IsEmpty() && m_kicad_env.Last() != '/' )
458 }
459
460 // Init parameters for configuration
461 App().SetVendorName( wxT( "KiCad" ) );
462 App().SetAppName( pgm_name );
463
464 // Install some image handlers, mainly for help
465 if( wxImage::FindHandler( wxBITMAP_TYPE_PNG ) == nullptr )
466 wxImage::AddHandler( new wxPNGHandler );
467
468 if( wxImage::FindHandler( wxBITMAP_TYPE_GIF ) == nullptr )
469 wxImage::AddHandler( new wxGIFHandler );
470
471 if( wxImage::FindHandler( wxBITMAP_TYPE_JPEG ) == nullptr )
472 wxImage::AddHandler( new wxJPEGHandler );
473
474 wxFileSystem::AddHandler( new wxZipFSHandler );
475
476 // Analyze the command line & initialize the binary path
477 wxString tmp;
480 SetDefaultLanguage( tmp );
481
482 m_settings_manager = std::make_unique<SETTINGS_MANAGER>( aHeadless );
483
484 // Our unit test mocks break if we continue
485 // A bug caused InitPgm to terminate early in unit tests and the mocks are...simplistic
486 // TODO fix the unit tests so this can be removed
487 if( aIsUnitTest )
488 return false;
489
490 // Something got in the way of settings load: can't continue
491 if( !m_settings_manager->IsOK() )
492 return false;
493
494 // Set up built-in environment variables (and override them from the system environment if set)
496
497 // Load color settings after env is initialized
498 m_settings_manager->ReloadColorSettings();
499
500 // Load common settings from disk after setting up env vars
502
503 // Init user language *before* calling loadSettings, because
504 // env vars could be incorrectly initialized on Linux
505 // (if the value contains some non ASCII7 chars, the env var is not initialized)
506 SetLanguage( tmp, true );
507
508 // Now that translations are available, inform the user if the OS is unsupported
510
512
513#ifdef KICAD_USE_SENTRY
514 sentryPrompt();
515#endif
516
517 ReadPdfBrowserInfos(); // needs GetCommonSettings()
518
519 // Create the python scripting stuff
520 // Skip it fot applications that do not use it
521 if( !aSkipPyInit )
522 m_python_scripting = std::make_unique<SCRIPTING>();
523
524 // TODO(JE): Remove this if apps are refactored to not assume Prj() always works
525 // Need to create a project early for now (it can have an empty path for the moment)
527
528 // This sets the maximum tooltip display duration to 10s (up from 5) but only affects
529 // Windows as other platforms display tooltips while the mouse is not moving
530 if( !aHeadless )
531 {
532 wxToolTip::Enable( true );
533 wxToolTip::SetAutoPop( 10000 );
534 }
535
536 if( ADVANCED_CFG::GetCfg().m_UpdateUIEventInterval != 0 )
537 wxUpdateUIEvent::SetUpdateInterval( ADVANCED_CFG::GetCfg().m_UpdateUIEventInterval );
538
539 return true;
540}
541
542
544{
545 m_bin_dir = wxStandardPaths::Get().GetExecutablePath();
546
547#ifdef __WXMAC__
548 // On OSX Pgm().GetExecutablePath() will always point to main
549 // bundle directory, e.g., /Applications/kicad.app/
550
551 wxFileName fn( m_bin_dir );
552
553 if( fn.GetName() == wxT( "kicad" ) || fn.GetName() == wxT( "kicad-cli" ) )
554 {
555 // kicad launcher, so just remove the Contents/MacOS part
556 fn.RemoveLastDir();
557 fn.RemoveLastDir();
558 }
559 else
560 {
561 // standalone binaries live in Contents/Applications/<standalone>.app/Contents/MacOS
562 fn.RemoveLastDir();
563 fn.RemoveLastDir();
564 fn.RemoveLastDir();
565 fn.RemoveLastDir();
566 fn.RemoveLastDir();
567 }
568
569 m_bin_dir = fn.GetPath() + wxT( "/" );
570#else
571 // Use unix notation for paths. I am not sure this is a good idea,
572 // but it simplifies compatibility between Windows and Unices.
573 // However it is a potential problem in path handling under Windows.
575
576 // Remove file name form command line:
577 while( m_bin_dir.Last() != '/' && !m_bin_dir.IsEmpty() )
578 m_bin_dir.RemoveLast();
579#endif
580
581 return true;
582}
583
584
586{
588
589 for( const std::pair<wxString, ENV_VAR_ITEM> it : GetCommonSettings()->m_Env.vars )
590 {
591 wxLogTrace( traceEnvVars, wxT( "PGM_BASE::loadSettings: Found entry %s = %s" ),
592 it.first, it.second.GetValue() );
593
594 // Do not store the env var PROJECT_VAR_NAME ("KIPRJMOD") definition if for some reason
595 // it is found in config. (It is reserved and defined as project path)
596 if( it.first == PROJECT_VAR_NAME )
597 continue;
598
599 // Don't set bogus empty entries in the environment
600 if( it.first.IsEmpty() )
601 continue;
602
603 // Do not overwrite vars set by the system environment with values from the settings file
604 if( it.second.GetDefinedExternally() )
605 continue;
606
607 SetLocalEnvVariable( it.first, it.second.GetValue() );
608 }
609}
610
611
613{
614 // GetCommonSettings() is not initialized until fairly late in the
615 // process startup: InitPgm(), so test before using:
616 if( GetCommonSettings() )
617 GetCommonSettings()->m_System.working_dir = wxGetCwd();
618}
619
620
622{
623 return m_settings_manager ? m_settings_manager->GetCommonSettings() : nullptr;
624}
625
626
627bool PGM_BASE::SetLanguage( wxString& aErrMsg, bool first_time )
628{
629 // Suppress wxWidgets error popups if locale is not found
630 wxLogNull doNotLog;
631
632 if( first_time )
633 {
634 setLanguageId( wxLANGUAGE_DEFAULT );
635 // First time SetLanguage is called, the user selected language id is set
636 // from common user config settings
637 wxString languageSel = GetCommonSettings()->m_System.language;
638
639 // Search for the current selection
640 for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
641 {
642 if( LanguagesList[ii].m_Lang_Label == languageSel )
643 {
644 setLanguageId( LanguagesList[ii].m_WX_Lang_Identifier );
645 break;
646 }
647 }
648 }
649
650 // dictionary file name without extend (full name is kicad.mo)
651 wxString dictionaryName( wxT( "kicad" ) );
652
653 delete m_locale;
654 m_locale = new wxLocale;
655
656 // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return
657 // false just because it failed to load wxstd catalog
658 if( !m_locale->Init( m_language_id, wxLOCALE_DONT_LOAD_DEFAULT ) )
659 {
660 wxLogTrace( traceLocale, wxT( "This language is not supported by the system." ) );
661
662 setLanguageId( wxLANGUAGE_DEFAULT );
663 delete m_locale;
664
665 m_locale = new wxLocale;
666 m_locale->Init( wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT);
667
668 aErrMsg = _( "This language is not supported by the operating system." );
669 return false;
670 }
671 else if( !first_time )
672 {
673 wxLogTrace( traceLocale, wxT( "Search for dictionary %s.mo in %s" ) ,
674 dictionaryName, m_locale->GetName() );
675 }
676
677 if( !first_time )
678 {
679 // If we are here, the user has selected another language.
680 // Therefore the new preferred language name is stored in common config.
681 // Do NOT store the wxWidgets language Id, it can change between wxWidgets
682 // versions, for a given language
683 wxString languageSel;
684
685 // Search for the current selection language name
686 for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
687 {
688 if( LanguagesList[ii].m_WX_Lang_Identifier == m_language_id )
689 {
690 languageSel = LanguagesList[ii].m_Lang_Label;
691 break;
692 }
693 }
694
696 cfg->m_System.language = languageSel;
697 cfg->SaveToFile( GetSettingsManager().GetPathForSettingsFile( cfg ) );
698 }
699
700 // Try adding the dictionary if it is not currently loaded
701 if( !m_locale->IsLoaded( dictionaryName ) )
702 m_locale->AddCatalog( dictionaryName );
703
704 // Verify the Kicad dictionary was loaded properly
705 // However, for the English language, the dictionary is not mandatory, as
706 // all messages are already in English, just restricted to ASCII7 chars,
707 // the verification is skipped.
708 if( !m_locale->IsLoaded( dictionaryName ) && m_language_id != wxLANGUAGE_ENGLISH )
709 {
710 wxLogTrace( traceLocale, wxT( "Unable to load dictionary %s.mo in %s" ),
711 dictionaryName, m_locale->GetName() );
712
713 setLanguageId( wxLANGUAGE_DEFAULT );
714 delete m_locale;
715
716 m_locale = new wxLocale;
717 m_locale->Init( wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT);
718
719 aErrMsg = _( "The KiCad language file for this language is not installed." );
720 return false;
721 }
722
723 return true;
724}
725
726
727bool PGM_BASE::SetDefaultLanguage( wxString& aErrMsg )
728{
729 // Suppress error popups from wxLocale
730 wxLogNull doNotLog;
731
732 setLanguageId( wxLANGUAGE_DEFAULT );
733
734 // dictionary file name without extend (full name is kicad.mo)
735 wxString dictionaryName( wxT( "kicad" ) );
736
737 delete m_locale;
738 m_locale = new wxLocale;
739 m_locale->Init();
740
741 // Try adding the dictionary if it is not currently loaded
742 if( !m_locale->IsLoaded( dictionaryName ) )
743 m_locale->AddCatalog( dictionaryName );
744
745 // Verify the Kicad dictionary was loaded properly
746 // However, for the English language, the dictionary is not mandatory, as
747 // all messages are already in English, just restricted to ASCII7 chars,
748 // the verification is skipped.
749 if( !m_locale->IsLoaded( dictionaryName ) && m_language_id != wxLANGUAGE_ENGLISH )
750 {
751 wxLogTrace( traceLocale, wxT( "Unable to load dictionary %s.mo in %s" ),
752 dictionaryName, m_locale->GetName() );
753
754 setLanguageId( wxLANGUAGE_DEFAULT );
755 delete m_locale;
756
757 m_locale = new wxLocale;
758 m_locale->Init();
759
760 aErrMsg = _( "The KiCad language file for this language is not installed." );
761 return false;
762 }
763
764 return true;
765}
766
767
769{
770 wxLogTrace( traceLocale, wxT( "Select language ID %d from %d possible languages." ),
771 menu_id, (int)arrayDim( LanguagesList )-1 );
772
773 for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
774 {
775 if( menu_id == LanguagesList[ii].m_KI_Lang_Identifier )
776 {
777 setLanguageId( LanguagesList[ii].m_WX_Lang_Identifier );
778 break;
779 }
780 }
781}
782
783
785{
786 const wxLanguageInfo* langInfo = wxLocale::GetLanguageInfo( m_language_id );
787
788 if( !langInfo )
789 return "";
790 else
791 {
792 #if wxCHECK_VERSION( 3, 1, 6 )
793 wxString str = langInfo->GetCanonicalWithRegion();
794 #else
795 wxString str = langInfo->CanonicalName;
796 #endif
797 str.Replace( "_", "-" );
798
799 return str;
800 }
801}
802
803
805{
806 wxLocale::AddCatalogLookupPathPrefix( PATHS::GetLocaleDataPath() );
807
808 if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
809 {
810 wxFileName fn( Pgm().GetExecutablePath() );
811 fn.RemoveLastDir();
812 fn.AppendDir( wxT( "translation" ) );
813 wxLocale::AddCatalogLookupPathPrefix( fn.GetPath() );
814 }
815}
816
817
818bool PGM_BASE::SetLocalEnvVariable( const wxString& aName, const wxString& aValue )
819{
820 wxString env;
821
822 if( aName.IsEmpty() )
823 {
824 wxLogTrace( traceEnvVars,
825 wxT( "PGM_BASE::SetLocalEnvVariable: Attempt to set empty variable to value %s" ),
826 aValue );
827 return false;
828 }
829
830 // Check to see if the environment variable is already set.
831 if( wxGetEnv( aName, &env ) )
832 {
833 wxLogTrace( traceEnvVars,
834 wxT( "PGM_BASE::SetLocalEnvVariable: Environment variable %s already set to %s" ),
835 aName, env );
836 return env == aValue;
837 }
838
839 wxLogTrace( traceEnvVars,
840 wxT( "PGM_BASE::SetLocalEnvVariable: Setting local environment variable %s to %s" ),
841 aName, aValue );
842
843 return wxSetEnv( aName, aValue );
844}
845
846
848{
849 // Overwrites externally defined environment variable until the next time the application
850 // is run.
851 for( const std::pair<wxString, ENV_VAR_ITEM> m_local_env_var : GetCommonSettings()->m_Env.vars )
852 {
853 wxLogTrace( traceEnvVars,
854 wxT( "PGM_BASE::SetLocalEnvVariables: Setting local environment variable %s to %s" ),
855 m_local_env_var.first,
856 m_local_env_var.second.GetValue() );
857 wxSetEnv( m_local_env_var.first, m_local_env_var.second.GetValue() );
858 }
859}
860
861
863{
864 return GetCommonSettings()->m_Env.vars;
865}
866
867
869{
870 if( !wxTheApp )
871 return false;
872
873#if wxCHECK_VERSION( 3, 1, 6 )
874 return wxTheApp->IsGUI();
875#else
876 // wxWidgets older than version 3.1.6 do not have a way to know if the app
877 // has a GUI or is a console application.
878 // So the trick is to set the App class name when starting kicad-cli, and when
879 // the app class name is the kicad-cli class name the app is a console app
880 bool run_gui = wxTheApp->GetClassName() != KICAD_CLI_APP_NAME;
881 return run_gui;
882#endif
883}
884
885
886void PGM_BASE::HandleException( std::exception_ptr aPtr )
887{
888 try
889 {
890 if( aPtr )
891 std::rethrow_exception( aPtr );
892 }
893 catch( const IO_ERROR& ioe )
894 {
895 wxLogError( ioe.What() );
896 }
897 catch( const std::exception& e )
898 {
899#ifdef KICAD_USE_SENTRY
900 if( Pgm().IsSentryOptedIn() )
901 {
902 sentry_value_t exc = sentry_value_new_exception( "exception", e.what() );
903 sentry_value_set_stacktrace( exc, NULL, 0 );
904
905 sentry_value_t sentryEvent = sentry_value_new_event();
906 sentry_event_add_exception( sentryEvent, exc );
907 sentry_capture_event( sentryEvent );
908 }
909#endif
910
911 wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
912 FROM_UTF8( typeid( e ).name() ), FROM_UTF8( e.what() ) );
913 }
914 catch( ... )
915 {
916 wxLogError( wxT( "Unhandled exception of unknown type" ) );
917 }
918}
const char * name
Definition: DXF_plotter.cpp:56
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
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:76
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
virtual bool SaveToFile(const wxString &aDirectory="", bool aForce=false)
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
static void EnsureUserPathsExist()
Ensures/creates user default paths.
Definition: paths.cpp:369
static wxString GetUserCachePath()
Gets the stock (install) 3d viewer plugins path.
Definition: paths.cpp:321
static wxString GetLocaleDataPath()
Gets the locales translation data path.
Definition: paths.cpp:252
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition: pgm_base.cpp:621
virtual wxApp & App()
Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:167
int m_argcUtf8
argv parameters converted to utf8 form, because wxwidgets has opinions and will return argv as either...
Definition: pgm_base.h:395
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.cpp:862
bool setExecutablePath()
Find the path to the executable and stores it in PGM_BASE::m_bin_dir.
Definition: pgm_base.cpp:543
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:344
void setLanguageId(int aId)
Trap all changes in here, simplifies debugging.
Definition: pgm_base.h:355
wxString m_bin_dir
Definition: pgm_base.h:375
std::unique_ptr< SETTINGS_MANAGER > m_settings_manager
Definition: pgm_base.h:371
void loadCommonSettings()
Loads internal settings from COMMON_SETTINGS.
Definition: pgm_base.cpp:585
wxLocale * m_locale
The KICAD system environment variable.
Definition: pgm_base.h:378
void Destroy()
Definition: pgm_base.cpp:153
bool InitPgm(bool aHeadless=false, bool aSkipPyInit=false, bool aIsUnitTest=false)
Initialize this program.
Definition: pgm_base.cpp:402
char ** m_argvUtf8
Definition: pgm_base.h:392
virtual void ReadPdfBrowserInfos()
Read the PDF browser choice from the common configuration.
Definition: eda_doc.cpp:37
bool IsGUI()
Determine if the application is running with a GUI.
Definition: pgm_base.cpp:868
bool m_Quitting
Definition: pgm_base.h:348
void BuildArgvUtf8()
Builds the UTF8 based argv variable.
Definition: pgm_base.cpp:387
virtual void SetTextEditor(const wxString &aFileName)
Definition: pgm_base.cpp:174
virtual const wxString & GetExecutablePath() const
Definition: pgm_base.h:167
virtual bool SetLocalEnvVariable(const wxString &aName, const wxString &aValue)
Sets the environment variable aName to aValue.
Definition: pgm_base.cpp:818
wxString m_kicad_env
full path to this program
Definition: pgm_base.h:376
virtual void ForceSystemPdfBrowser(bool aFlg)
Force the use of system PDF browser, even if a preferred PDF browser is set.
Definition: pgm_base.h:188
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:847
virtual void SetLanguagePath()
Definition: pgm_base.cpp:804
bool SetDefaultLanguage(wxString &aErrMsg)
Set the default language without reference to any preferences.
Definition: pgm_base.cpp:727
wxString m_text_editor
Filename of the app selected for browsing PDFs.
Definition: pgm_base.h:384
virtual ~PGM_BASE()
Definition: pgm_base.cpp:140
std::unique_ptr< SCRIPTING > m_python_scripting
Definition: pgm_base.h:373
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:768
int m_language_id
Definition: pgm_base.h:379
void HandleException(std::exception_ptr aPtr)
A excepion handler to be used at the top level if exceptions bubble up that for.
Definition: pgm_base.cpp:886
virtual wxString GetLanguageTag()
Definition: pgm_base.cpp:784
virtual const wxString & GetTextEditor(bool aCanShowFileChooser=true)
Return the path to the preferred text editor application.
Definition: pgm_base.cpp:181
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:136
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition: pgm_base.cpp:612
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:217
virtual bool SetLanguage(wxString &aErrMsg, bool first_time=false)
Set the dictionary file name for internationalization.
Definition: pgm_base.cpp:627
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Loads a project or sets up a new project with a specified path.
#define KICAD_CLI_APP_NAME
Definition: cli_names.h:23
bool WarnUserIfOperatingSystemUnsupported()
Checks if the operating system is explicitly unsupported and displays a disclaimer message box.
Definition: common.cpp:654
The common library.
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:335
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:308
This file is part of the common library.
#define _(s)
Base window classes and related definitions.
#define WIN_STRING_DIR_SEP
Definition: gestfich.h:36
#define UNIX_STRING_DIR_SEP
Definition: gestfich.h:35
const wxChar *const traceEnvVars
Flag to enable debug output of environment variable operations.
const wxChar *const traceLocale
Flag to enable locale debug output.
@ 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.
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
Macros and inline functions to create menus items in menubars or popup menus.
STATE GetPolicyState(const wxString &aKey)
Definition: gtk/policy.cpp:25
LANGUAGE_DESCR LanguagesList[]
An array containing all the languages that KiCad supports.
Definition: pgm_base.cpp:87
#define _(s)
Current list of languages supported by KiCad.
Definition: pgm_base.cpp:123
see class PGM_BASE
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: single_top.cpp:115
LANGUAGE_DESCR LanguagesList[]
An array containing all the languages that KiCad supports.
Definition: pgm_base.cpp:87
#define POLICY_KEY_DATACOLLECTION
Definition: policy_keys.h:28
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
Definition: project.h:39
APIIMPORT wxPGGlobalVarsClass * wxPGGlobalVars
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.