You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

631 lines
21 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015 Wayne Stambaugh <stambaughw@gmail.com>
  5. * Copyright (C) 2015-2021 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <dialogs/dialog_configure_paths.h>
  25. #include <bitmaps.h>
  26. #include <confirm.h>
  27. #include <menus_helpers.h>
  28. #include <validators.h>
  29. #include <dialogs/html_messagebox.h>
  30. #include <filename_resolver.h>
  31. #include <env_vars.h>
  32. #include <grid_tricks.h>
  33. #include <pgm_base.h>
  34. #include <widgets/wx_grid.h>
  35. #include <widgets/grid_text_button_helpers.h>
  36. #include <algorithm>
  37. #include <wx/dirdlg.h>
  38. enum TEXT_VAR_GRID_COLUMNS
  39. {
  40. TV_NAME_COL = 0,
  41. TV_VALUE_COL,
  42. TV_FLAG_COL
  43. };
  44. enum SEARCH_PATH_GRID_COLUMNS
  45. {
  46. SP_ALIAS_COL = 0,
  47. SP_PATH_COL,
  48. SP_DESC_COL
  49. };
  50. DIALOG_CONFIGURE_PATHS::DIALOG_CONFIGURE_PATHS( wxWindow* aParent, FILENAME_RESOLVER* aResolver ) :
  51. DIALOG_CONFIGURE_PATHS_BASE( aParent ),
  52. m_errorGrid( nullptr ),
  53. m_errorRow( -1 ),
  54. m_errorCol( -1 ),
  55. m_resolver( aResolver ),
  56. m_gridWidth( 0 ),
  57. m_gridWidthsDirty( true ),
  58. m_helpDialog( nullptr )
  59. {
  60. m_btnAddEnvVar->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
  61. m_btnDeleteEnvVar->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
  62. m_btnAddSearchPath->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
  63. m_btnDeleteSearchPath->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
  64. m_btnMoveUp->SetBitmap( KiBitmap( BITMAPS::small_up ) );
  65. m_btnMoveDown->SetBitmap( KiBitmap( BITMAPS::small_down ) );
  66. m_EnvVars->ClearRows();
  67. m_EnvVars->AppendCols( 1 ); // for the isExternal flags
  68. m_EnvVars->HideCol( TV_FLAG_COL );
  69. m_EnvVars->UseNativeColHeader( true );
  70. wxGridCellAttr* attr = new wxGridCellAttr;
  71. attr->SetEditor( new GRID_CELL_PATH_EDITOR( this, m_EnvVars, &m_curdir, wxEmptyString ) );
  72. m_EnvVars->SetColAttr( TV_VALUE_COL, attr );
  73. attr = new wxGridCellAttr;
  74. attr->SetEditor( new GRID_CELL_PATH_EDITOR( this, m_SearchPaths, &m_curdir, wxEmptyString ) );
  75. m_SearchPaths->SetColAttr( TV_VALUE_COL, attr );
  76. // Give a bit more room for combobox editors
  77. m_EnvVars->SetDefaultRowSize( m_EnvVars->GetDefaultRowSize() + 4 );
  78. m_SearchPaths->SetDefaultRowSize( m_SearchPaths->GetDefaultRowSize() + 4 );
  79. m_EnvVars->PushEventHandler( new GRID_TRICKS( m_EnvVars ) );
  80. m_SearchPaths->PushEventHandler( new GRID_TRICKS( m_SearchPaths ) );
  81. m_EnvVars->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
  82. m_SearchPaths->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
  83. if( m_resolver )
  84. {
  85. m_SearchPaths->ClearRows();
  86. m_SearchPaths->UseNativeColHeader( true );
  87. // prohibit these characters in the alias names: []{}()%~<>"='`;:.,&?/\|$
  88. m_aliasValidator.SetStyle( wxFILTER_EXCLUDE_CHAR_LIST );
  89. m_aliasValidator.SetCharExcludes( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) );
  90. }
  91. else
  92. m_sb3DSearchPaths->Show( false );
  93. SetInitialFocus( m_EnvVars );
  94. m_sdbSizerOK->SetDefault();
  95. // wxFormBuilder doesn't include this event...
  96. m_EnvVars->Connect( wxEVT_GRID_CELL_CHANGING,
  97. wxGridEventHandler( DIALOG_CONFIGURE_PATHS::OnGridCellChanging ),
  98. nullptr, this );
  99. m_SearchPaths->Connect( wxEVT_GRID_CELL_CHANGING,
  100. wxGridEventHandler( DIALOG_CONFIGURE_PATHS::OnGridCellChanging ),
  101. nullptr, this );
  102. GetSizer()->SetSizeHints( this );
  103. Centre();
  104. }
  105. DIALOG_CONFIGURE_PATHS::~DIALOG_CONFIGURE_PATHS()
  106. {
  107. // Delete the GRID_TRICKS.
  108. m_SearchPaths->PopEventHandler( true );
  109. m_EnvVars->PopEventHandler( true );
  110. if( m_helpDialog )
  111. m_helpDialog->Destroy();
  112. m_EnvVars->Disconnect( wxEVT_GRID_CELL_CHANGING,
  113. wxGridEventHandler( DIALOG_CONFIGURE_PATHS::OnGridCellChanging ),
  114. nullptr, this );
  115. m_SearchPaths->Disconnect( wxEVT_GRID_CELL_CHANGING,
  116. wxGridEventHandler( DIALOG_CONFIGURE_PATHS::OnGridCellChanging ),
  117. nullptr, this );
  118. }
  119. bool DIALOG_CONFIGURE_PATHS::TransferDataToWindow()
  120. {
  121. if( !wxDialog::TransferDataToWindow() )
  122. return false;
  123. // Do 3D search paths first so they get first crack at setting m_curdir
  124. if( m_resolver )
  125. {
  126. const std::list<SEARCH_PATH>* paths = m_resolver->GetPaths();
  127. for( auto it = paths->begin(); it != paths->end(); ++it )
  128. {
  129. if ( !( *it ).m_Alias.StartsWith( "${" ) && !( *it ).m_Alias.StartsWith( "$(" ) )
  130. {
  131. AppendSearchPath( it->m_Alias, it->m_Pathvar, it->m_Description );
  132. if( m_curdir.IsEmpty() )
  133. m_curdir = it->m_Pathexp;
  134. }
  135. }
  136. }
  137. // Environment variables
  138. const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
  139. for( auto it = envVars.begin(); it != envVars.end(); ++it )
  140. {
  141. const wxString& path = it->second.GetValue();
  142. AppendEnvVar( it->first, path, it->second.GetDefinedExternally() );
  143. if( m_curdir.IsEmpty() && !path.StartsWith( "${" ) && !path.StartsWith( "$(" ) )
  144. m_curdir = path;
  145. }
  146. return true;
  147. }
  148. void DIALOG_CONFIGURE_PATHS::AppendEnvVar( const wxString& aName, const wxString& aPath,
  149. bool isExternal )
  150. {
  151. int i = m_EnvVars->GetNumberRows();
  152. m_EnvVars->AppendRows( 1 );
  153. m_EnvVars->SetCellValue( i, TV_NAME_COL, aName );
  154. wxGridCellAttr* nameCellAttr = m_EnvVars->GetOrCreateCellAttr( i, TV_NAME_COL );
  155. wxGridCellTextEditor* nameTextEditor = new GRID_CELL_TEXT_EDITOR();
  156. nameTextEditor->SetValidator( ENV_VAR_NAME_VALIDATOR() );
  157. nameCellAttr->SetEditor( nameTextEditor );
  158. nameCellAttr->SetReadOnly( ENV_VAR::IsEnvVarImmutable( aName ) );
  159. nameCellAttr->DecRef();
  160. m_EnvVars->SetCellValue( i, TV_VALUE_COL, aPath );
  161. wxGridCellAttr* pathCellAttr = m_EnvVars->GetOrCreateCellAttr( i, TV_VALUE_COL );
  162. wxSystemColour c = isExternal ? wxSYS_COLOUR_MENU : wxSYS_COLOUR_LISTBOX;
  163. pathCellAttr->SetBackgroundColour( wxSystemSettings::GetColour( c ) );
  164. pathCellAttr->DecRef();
  165. m_EnvVars->SetCellValue( i, TV_FLAG_COL, isExternal ? wxT( "external" ) : wxEmptyString );
  166. }
  167. void DIALOG_CONFIGURE_PATHS::AppendSearchPath( const wxString& aName, const wxString& aPath,
  168. const wxString& aDescription )
  169. {
  170. int i = m_SearchPaths->GetNumberRows();
  171. m_SearchPaths->AppendRows( 1 );
  172. m_SearchPaths->SetCellValue( i, SP_ALIAS_COL, aName );
  173. wxGridCellAttr* nameCellAttr = m_SearchPaths->GetOrCreateCellAttr( i, SP_ALIAS_COL );
  174. wxGridCellTextEditor* nameTextEditor = new GRID_CELL_TEXT_EDITOR();
  175. nameTextEditor->SetValidator( m_aliasValidator );
  176. nameCellAttr->SetEditor( nameTextEditor );
  177. nameCellAttr->DecRef();
  178. m_SearchPaths->SetCellValue( i, SP_PATH_COL, aPath );
  179. m_SearchPaths->SetCellValue( i, SP_DESC_COL, aDescription );
  180. }
  181. bool DIALOG_CONFIGURE_PATHS::TransferDataFromWindow()
  182. {
  183. if( !m_EnvVars->CommitPendingChanges() || !m_SearchPaths->CommitPendingChanges() )
  184. return false;
  185. if( !wxDialog::TransferDataFromWindow() )
  186. return false;
  187. // Environment variables
  188. ENV_VAR_MAP& envVarMap = Pgm().GetLocalEnvVariables();
  189. for( int row = 0; row < m_EnvVars->GetNumberRows(); ++row )
  190. {
  191. wxString name = m_EnvVars->GetCellValue( row, TV_NAME_COL );
  192. wxString path = m_EnvVars->GetCellValue( row, TV_VALUE_COL );
  193. bool external = !m_EnvVars->GetCellValue( row, TV_FLAG_COL ).IsEmpty();
  194. if( external )
  195. {
  196. // Don't check for consistency on external variables, just use them as-is
  197. }
  198. else if( name.IsEmpty() )
  199. {
  200. m_errorGrid = m_EnvVars;
  201. m_errorRow = row;
  202. m_errorCol = TV_NAME_COL;
  203. m_errorMsg = _( "Environment variable name cannot be empty." );
  204. return false;
  205. }
  206. else if( path.IsEmpty() )
  207. {
  208. m_errorGrid = m_EnvVars;
  209. m_errorRow = row;
  210. m_errorCol = TV_VALUE_COL;
  211. m_errorMsg = _( "Environment variable path cannot be empty." );
  212. return false;
  213. }
  214. if( envVarMap.count( name ) )
  215. envVarMap.at( name ).SetValue( path );
  216. else
  217. envVarMap[ name ] = ENV_VAR_ITEM( name, path );
  218. }
  219. Pgm().SetLocalEnvVariables();
  220. // 3D search paths
  221. if( m_resolver )
  222. {
  223. std::vector<SEARCH_PATH> alist;
  224. SEARCH_PATH alias;
  225. for( int row = 0; row < m_SearchPaths->GetNumberRows(); ++row )
  226. {
  227. alias.m_Alias = m_SearchPaths->GetCellValue( row, SP_ALIAS_COL );
  228. alias.m_Pathvar = m_SearchPaths->GetCellValue( row, SP_PATH_COL );
  229. alias.m_Description = m_SearchPaths->GetCellValue( row, SP_DESC_COL );
  230. if( alias.m_Alias.IsEmpty() )
  231. {
  232. m_errorGrid = m_SearchPaths;
  233. m_errorRow = row;
  234. m_errorCol = SP_ALIAS_COL;
  235. m_errorMsg = _( "3D search path alias cannot be empty." );
  236. return false;
  237. }
  238. else if( alias.m_Pathvar.IsEmpty() )
  239. {
  240. m_errorGrid = m_SearchPaths;
  241. m_errorRow = row;
  242. m_errorCol = SP_PATH_COL;
  243. m_errorMsg = _( "3D search path cannot be empty." );
  244. return false;
  245. }
  246. alist.push_back( alias );
  247. }
  248. if( !m_resolver->UpdatePathList( alist ) )
  249. return false;
  250. }
  251. return true;
  252. }
  253. void DIALOG_CONFIGURE_PATHS::OnGridCellChanging( wxGridEvent& event )
  254. {
  255. wxGrid* grid = dynamic_cast<wxGrid*>( event.GetEventObject() );
  256. int row = event.GetRow();
  257. int col = event.GetCol();
  258. wxString text = event.GetString();
  259. if( text.IsEmpty() )
  260. {
  261. if( grid == m_EnvVars )
  262. {
  263. if( col == TV_NAME_COL )
  264. m_errorMsg = _( "Environment variable name cannot be empty." );
  265. else
  266. m_errorMsg = _( "Environment variable path cannot be empty." );
  267. }
  268. else
  269. {
  270. if( col == SP_ALIAS_COL )
  271. m_errorMsg = _( "3D search path alias cannot be empty." );
  272. else
  273. m_errorMsg = _( "3D search path cannot be empty." );
  274. }
  275. m_errorGrid = dynamic_cast<wxGrid*>( event.GetEventObject() );
  276. m_errorRow = row;
  277. m_errorCol = col;
  278. event.Veto();
  279. }
  280. if( grid == m_EnvVars )
  281. {
  282. if( col == TV_VALUE_COL && m_EnvVars->GetCellValue( row, TV_FLAG_COL ).Length()
  283. && !Pgm().GetCommonSettings()->m_DoNotShowAgain.env_var_overwrite_warning )
  284. {
  285. wxString msg1 = _( "This path was defined externally to the running process and\n"
  286. "will only be temporarily overwritten." );
  287. wxString msg2 = _( "The next time KiCad is launched, any paths that have already\n"
  288. "been defined are honored and any settings defined in the path\n"
  289. "configuration dialog are ignored. If you did not intend for\n"
  290. "this behavior, either rename any conflicting entries or remove\n"
  291. "the external environment variable(s) from your system." );
  292. KIDIALOG dlg( this, msg1, KIDIALOG::KD_WARNING );
  293. dlg.ShowDetailedText( msg2 );
  294. dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
  295. dlg.ShowModal();
  296. if( dlg.DoNotShowAgain() )
  297. Pgm().GetCommonSettings()->m_DoNotShowAgain.env_var_overwrite_warning = true;
  298. }
  299. else if( col == TV_NAME_COL && m_EnvVars->GetCellValue( row, TV_NAME_COL ) != text )
  300. {
  301. // This env var name is reserved and cannot be added here.
  302. if( text == PROJECT_VAR_NAME )
  303. {
  304. wxMessageBox( wxString::Format( _( "The name %s is reserved, and cannot be used." ),
  305. PROJECT_VAR_NAME ) );
  306. event.Veto();
  307. }
  308. else // Changing name; clear external flag
  309. {
  310. m_EnvVars->SetCellValue( row, TV_FLAG_COL, wxEmptyString );
  311. }
  312. }
  313. }
  314. }
  315. void DIALOG_CONFIGURE_PATHS::OnAddEnvVar( wxCommandEvent& event )
  316. {
  317. if( !m_EnvVars->CommitPendingChanges() )
  318. return;
  319. AppendEnvVar( wxEmptyString, wxEmptyString, false );
  320. m_EnvVars->MakeCellVisible( m_EnvVars->GetNumberRows() - 1, TV_NAME_COL );
  321. m_EnvVars->SetGridCursor( m_EnvVars->GetNumberRows() - 1, TV_NAME_COL );
  322. m_EnvVars->EnableCellEditControl( true );
  323. m_EnvVars->ShowCellEditControl();
  324. }
  325. void DIALOG_CONFIGURE_PATHS::OnAddSearchPath( wxCommandEvent& event )
  326. {
  327. if( !m_SearchPaths->CommitPendingChanges() )
  328. return;
  329. AppendSearchPath( wxEmptyString, wxEmptyString, wxEmptyString);
  330. m_SearchPaths->MakeCellVisible( m_SearchPaths->GetNumberRows() - 1, SP_ALIAS_COL );
  331. m_SearchPaths->SetGridCursor( m_SearchPaths->GetNumberRows() - 1, SP_ALIAS_COL );
  332. m_SearchPaths->EnableCellEditControl( true );
  333. m_SearchPaths->ShowCellEditControl();
  334. }
  335. void DIALOG_CONFIGURE_PATHS::OnRemoveEnvVar( wxCommandEvent& event )
  336. {
  337. int curRow = m_EnvVars->GetGridCursorRow();
  338. if( curRow < 0 || m_EnvVars->GetNumberRows() <= curRow )
  339. return;
  340. else if( ENV_VAR::IsEnvVarImmutable( m_EnvVars->GetCellValue( curRow, TV_NAME_COL ) ) )
  341. {
  342. wxBell();
  343. return;
  344. }
  345. m_EnvVars->CommitPendingChanges( true /* silent mode; we don't care if it's valid */ );
  346. m_EnvVars->DeleteRows( curRow, 1 );
  347. m_EnvVars->MakeCellVisible( std::max( 0, curRow-1 ), m_EnvVars->GetGridCursorCol() );
  348. m_EnvVars->SetGridCursor( std::max( 0, curRow-1 ), m_EnvVars->GetGridCursorCol() );
  349. }
  350. void DIALOG_CONFIGURE_PATHS::OnDeleteSearchPath( wxCommandEvent& event )
  351. {
  352. int curRow = m_SearchPaths->GetGridCursorRow();
  353. if( curRow < 0 || m_SearchPaths->GetNumberRows() <= curRow )
  354. return;
  355. m_SearchPaths->CommitPendingChanges( true /* silent mode; we don't care if it's valid */ );
  356. m_SearchPaths->DeleteRows( curRow, 1 );
  357. // if there are still rows in grid, make previous row visible
  358. if( m_SearchPaths->GetNumberRows() )
  359. {
  360. m_SearchPaths->MakeCellVisible( std::max( 0, curRow-1 ),
  361. m_SearchPaths->GetGridCursorCol() );
  362. m_SearchPaths->SetGridCursor( std::max( 0, curRow-1 ), m_SearchPaths->GetGridCursorCol() );
  363. }
  364. }
  365. void DIALOG_CONFIGURE_PATHS::OnSearchPathMoveUp( wxCommandEvent& event )
  366. {
  367. if( !m_SearchPaths->CommitPendingChanges() )
  368. return;
  369. int curRow = m_SearchPaths->GetGridCursorRow();
  370. int prevRow = curRow - 1;
  371. if( curRow > 0 )
  372. {
  373. for( int i = 0; i < m_SearchPaths->GetNumberCols(); ++i )
  374. {
  375. wxString tmp = m_SearchPaths->GetCellValue( curRow, i );
  376. m_SearchPaths->SetCellValue( curRow, i, m_SearchPaths->GetCellValue( prevRow, i ) );
  377. m_SearchPaths->SetCellValue( prevRow, i, tmp );
  378. }
  379. m_SearchPaths->SetGridCursor( prevRow, m_SearchPaths->GetGridCursorCol() );
  380. }
  381. else
  382. {
  383. wxBell();
  384. }
  385. }
  386. void DIALOG_CONFIGURE_PATHS::OnSearchPathMoveDown( wxCommandEvent& event )
  387. {
  388. if( !m_SearchPaths->CommitPendingChanges() )
  389. return;
  390. int curRow = m_SearchPaths->GetGridCursorRow();
  391. int nextRow = curRow + 1;
  392. if( curRow < m_SearchPaths->GetNumberRows() - 1 )
  393. {
  394. for( int i = 0; i < m_SearchPaths->GetNumberCols(); ++i )
  395. {
  396. wxString tmp = m_SearchPaths->GetCellValue( curRow, i );
  397. m_SearchPaths->SetCellValue( curRow, i, m_SearchPaths->GetCellValue( nextRow, i ) );
  398. m_SearchPaths->SetCellValue( nextRow, i, tmp );
  399. }
  400. m_SearchPaths->SetGridCursor( nextRow, m_SearchPaths->GetGridCursorCol() );
  401. }
  402. else
  403. {
  404. wxBell();
  405. }
  406. }
  407. void DIALOG_CONFIGURE_PATHS::OnGridCellRightClick( wxGridEvent& aEvent )
  408. {
  409. wxASSERT((int) TV_VALUE_COL == (int) SP_PATH_COL );
  410. if( aEvent.GetCol() == TV_VALUE_COL )
  411. {
  412. wxMenu menu;
  413. AddMenuItem( &menu, 1, _( "File Browser..." ), KiBitmap( BITMAPS::small_folder ) );
  414. if( GetPopupMenuSelectionFromUser( menu ) == 1 )
  415. {
  416. wxDirDialog dlg( nullptr, _( "Select Path" ), m_curdir,
  417. wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );
  418. if( dlg.ShowModal() == wxID_OK )
  419. {
  420. wxGrid* grid = dynamic_cast<wxGrid*>( aEvent.GetEventObject() );
  421. grid->SetCellValue( aEvent.GetRow(), TV_VALUE_COL, dlg.GetPath() );
  422. m_curdir = dlg.GetPath();
  423. }
  424. }
  425. }
  426. }
  427. void DIALOG_CONFIGURE_PATHS::OnUpdateUI( wxUpdateUIEvent& event )
  428. {
  429. if( m_gridWidthsDirty )
  430. {
  431. int width = m_EnvVars->GetClientRect().GetWidth();
  432. m_EnvVars->AutoSizeColumn( TV_NAME_COL );
  433. m_EnvVars->SetColSize( TV_NAME_COL, std::max( m_EnvVars->GetColSize( TV_NAME_COL ), 120 ) );
  434. m_EnvVars->SetColSize( TV_VALUE_COL, width - m_EnvVars->GetColSize( TV_NAME_COL ) );
  435. width = m_SearchPaths->GetClientRect().GetWidth();
  436. m_SearchPaths->AutoSizeColumn( SP_ALIAS_COL );
  437. m_SearchPaths->SetColSize( SP_ALIAS_COL,
  438. std::max( m_SearchPaths->GetColSize( SP_ALIAS_COL ), 120 ) );
  439. m_SearchPaths->AutoSizeColumn( SP_PATH_COL );
  440. m_SearchPaths->SetColSize( SP_PATH_COL,
  441. std::max( m_SearchPaths->GetColSize( SP_PATH_COL ), 300 ) );
  442. m_SearchPaths->SetColSize( SP_DESC_COL, width -
  443. ( m_SearchPaths->GetColSize( SP_ALIAS_COL ) +
  444. m_SearchPaths->GetColSize( SP_PATH_COL ) ) );
  445. m_gridWidth = m_EnvVars->GetSize().GetX();
  446. m_gridWidthsDirty = false;
  447. }
  448. // Handle a grid error. This is delayed to OnUpdateUI so that we can change focus
  449. // even when the original validation was triggered from a killFocus event (and for
  450. // dialog with notebooks, so that the corresponding notebook page can be shown in
  451. // the background when triggered from an OK).
  452. if( m_errorGrid )
  453. {
  454. // We will re-enter this routine when the error dialog is displayed, so make
  455. // sure we don't keep putting up more dialogs.
  456. wxGrid* grid = m_errorGrid;
  457. m_errorGrid = nullptr;
  458. DisplayErrorMessage( this, m_errorMsg );
  459. grid->SetFocus();
  460. grid->MakeCellVisible( m_errorRow, m_errorCol );
  461. grid->SetGridCursor( m_errorRow, m_errorCol );
  462. grid->EnableCellEditControl( true );
  463. grid->ShowCellEditControl();
  464. }
  465. }
  466. void DIALOG_CONFIGURE_PATHS::OnGridSize( wxSizeEvent& event )
  467. {
  468. if( event.GetSize().GetX() != m_gridWidth )
  469. m_gridWidthsDirty = true;
  470. event.Skip();
  471. }
  472. void DIALOG_CONFIGURE_PATHS::OnHelp( wxCommandEvent& event )
  473. {
  474. if( m_helpDialog )
  475. {
  476. m_helpDialog->ShowModeless();
  477. return;
  478. }
  479. wxString msg = _( "Enter the name and value for each environment variable. Grey entries "
  480. "are names that have been defined externally at the system or user "
  481. "level. Environment variables defined at the system or user level "
  482. "take precedence over the ones defined in this table. This means the "
  483. "values in this table are ignored." );
  484. msg << "<br><br><b>";
  485. msg << _( "To ensure environment variable names are valid on all platforms, the name field "
  486. "will only accept upper case letters, digits, and the underscore characters." );
  487. msg << "</b>";
  488. for( const auto& var : ENV_VAR::GetPredefinedEnvVars() )
  489. {
  490. msg << "<br><br><b>" << var << "</b>";
  491. const auto desc = ENV_VAR::LookUpEnvVarHelp( var );
  492. if( desc.size() > 0 )
  493. msg << ": " << desc;
  494. }
  495. m_helpDialog = new HTML_MESSAGE_BOX( nullptr, _( "Environment Variable Help" ) );
  496. m_helpDialog->SetDialogSizeInDU( 400, 250 );
  497. m_helpDialog->AddHTML_Text( msg );
  498. m_helpDialog->ShowModeless();
  499. // m_helpDialog will be destroyed when closing the dialog
  500. }