KiCad PCB EDA Suite
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 <stambaughw@gmail.com>
6  * Copyright (C) 1992-2018 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 <fctsys.h>
34 #include <wx/html/htmlwin.h>
35 #include <wx/fs_zip.h>
36 #include <wx/dir.h>
37 #include <wx/filename.h>
38 #include <wx/snglinst.h>
39 #include <wx/stdpaths.h>
40 #include <wx/sysopt.h>
41 #include <wx/richmsgdlg.h>
42 
43 #include <pgm_base.h>
44 #include <draw_frame.h>
45 #include <eda_base_frame.h>
46 #include <macros.h>
47 #include <config_params.h>
48 #include <id.h>
49 #include <build_version.h>
50 #include <hotkeys_basic.h>
51 #include <gestfich.h>
52 #include <menus_helpers.h>
53 #include <confirm.h>
54 #include <dialog_configure_paths.h>
55 #include <lockfile.h>
56 #include <systemdirsappend.h>
57 #include <trace_helpers.h>
59 
60 #define KICAD_COMMON wxT( "kicad_common" )
61 
62 // some key strings used to store parameters in KICAD_COMMON
63 
64 const wxChar PGM_BASE::workingDirKey[] = wxT( "WorkingDir" ); // public
65 
66 static const wxChar languageCfgKey[] = wxT( "LanguageID" );
67 static const wxChar pathEnvVariables[] = wxT( "EnvironmentVariables" );
68 static const wxChar showEnvVarWarningDialog[] = wxT( "ShowEnvVarWarningDialog" );
69 static const wxChar traceEnvVars[] = wxT( "KIENVVARS" );
70 
71 
72 FILE_HISTORY::FILE_HISTORY( size_t aMaxFiles, int aBaseFileId ) :
73  wxFileHistory( std::min( aMaxFiles, (size_t) MAX_FILE_HISTORY_SIZE ) )
74 {
75  SetBaseId( aBaseFileId );
76 }
77 
78 
79 void FILE_HISTORY::SetMaxFiles( size_t aMaxFiles )
80 {
81  m_fileMaxFiles = std::min( aMaxFiles, (size_t) MAX_FILE_HISTORY_SIZE );
82 
83  size_t numFiles = m_fileHistory.size();
84 
85  while( numFiles > m_fileMaxFiles )
86  RemoveFileFromHistory( --numFiles );
87 }
88 
89 
99 {
102 
105 
108 
110  wxString m_Lang_Label;
111 
114 };
115 
116 
124 {
125  { wxLANGUAGE_DEFAULT, ID_LANGUAGE_DEFAULT, lang_def_xpm, _( "Default" ) },
126  { wxLANGUAGE_ENGLISH, ID_LANGUAGE_ENGLISH, lang_en_xpm, wxT( "English" ), true },
127  { wxLANGUAGE_FRENCH, ID_LANGUAGE_FRENCH, lang_fr_xpm, _( "French" ) },
128  { wxLANGUAGE_FINNISH, ID_LANGUAGE_FINNISH, lang_fi_xpm, _( "Finnish" ) },
129  { wxLANGUAGE_SPANISH, ID_LANGUAGE_SPANISH, lang_es_xpm, _( "Spanish" ) },
130  { wxLANGUAGE_PORTUGUESE, ID_LANGUAGE_PORTUGUESE, lang_pt_xpm, _( "Portuguese" ) },
131  { wxLANGUAGE_ITALIAN, ID_LANGUAGE_ITALIAN, lang_it_xpm, _( "Italian" ) },
132  { wxLANGUAGE_GERMAN, ID_LANGUAGE_GERMAN, lang_de_xpm, _( "German" ) },
133  { wxLANGUAGE_GREEK, ID_LANGUAGE_GREEK, lang_gr_xpm, _( "Greek" ) },
134  { wxLANGUAGE_SLOVENIAN, ID_LANGUAGE_SLOVENIAN, lang_sl_xpm, _( "Slovenian" ) },
135  { wxLANGUAGE_SLOVAK, ID_LANGUAGE_SLOVAK, lang_sk_xpm, _( "Slovak" ) },
136  { wxLANGUAGE_HUNGARIAN, ID_LANGUAGE_HUNGARIAN, lang_hu_xpm, _( "Hungarian" ) },
137  { wxLANGUAGE_POLISH, ID_LANGUAGE_POLISH, lang_pl_xpm, _( "Polish" ) },
138  { wxLANGUAGE_CZECH, ID_LANGUAGE_CZECH, lang_cs_xpm, _( "Czech" ) },
139  { wxLANGUAGE_RUSSIAN, ID_LANGUAGE_RUSSIAN, lang_ru_xpm, _( "Russian" ) },
140  { wxLANGUAGE_KOREAN, ID_LANGUAGE_KOREAN, lang_ko_xpm, _( "Korean" ) },
141  { wxLANGUAGE_CHINESE_SIMPLIFIED, ID_LANGUAGE_CHINESE_SIMPLIFIED, lang_zh_xpm,
142  _( "Chinese simplified" ) },
143  { wxLANGUAGE_CHINESE_TRADITIONAL, ID_LANGUAGE_CHINESE_TRADITIONAL, lang_zh_xpm,
144  _( "Chinese traditional" ) },
145  { wxLANGUAGE_CATALAN, ID_LANGUAGE_CATALAN, lang_ca_xpm, _( "Catalan" ) },
146  { wxLANGUAGE_DUTCH, ID_LANGUAGE_DUTCH, lang_nl_xpm, _( "Dutch" ) },
147  { wxLANGUAGE_JAPANESE, ID_LANGUAGE_JAPANESE, lang_jp_xpm, _( "Japanese" ) },
148  { wxLANGUAGE_BULGARIAN, ID_LANGUAGE_BULGARIAN, lang_bg_xpm, _( "Bulgarian" ) },
149  { wxLANGUAGE_LITHUANIAN, ID_LANGUAGE_LITHUANIAN, lang_lt_xpm, _( "Lithuanian" ) }
150 };
151 
152 
154 {
155  m_pgm_checker = NULL;
156  m_locale = NULL;
157 
158  m_show_env_var_dialog = true;
159 
160  setLanguageId( wxLANGUAGE_DEFAULT );
161 
162  ForceSystemPdfBrowser( false );
163 }
164 
165 
167 {
168  Destroy();
169 }
170 
171 
173 {
174  // unlike a normal destructor, this is designed to be called more than once safely:
175  m_common_settings.reset();
176 
177  delete m_pgm_checker;
178  m_pgm_checker = 0;
179 
180  delete m_locale;
181  m_locale = 0;
182 }
183 
184 
186 {
187  wxASSERT( wxTheApp );
188  return *wxTheApp;
189 }
190 
191 
192 void PGM_BASE::SetEditorName( const wxString& aFileName )
193 {
194  m_editor_name = aFileName;
195  wxASSERT( m_common_settings );
196  m_common_settings->Write( "Editor", aFileName );
197 }
198 
199 
200 const wxString& PGM_BASE::GetEditorName( bool aCanShowFileChooser )
201 {
202  wxString editorname = m_editor_name;
203 
204  if( !editorname )
205  {
206  if( !wxGetEnv( "EDITOR", &editorname ) )
207  {
208  // If there is no EDITOR variable set, try the desktop default
209 #ifdef __WXMAC__
210  editorname = "/usr/bin/open";
211 #elif __WXX11__
212  editorname = "/usr/bin/xdg-open";
213 #endif
214  }
215  }
216 
217  // If we still don't have an editor name show a dialog asking the user to select one
218  if( !editorname && aCanShowFileChooser )
219  {
220  DisplayInfoMessage( NULL,
221  _( "No default editor found, you must choose it" ) );
222 
223  editorname = AskUserForPreferredEditor();
224  }
225 
226  // If we finally have a new editor name request it to be copied to m_editor_name and
227  // saved to the preferences file.
228  if( !editorname.IsEmpty() )
229  SetEditorName( editorname );
230 
231  // m_editor_name already has the same value that editorname, or empty if no editor was
232  // found/chosen.
233  return m_editor_name;
234 }
235 
236 
237 const wxString PGM_BASE::AskUserForPreferredEditor( const wxString& aDefaultEditor )
238 {
239  // Create a mask representing the executable files in the current platform
240 #ifdef __WINDOWS__
241  wxString mask( _( "Executable file (*.exe)|*.exe" ) );
242 #else
243  wxString mask( _( "Executable file (*)|*" ) );
244 #endif
245 
246  // Extract the path, name and extension from the default editor (even if the editor's
247  // name was empty, this method will succeed and return empty strings).
248  wxString path, name, ext;
249  wxFileName::SplitPath( aDefaultEditor, &path, &name, &ext );
250 
251  // Show the modal editor and return the file chosen (may be empty if the user cancels
252  // the dialog).
253  return EDA_FILE_SELECTOR( _( "Select Preferred Editor" ), path,
254  name, ext, mask,
255  NULL, wxFD_OPEN | wxFD_FILE_MUST_EXIST,
256  true );
257 }
258 
259 
261 {
262  wxFileName pgm_name( App().argv[0] );
263 
264  wxConfigBase::DontCreateOnDemand();
265 
266  wxInitAllImageHandlers();
267 
268  m_pgm_checker = new wxSingleInstanceChecker( pgm_name.GetName().Lower() + wxT( "-" ) +
269  wxGetUserId(), GetKicadLockFilePath() );
270 
271  if( m_pgm_checker->IsAnotherRunning() )
272  {
273  wxString quiz = wxString::Format(
274  _( "%s is already running. Continue?" ),
275  GetChars( pgm_name.GetName() )
276  );
277 
278  if( !IsOK( NULL, quiz ) )
279  return false;
280  }
281 
282  // Init KiCad environment
283  // the environment variable KICAD (if exists) gives the kicad path:
284  // something like set KICAD=d:\kicad
285  bool isDefined = wxGetEnv( "KICAD", &m_kicad_env );
286 
287  if( isDefined ) // ensure m_kicad_env ends by "/"
288  {
290 
291  if( !m_kicad_env.IsEmpty() && m_kicad_env.Last() != '/' )
293  }
294 
295  // Init parameters for configuration
296  App().SetVendorName( "KiCad" );
297  App().SetAppName( pgm_name.GetName().Lower() );
298 
299  // Install some image handlers, mainly for help
300  if( wxImage::FindHandler( wxBITMAP_TYPE_PNG ) == NULL )
301  wxImage::AddHandler( new wxPNGHandler );
302 
303  if( wxImage::FindHandler( wxBITMAP_TYPE_GIF ) == NULL )
304  wxImage::AddHandler( new wxGIFHandler );
305 
306  if( wxImage::FindHandler( wxBITMAP_TYPE_JPEG ) == NULL )
307  wxImage::AddHandler( new wxJPEGHandler );
308 
309  wxFileSystem::AddHandler( new wxZipFSHandler );
310 
311  // Analyze the command line & initialize the binary path
313 
314  SetLanguagePath();
315 
316  // OS specific instantiation of wxConfigBase derivative:
318 
319  wxString envVarName = wxT( "KIGITHUB" );
320  ENV_VAR_ITEM envVarItem;
321  wxString envValue;
322  wxFileName tmpFileName;
323 
324  if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() )
325  {
326  tmpFileName.AssignDir( envValue );
327  envVarItem.SetDefinedExternally( true );
328  }
329  else
330  {
331  envVarItem.SetValue( wxString( wxT( "https://github.com/KiCad" ) ) );
332  envVarItem.SetDefinedExternally( false );
333  }
334 
335  m_local_env_vars[ envVarName ] = envVarItem;
336 
337  wxFileName baseSharePath;
338 #if defined( __WXMSW__ )
339  // Make the paths relative to the executable dir as KiCad might be installed anywhere
340  // It follows the Windows installer paths scheme, where binaries are installed in
341  // PATH/bin and extra files in PATH/share/kicad
342  baseSharePath.AssignDir( m_bin_dir + "\\.." );
343  baseSharePath.Normalize();
344 #else
345  baseSharePath.AssignDir( wxString( wxT( DEFAULT_INSTALL_PATH ) ) );
346 #endif
347 
348 #if !defined( __WXMAC__ )
349  baseSharePath.AppendDir( "share" );
350  baseSharePath.AppendDir( "kicad" );
351 #endif
352 
353  // KISYSMOD
354  envVarName = wxT( "KISYSMOD" );
355 
356  if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() )
357  {
358  tmpFileName.AssignDir( envValue );
359  envVarItem.SetDefinedExternally( true );
360  }
361  else
362  {
363  tmpFileName = baseSharePath;
364  tmpFileName.AppendDir( "modules" );
365  envVarItem.SetDefinedExternally( false );
366  }
367 
368  envVarItem.SetValue( tmpFileName.GetPath() );
369  m_local_env_vars[ envVarName ] = envVarItem;
370 
371  // KISYS3DMOD
372  envVarName = wxT( "KISYS3DMOD" );
373 
374  if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() )
375  {
376  tmpFileName.AssignDir( envValue );
377  envVarItem.SetDefinedExternally( true );
378  }
379  else
380  {
381  tmpFileName.AppendDir( "packages3d" );
382  envVarItem.SetDefinedExternally( false );
383  }
384 
385  envVarItem.SetValue( tmpFileName.GetFullPath() );
386  m_local_env_vars[ envVarName ] = envVarItem;
387 
388  // KICAD_TEMPLATE_DIR
389  envVarName = "KICAD_TEMPLATE_DIR";
390 
391  if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() )
392  {
393  tmpFileName.AssignDir( envValue );
394  envVarItem.SetDefinedExternally( true );
395  }
396  else
397  {
398  // Attempt to find the best default template path.
399  SEARCH_STACK bases;
400  SEARCH_STACK templatePaths;
401 
402  SystemDirsAppend( &bases );
403 
404  for( unsigned i = 0; i < bases.GetCount(); ++i )
405  {
406  wxFileName fn( bases[i], wxEmptyString );
407 
408  // Add KiCad template file path to search path list.
409  fn.AppendDir( "template" );
410 
411  // Only add path if exists and can be read by the user.
412  if( fn.DirExists() && fn.IsDirReadable() )
413  {
414  wxLogTrace( tracePathsAndFiles, "Checking template path '%s' exists",
415  fn.GetPath() );
416  templatePaths.AddPaths( fn.GetPath() );
417  }
418  }
419 
420  if( templatePaths.IsEmpty() )
421  {
422  tmpFileName = baseSharePath;
423  tmpFileName.AppendDir( "template" );
424  }
425  else
426  {
427  // Take the first one. There may be more but this will likely be the best option.
428  tmpFileName.AssignDir( templatePaths[0] );
429  }
430 
431  envVarItem.SetDefinedExternally( false );
432  }
433 
434  envVarItem.SetValue( tmpFileName.GetPath() );
435  m_local_env_vars[ envVarName ] = envVarItem;
436 
437  // KICAD_USER_TEMPLATE_DIR
438  envVarName = "KICAD_USER_TEMPLATE_DIR";
439 
440  if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() )
441  {
442  tmpFileName.AssignDir( envValue );
443  envVarItem.SetDefinedExternally( true );
444  }
445  else
446  {
447  // Default user template path.
448  tmpFileName = wxStandardPaths::Get().GetDocumentsDir();
449  tmpFileName.AppendDir( "kicad" );
450  tmpFileName.AppendDir( "template" );
451  envVarItem.SetDefinedExternally( false );
452  }
453 
454  envVarItem.SetValue( tmpFileName.GetPath() );
455  m_local_env_vars[ envVarName ] = envVarItem;
456 
457  // KICAD_SYMBOLS
458  envVarName = wxT( "KICAD_SYMBOL_DIR" );
459 
460  if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() )
461  {
462  tmpFileName.AssignDir( envValue );
463  envVarItem.SetDefinedExternally( true );
464  }
465  else
466  {
467  tmpFileName = baseSharePath;
468  tmpFileName.AppendDir( "library" );
469  envVarItem.SetDefinedExternally( false );
470  }
471 
472  envVarItem.SetValue( tmpFileName.GetPath() );
473  m_local_env_vars[ envVarName ] = envVarItem;
474 
475  ReadPdfBrowserInfos(); // needs m_common_settings
476 
477  // Init user language *before* calling loadCommonSettings, because
478  // env vars could be incorrectly initialized on Linux
479  // (if the value contains some non ASCII7 chars, the env var is not initialized)
480  SetLanguage( true );
481 
483 
484 #ifdef __WXMAC__
485  // Always show filters on Open dialog to be able to choose plugin
486  wxSystemOptions::SetOption( wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES, 1 );
487 #endif
488 
489  return true;
490 }
491 
492 
494 {
495  m_bin_dir = wxStandardPaths::Get().GetExecutablePath();
496 
497 #ifdef __WXMAC__
498  // On OSX Pgm().GetExecutablePath() will always point to main
499  // bundle directory, e.g., /Applications/kicad.app/
500 
501  wxFileName fn( m_bin_dir );
502 
503  if( fn.GetName() == wxT( "kicad" ) )
504  {
505  // kicad launcher, so just remove the Contents/MacOS part
506  fn.RemoveLastDir();
507  fn.RemoveLastDir();
508  }
509  else
510  {
511  // standalone binaries live in Contents/Applications/<standalone>.app/Contents/MacOS
512  fn.RemoveLastDir();
513  fn.RemoveLastDir();
514  fn.RemoveLastDir();
515  fn.RemoveLastDir();
516  fn.RemoveLastDir();
517  }
518 
519  m_bin_dir = fn.GetPath() + wxT( "/" );
520 #else
521  // Use unix notation for paths. I am not sure this is a good idea,
522  // but it simplifies compatibility between Windows and Unices.
523  // However it is a potential problem in path handling under Windows.
525 
526  // Remove file name form command line:
527  while( m_bin_dir.Last() != '/' && !m_bin_dir.IsEmpty() )
528  m_bin_dir.RemoveLast();
529 #endif
530 
531  return true;
532 }
533 
534 
536 {
537  wxASSERT( m_common_settings );
538 
539  m_help_size.x = 500;
540  m_help_size.y = 400;
541 
542  // This only effect the first time KiCad is run. The user's setting will be used for all
543  // subsequent runs. Menu icons are off by default on OSX and on for all other platforms.
544 #if defined( __WXMAC__ )
545  bool defaultUseIconsInMenus = false;
546 #else
547  bool defaultUseIconsInMenus = true;
548 #endif
549 
551 
552  if( !m_common_settings->HasEntry( USE_ICONS_IN_MENUS_KEY ) )
553  m_common_settings->Write( USE_ICONS_IN_MENUS_KEY, defaultUseIconsInMenus );
554 
555  if( !m_common_settings->HasEntry( ICON_SCALE_KEY )
558  {
559  // 5.0 and earlier saved common settings in each app, and saved hardware antialiasing
560  // options only in pcbnew (which was the only canvas to support them). Since there's
561  // no single right answer to where to pull the common settings from, we might as well
562  // get them along with the hardware antialiasing option from pcbnew.
563  auto pcbnewConfig = GetNewConfig( wxString::FromUTF8( "pcbnew" ) );
564  wxString pcbFrameKey( PCB_EDIT_FRAME_NAME );
565 
566  if( !m_common_settings->HasEntry( ICON_SCALE_KEY ) )
567  {
568  int temp;
569  wxString msg;
570  bool option;
571 
572  pcbnewConfig->Read( "PcbIconScale", &temp, 0 );
573  m_common_settings->Write( ICON_SCALE_KEY, temp );
574 
575  pcbnewConfig->Read( ENBL_MOUSEWHEEL_PAN_KEY, &option, false );
576  m_common_settings->Write( ENBL_MOUSEWHEEL_PAN_KEY, option );
577 
578  pcbnewConfig->Read( ENBL_ZOOM_NO_CENTER_KEY, &option, false );
579  m_common_settings->Write( ENBL_ZOOM_NO_CENTER_KEY, option );
580 
581  pcbnewConfig->Read( ENBL_AUTO_PAN_KEY, &option, true );
582  m_common_settings->Write( ENBL_AUTO_PAN_KEY, option );
583  }
584 
585  if( !m_common_settings->HasEntry( GAL_ANTIALIASING_MODE_KEY ) )
586  {
587  int temp;
588  pcbnewConfig->Read( pcbFrameKey + GAL_DISPLAY_OPTIONS_KEY + GAL_ANTIALIASING_MODE_KEY,
591  }
592 
594  {
595  int temp;
596  pcbnewConfig->Read( pcbFrameKey + GAL_DISPLAY_OPTIONS_KEY + CAIRO_ANTIALIASING_MODE_KEY,
599  }
600  }
601 
602  m_editor_name = m_common_settings->Read( "Editor" );
603 
604  wxString entry, oldPath;
605  wxArrayString entries;
606  long index = 0L;
607 
608  oldPath = m_common_settings->GetPath();
610 
611  while( m_common_settings->GetNextEntry( entry, index ) )
612  {
613  wxLogTrace( traceEnvVars,
614  "Enumerating over entry %s, %ld.", GetChars( entry ), index );
615  entries.Add( entry );
616  }
617 
618  for( unsigned i = 0; i < entries.GetCount(); i++ )
619  {
620  wxString val = m_common_settings->Read( entries[i], wxEmptyString );
621 
622  if( m_local_env_vars[ entries[i] ].GetDefinedExternally() )
623  continue;
624 
625  m_local_env_vars[ entries[i] ] = ENV_VAR_ITEM( val, wxGetEnv( entries[i], NULL ) );
626  }
627 
628  for( ENV_VAR_MAP_ITER it = m_local_env_vars.begin(); it != m_local_env_vars.end(); ++it )
629  SetLocalEnvVariable( it->first, it->second.GetValue() );
630 
631  m_common_settings->SetPath( oldPath );
632 }
633 
634 
636 {
637  // m_common_settings is not initialized until fairly late in the
638  // process startup: InitPgm(), so test before using:
639  if( m_common_settings )
640  {
641  wxString cur_dir = wxGetCwd();
642 
643  m_common_settings->Write( workingDirKey, cur_dir );
645 
646  // Save the local environment variables.
648 
649  for( ENV_VAR_MAP_ITER it = m_local_env_vars.begin(); it != m_local_env_vars.end(); ++it )
650  {
651  if( it->second.GetDefinedExternally() )
652  continue;
653 
654  wxLogTrace( traceEnvVars, "Saving environment variable config entry %s as %s",
655  GetChars( it->first ), GetChars( it->second.GetValue() ) );
656  m_common_settings->Write( it->first, it->second.GetValue() );
657  }
658 
659  m_common_settings->SetPath( ".." );
660  }
661 }
662 
663 
664 bool PGM_BASE::SetLanguage( bool first_time )
665 {
666  bool retv = true;
667 
668  if( first_time )
669  {
670  setLanguageId( wxLANGUAGE_DEFAULT );
671  // First time SetLanguage is called, the user selected language id is set
672  // from commun user config settings
673  wxString languageSel;
674 
675  m_common_settings->Read( languageCfgKey, &languageSel );
676 
677  // Search for the current selection
678  for( unsigned ii = 0; ii < arrayDim( s_Languages ); ii++ )
679  {
680  if( s_Languages[ii].m_Lang_Label == languageSel )
681  {
682  setLanguageId( s_Languages[ii].m_WX_Lang_Identifier );
683  break;
684  }
685  }
686  }
687 
688  // dictionary file name without extend (full name is kicad.mo)
689  wxString dictionaryName( "kicad" );
690 
691  delete m_locale;
692  m_locale = new wxLocale;
693 
694  if( !m_locale->Init( m_language_id ) )
695  {
696  wxLogTrace( traceLocale, "This language is not supported by the system." );
697 
698  setLanguageId( wxLANGUAGE_DEFAULT );
699  delete m_locale;
700 
701  m_locale = new wxLocale;
702  m_locale->Init();
703  retv = false;
704  }
705  else if( !first_time )
706  {
707  wxLogTrace( traceLocale, "Search for dictionary %s.mo in %s",
708  GetChars( dictionaryName ), GetChars( m_locale->GetName() ) );
709  }
710 
711  if( !first_time )
712  {
713  // If we are here, the user has selected another language.
714  // Therefore the new prefered language name is stored in common config.
715  // Do NOT store the wxWidgets language Id, it can change between wxWidgets
716  // versions, for a given language
717  wxString languageSel;
718 
719  // Search for the current selection language name
720  for( unsigned ii = 0; ii < arrayDim( s_Languages ); ii++ )
721  {
722  if( s_Languages[ii].m_WX_Lang_Identifier == m_language_id )
723  {
724  languageSel = s_Languages[ii].m_Lang_Label;
725  break;
726  }
727  }
728 
729  m_common_settings->Write( languageCfgKey, languageSel );
730  }
731 
732  // Test if floating point notation is working (bug encountered in cross compilation)
733  // Make a conversion double <=> string
734  double dtst = 0.5;
735  wxString msg;
736 
737  msg << dtst;
738  double result;
739  msg.ToDouble( &result );
740 
741  if( result != dtst )
742  // string to double encode/decode does not work! Bug detected:
743  // Disable floating point localization:
744  setlocale( LC_NUMERIC, "C" );
745 
746  if( !m_locale->IsLoaded( dictionaryName ) )
747  m_locale->AddCatalog( dictionaryName );
748 
749  if( !retv )
750  return retv;
751 
752  return m_locale->IsOk();
753 }
754 
755 
757 {
758  wxLogTrace( traceLocale, "Select language ID %d from %d possible languages.",
759  menu_id, (int)arrayDim( s_Languages ) );
760 
761  for( unsigned ii = 0; ii < arrayDim( s_Languages ); ii++ )
762  {
763  if( menu_id == s_Languages[ii].m_KI_Lang_Identifier )
764  {
765  setLanguageId( s_Languages[ii].m_WX_Lang_Identifier );
766  break;
767  }
768  }
769 }
770 
771 
773 {
774  SEARCH_STACK guesses;
775 
776  SystemDirsAppend( &guesses );
777 
778  // Add our internat dir to the wxLocale catalog of paths
779  for( unsigned i = 0; i < guesses.GetCount(); i++ )
780  {
781  wxFileName fn( guesses[i], wxEmptyString );
782 
783  // Append path for Windows and unix KiCad package install
784  fn.AppendDir( "share" );
785  fn.AppendDir( "internat" );
786 
787  if( fn.IsDirReadable() )
788  {
789  wxLogTrace( traceLocale, "Adding locale lookup path: " + fn.GetPath() );
790  wxLocale::AddCatalogLookupPathPrefix( fn.GetPath() );
791  }
792 
793  // Append path for unix standard install
794  fn.RemoveLastDir();
795  fn.AppendDir( "kicad" );
796  fn.AppendDir( "internat" );
797 
798  if( fn.IsDirReadable() )
799  {
800  wxLogTrace( traceLocale, "Adding locale lookup path: " + fn.GetPath() );
801  wxLocale::AddCatalogLookupPathPrefix( fn.GetPath() );
802  }
803  }
804 }
805 
806 
807 void PGM_BASE::AddMenuLanguageList( wxMenu* MasterMenu )
808 {
809  wxMenu* menu = NULL;
810  wxMenuItem* item = MasterMenu->FindItem( ID_LANGUAGE_CHOICE );
811 
812  if( item ) // This menu exists, do nothing
813  return;
814 
815  menu = new wxMenu;
816 
817  for( unsigned ii = 0; ii < arrayDim( s_Languages ); ii++ )
818  {
819  wxString label;
820 
821  if( s_Languages[ii].m_DoNotTranslate )
822  label = s_Languages[ii].m_Lang_Label;
823  else
824  label = wxGetTranslation( s_Languages[ii].m_Lang_Label );
825 
826  AddMenuItem( menu, s_Languages[ii].m_KI_Lang_Identifier,
827  label, KiBitmap(s_Languages[ii].m_Lang_Icon ),
828  wxITEM_CHECK );
829  }
830 
831  AddMenuItem( MasterMenu, menu,
833  _( "Set Language" ),
834  _( "Select application language (only for testing)" ),
835  KiBitmap( language_xpm ) );
836 
837  // Set Check mark on current selected language
838  for( unsigned ii = 0; ii < arrayDim( s_Languages ); ii++ )
839  {
840  if( m_language_id == s_Languages[ii].m_WX_Lang_Identifier )
841  menu->Check( s_Languages[ii].m_KI_Lang_Identifier, true );
842  else
843  menu->Check( s_Languages[ii].m_KI_Lang_Identifier, false );
844  }
845 }
846 
847 
848 bool PGM_BASE::SetLocalEnvVariable( const wxString& aName, const wxString& aValue )
849 {
850  wxString env;
851 
852  // Check to see if the environment variable is already set.
853  if( wxGetEnv( aName, &env ) )
854  {
855  wxLogTrace( traceEnvVars, "Environment variable %s already set to %s.",
856  GetChars( aName ), GetChars( env ) );
857  return env == aValue;
858  }
859 
860  wxLogTrace( traceEnvVars, "Setting local environment variable %s to %s.",
861  GetChars( aName ), GetChars( aValue ) );
862 
863  return wxSetEnv( aName, aValue );
864 }
865 
866 
868 {
869  m_local_env_vars.clear();
870  m_local_env_vars = aEnvVarMap;
871 
872  if( m_common_settings )
873  m_common_settings->DeleteGroup( pathEnvVariables );
874 
876 
877  // Overwrites externally defined environment variable until the next time the application
878  // is run.
879  for( ENV_VAR_MAP_ITER it = m_local_env_vars.begin(); it != m_local_env_vars.end(); ++it )
880  {
881  wxLogTrace( traceEnvVars, "Setting local environment variable %s to %s.",
882  GetChars( it->first ), GetChars( it->second.GetValue() ) );
883  wxSetEnv( it->first, it->second.GetValue() );
884  }
885 }
FILE_HISTORY(size_t aMaxFiles, int aBaseFileId)
Definition: pgm_base.cpp:72
static const wxChar pathEnvVariables[]
Definition: pgm_base.cpp:67
void loadCommonSettings()
Function loadCommonSettings loads the program (process) settings subset which are stored in ...
Definition: pgm_base.cpp:535
wxString GetKicadLockFilePath()
Function GetKicadLockFilePath.
Definition: lockfile.cpp:59
#define WIN_STRING_DIR_SEP
Definition: gestfich.h:44
VTBL_ENTRY void SetEditorName(const wxString &aFileName)
Definition: pgm_base.cpp:192
virtual ~PGM_BASE()
Definition: pgm_base.cpp:166
PNG memory record (file in memory).
Definition: bitmap_types.h:43
This file is part of the common library TODO brief description.
ENV_VAR_MAP m_local_env_vars
Local environment variable expansion settings such as KIGITHUB, KISYSMOD, and KISYS3DMOD.
Definition: pgm_base.h:400
std::unique_ptr< wxConfigBase > GetNewConfig(const wxString &aProgName)
Create a new wxConfig so we can put configuration files in a more proper place for each platform...
Definition: common.cpp:255
This file is part of the common library.
void SaveCommonSettings()
Function saveCommonSettings saves the program (process) settings subset which are stored ...
Definition: pgm_base.cpp:635
std::unique_ptr< wxConfigBase > m_common_settings
Configuration settings common to all KiCad program modules, like as in $HOME/.kicad_common.
Definition: pgm_base.h:367
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Function AddMenuItem is an inline helper function to create and insert a menu item with an icon into ...
Definition: bitmap.cpp:223
#define UNIX_STRING_DIR_SEP
Definition: gestfich.h:43
wxLocale * m_locale
The current locale.
Definition: pgm_base.h:376
Class ENV_VAR_ITEM.
Definition: pgm_base.h:102
static const wxChar workingDirKey[]
Definition: pgm_base.h:328
BITMAP_DEF m_Lang_Icon
The menu language icons.
Definition: pgm_base.cpp:107
VTBL_ENTRY void ForceSystemPdfBrowser(bool aFlg)
Function ForceSystemPdfBrowser forces the use of system PDF browser, even if a preferred PDF browser ...
Definition: pgm_base.h:240
static const wxChar showEnvVarWarningDialog[]
Definition: pgm_base.cpp:68
int m_KI_Lang_Identifier
KiCad identifier used in menu selection (See id.h)
Definition: pgm_base.cpp:104
#define MAX_FILE_HISTORY_SIZE
Definition: pgm_base.h:61
VTBL_ENTRY wxApp & App()
Function App returns a bare naked wxApp, which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:185
static const wxChar traceEnvVars[]
Definition: pgm_base.cpp:69
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
bool m_show_env_var_dialog
Flag to indicate if the environment variable overwrite warning dialog should be shown.
Definition: pgm_base.h:403
void Destroy()
Definition: pgm_base.cpp:172
bool setExecutablePath()
Function setExecutablePath finds the path to the executable and stores it in PGM_BASE::m_bin_dir.
Definition: pgm_base.cpp:493
System directories search utilities.
The common library.
Template specialization to enable wxStrings for certain containers (e.g. unordered_map) ...
Definition: bitmap.cpp:55
A small class to handle the list of existing translations.
Definition: pgm_base.cpp:98
wxSingleInstanceChecker * m_pgm_checker
prevents multiple instances of a program from being run at the same time.
Definition: pgm_base.h:363
Class SEARCH_STACK looks for files in a number of places.
Definition: search_stack.h:41
bool m_DoNotTranslate
Set to true if the m_Lang_Label must not be translated.
Definition: pgm_base.cpp:113
VTBL_ENTRY const wxString AskUserForPreferredEditor(const wxString &aDefaultEditor=wxEmptyString)
Shows a dialog that instructs the user to select a new preferred editor.
Definition: pgm_base.cpp:237
#define KICAD_COMMON
Definition: pgm_base.cpp:60
#define ENBL_ZOOM_NO_CENTER_KEY
Definition: pgm_base.h:48
int m_language_id
The current language setting.
Definition: pgm_base.h:379
This file contains miscellaneous commonly used macros and functions.
#define PCB_EDIT_FRAME_NAME
Definition: draw_frame.h:56
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
#define GAL_DISPLAY_OPTIONS_KEY
Definition: pgm_base.h:53
wxString m_kicad_env
The KICAD system environment variable.
Definition: pgm_base.h:373
#define ENBL_AUTO_PAN_KEY
Definition: pgm_base.h:51
VTBL_ENTRY bool SetLocalEnvVariable(const wxString &aName, const wxString &aValue)
Function SetLocalEnvVariable.
Definition: pgm_base.cpp:848
VTBL_ENTRY void SetLanguageIdentifier(int menu_id)
Function SetLanguageIdentifier sets in .m_language_id member the wxWidgets language identifier Id fro...
Definition: pgm_base.cpp:756
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
Definition: pgm_base.h:131
void SetDefinedExternally(bool aIsDefinedExternally)
Definition: pgm_base.h:114
wxString EDA_FILE_SELECTOR(const wxString &aTitle, const wxString &aPath, const wxString &aFileName, const wxString &aExtension, const wxString &aWildcard, wxWindow *aParent, int aStyle, const bool aKeepWorkingDirectory, const wxPoint &aPosition, wxString *aMruPath)
Function EDA_FILE_SELECTOR.
Definition: gestfich.cpp:82
#define ENBL_MOUSEWHEEL_PAN_KEY
Definition: pgm_base.h:49
Base window classes and related definitions.
void SystemDirsAppend(SEARCH_STACK *aSearchStack)
Function SystemDirsAppend appends system places to aSearchStack in a platform specific way...
wxLogTrace helper definitions.
void setLanguageId(int aId)
Trap all changes in here, simplifies debugging.
Definition: pgm_base.h:385
int m_WX_Lang_Identifier
wxWidgets locale identifier (See wxWidgets doc)
Definition: pgm_base.cpp:101
const wxChar *const traceLocale
Flag to enable locale debug output.
#define ICON_SCALE_KEY
Definition: pgm_base.h:46
wxString m_Lang_Label
Labels used in menus.
Definition: pgm_base.cpp:110
VTBL_ENTRY void SetLanguagePath()
Definition: pgm_base.cpp:772
VTBL_ENTRY bool SetLanguage(bool first_time=false)
Function SetLanguage sets the dictionary file name for internationalization.
Definition: pgm_base.cpp:664
wxString m_bin_dir
full path to this program
Definition: pgm_base.h:370
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
of elements in an array. This implements type-safe compile time checking
Definition: macros.h:99
VTBL_ENTRY void SetLocalEnvVariables(const ENV_VAR_MAP &aEnvVarMap)
Function SetLocalEnvVariables.
Definition: pgm_base.cpp:867
void SetMaxFiles(size_t aMaxFiles)
Definition: pgm_base.cpp:79
#define GAL_ANTIALIASING_MODE_KEY
Definition: pgm_base.h:54
VTBL_ENTRY void ReadPdfBrowserInfos()
Function ReadPdfBrowserInfos reads the PDF browser choice from the common configuration.
Definition: eda_doc.cpp:42
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
see class PGM_BASE
const char * name
Definition: DXF_plotter.cpp:61
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
void SetValue(const wxString &aValue)
Definition: pgm_base.h:120
wxSize m_help_size
Definition: pgm_base.h:397
size_t i
Definition: json11.cpp:597
#define USE_ICONS_IN_MENUS_KEY
Definition: pgm_base.h:45
bool InitPgm()
Function initPgm initializes this program (process) in a KiCad standard way, using some generalized t...
Definition: pgm_base.cpp:260
static const wxChar languageCfgKey[]
Definition: pgm_base.cpp:66
static LANGUAGE_DESCR s_Languages[]
Variable s_Languages Note: because this list is not created on the fly, wxTranslation must be called ...
Definition: pgm_base.cpp:123
#define CAIRO_ANTIALIASING_MODE_KEY
Definition: pgm_base.h:55
wxString m_editor_name
Definition: pgm_base.h:396
std::map< wxString, ENV_VAR_ITEM >::iterator ENV_VAR_MAP_ITER
Definition: pgm_base.h:132
VTBL_ENTRY const wxString & GetEditorName(bool aCanShowFileChooser=true)
Return the preferred editor name.
Definition: pgm_base.cpp:200
VTBL_ENTRY void AddMenuLanguageList(wxMenu *MasterMenu)
Function AddMenuLanguageList creates a menu list for language choice, and add it as submenu to Master...
Definition: pgm_base.cpp:807
Some functions to handle hotkeys in KiCad.
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:277
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:295
void AddPaths(const wxString &aPaths, int aIndex=-1)
Function AddPaths insert or append path(s)
#define min(a, b)
Definition: auxiliary.h:85
File locking utilities.