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.

511 lines
15 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-2018 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. /**
  25. * @file dialog_env_var_config.cpp
  26. */
  27. #include <dialog_env_var_config.h>
  28. #include <confirm.h>
  29. #include <validators.h>
  30. #include <html_messagebox.h>
  31. #include <wx/regex.h>
  32. /** A helper dialog to edit a env var name and/or its value (often a path)
  33. */
  34. class DIALOG_ENV_VAR_SINGLE : public DIALOG_ENV_VAR_SINGLE_BASE
  35. {
  36. public:
  37. DIALOG_ENV_VAR_SINGLE( wxWindow* parent, const wxString& aEnvVarName,
  38. const wxString& aEnvVarPath );
  39. /// @return the new environment variable name
  40. wxString GetEnvVarName() const
  41. {
  42. return m_envVarName->GetValue();
  43. }
  44. /// @return the new environment variable value
  45. wxString GetEnvVarValue() const
  46. {
  47. return m_envVarPath->GetValue();
  48. }
  49. /// disable the environment variable name (must be called
  50. /// for predefined environment variable names, not editable
  51. void SetEnvVarProtected()
  52. {
  53. m_envVarName->Enable( false );
  54. }
  55. protected:
  56. void OnSelectPath( wxCommandEvent& event ) override;
  57. void onHelpClick( wxCommandEvent& event ) override;
  58. // Currently, only upper case variable names are accepted. onVarNameChange
  59. // changes on the fly any lower case char by the corresponding upper case
  60. void onVarNameChange( wxCommandEvent& event ) override;
  61. bool TransferDataFromWindow() override;
  62. };
  63. DIALOG_ENV_VAR_CONFIG::DIALOG_ENV_VAR_CONFIG( wxWindow* aParent, const ENV_VAR_MAP& aEnvVarMap ) :
  64. DIALOG_ENV_VAR_CONFIG_BASE( aParent )
  65. {
  66. // Copy environment variables across
  67. m_envVarMap = aEnvVarMap;
  68. }
  69. bool DIALOG_ENV_VAR_CONFIG::TransferDataToWindow()
  70. {
  71. wxLogDebug( wxT( "In DIALOG_ENV_VAR_CONFIG::TransferDataToWindow()." ) );
  72. if( !wxDialog::TransferDataToWindow() )
  73. return false;
  74. //TODO
  75. /*
  76. // Grab the project path var (not editable)
  77. wxString prjPath;
  78. wxGetEnv( PROJECT_VAR_NAME, &prjPath );
  79. m_kiprjmod->SetLabel( prjPath );
  80. */
  81. //TODO - Call SetAlternateRowColour first to prevent assertion error
  82. //m_pathList->EnableAlternateRowColours( true );
  83. PopulatePathList();
  84. // Select the first item in the list
  85. SelectListIndex( 0 );
  86. GetSizer()->Layout();
  87. GetSizer()->Fit( this );
  88. GetSizer()->SetSizeHints( this );
  89. return true;
  90. }
  91. bool DIALOG_ENV_VAR_CONFIG::TransferDataFromWindow()
  92. {
  93. if( !wxDialog::TransferDataFromWindow() )
  94. {
  95. return false;
  96. }
  97. Pgm().SetLocalEnvVariables( m_envVarMap );
  98. return true;
  99. }
  100. void DIALOG_ENV_VAR_CONFIG::PopulatePathList()
  101. {
  102. m_pathList->Freeze();
  103. m_pathList->ClearAll();
  104. m_pathList->AppendColumn( _( "Name:" ) );
  105. m_pathList->AppendColumn( _( "Path:" ) );
  106. int row = 0;
  107. for( auto it = m_envVarMap.begin(); it != m_envVarMap.end(); ++it )
  108. {
  109. long index = m_pathList->InsertItem( row, it->first );
  110. m_pathList->SetItem( index, 1, it->second.GetValue() );
  111. if( it->second.GetDefinedExternally() )
  112. {
  113. wxColour color = wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT );
  114. m_pathList->SetItemBackgroundColour( index, color );
  115. }
  116. row++;
  117. }
  118. m_pathList->SetColumnWidth( 0, wxLIST_AUTOSIZE );
  119. m_pathList->SetColumnWidth( 1, wxLIST_AUTOSIZE );
  120. m_pathList->Update();
  121. m_pathList->Thaw();
  122. }
  123. bool DIALOG_ENV_VAR_CONFIG::GetPathAtIndex( unsigned int aIndex, wxString& aEnvVar,
  124. wxString& aEnvPath )
  125. {
  126. if( aIndex > m_envVarMap.size() )
  127. {
  128. return false;
  129. }
  130. unsigned int idx = 0;
  131. for( auto it = m_envVarMap.begin(); it != m_envVarMap.end(); ++it )
  132. {
  133. if( idx == aIndex )
  134. {
  135. aEnvVar = it->first;
  136. aEnvPath = it->second.GetValue();
  137. return true;
  138. }
  139. idx++;
  140. }
  141. return false;
  142. }
  143. void DIALOG_ENV_VAR_CONFIG::OnAddButton( wxCommandEvent& event )
  144. {
  145. DIALOG_ENV_VAR_SINGLE dlg( nullptr, wxEmptyString, wxEmptyString );
  146. if( dlg.ShowModal() == wxID_OK )
  147. {
  148. wxString newName = dlg.GetEnvVarName();
  149. wxString newPath = dlg.GetEnvVarValue();
  150. // Check that the name does not already exist
  151. if( m_envVarMap.count( newName ) > 0 )
  152. {
  153. //TODO - Improve this message, use DisplayErrorMessage instead
  154. DisplayError( this, _( "Path already exists." ) );
  155. }
  156. else
  157. {
  158. m_envVarMap[newName] = ENV_VAR_ITEM( newPath );
  159. // Update path list
  160. PopulatePathList();
  161. }
  162. }
  163. }
  164. void DIALOG_ENV_VAR_CONFIG::OnEditButton( wxCommandEvent& event )
  165. {
  166. EditSelectedEntry();
  167. }
  168. void DIALOG_ENV_VAR_CONFIG::EditSelectedEntry()
  169. {
  170. wxString envName;
  171. wxString envPath;
  172. if( GetPathAtIndex( m_pathIndex, envName, envPath ) )
  173. {
  174. auto dlg = new DIALOG_ENV_VAR_SINGLE( nullptr, envName, envPath );
  175. if( IsEnvVarImmutable( envName ) )
  176. {
  177. dlg->SetEnvVarProtected();
  178. }
  179. if( dlg->ShowModal() == wxID_OK )
  180. {
  181. wxString newName = dlg->GetEnvVarName();
  182. wxString newPath = dlg->GetEnvVarValue();
  183. // If the path name has not been changed
  184. if( envName.Cmp( newName ) == 0 )
  185. {
  186. m_envVarMap[envName].SetValue( newPath );
  187. if( m_envVarMap[envName].GetDefinedExternally() )
  188. {
  189. m_extDefsChanged = true;
  190. }
  191. }
  192. // Path-name needs to be updated
  193. else
  194. {
  195. if( IsEnvVarImmutable( envName ) )
  196. {
  197. DisplayErrorMessage( this,
  198. wxString::Format( _( "Environment variable \"%s\" cannot "
  199. "be renamed." ),
  200. envName.ToStdString() ),
  201. _( "The selected environment variable name "
  202. "is required for KiCad functionality and "
  203. "can not be renamed." ) );
  204. return;
  205. }
  206. auto envVar = m_envVarMap[envName];
  207. m_envVarMap.erase( envName );
  208. envVar.SetValue( newPath );
  209. envVar.SetDefinedExternally( false );
  210. m_envVarMap[newName] = envVar;
  211. }
  212. // Update the path list
  213. PopulatePathList();
  214. }
  215. dlg->Destroy();
  216. }
  217. }
  218. void DIALOG_ENV_VAR_CONFIG::OnHelpButton( wxCommandEvent& event )
  219. {
  220. wxString msg = _( "Enter the name and value for each environment variable. Grey entries "
  221. "are names that have been defined externally at the system or user "
  222. "level. Environment variables defined at the system or user level "
  223. "take precedence over the ones defined in this table. This means the "
  224. "values in this table are ignored." );
  225. msg << wxT( "<br><br><b>" );
  226. msg << _( "To ensure environment variable names are valid on all platforms, the name field "
  227. "will only accept upper case letters, digits, and the underscore characters." );
  228. msg << wxT( "</b><br><br>" );
  229. msg << _( "<b>KICAD_SYMBOL_DIR</b> is the base path of the locally installed symbol "
  230. "libraries." );
  231. msg << wxT( "<br><br>" );
  232. msg << _( "<b>KIGITHUB</b> is used by KiCad to define the URL of the repository "
  233. "of the official KiCad footprint libraries. This is only required if the "
  234. "Github plugin is used to access footprint libraries" );
  235. msg << wxT( "<br><br>" );
  236. msg << _( "<b>KISYS3DMOD</b> is the base path of system footprint 3D "
  237. "shapes (.3Dshapes folders)." );
  238. msg << wxT( "<br><br>" );
  239. msg << _( "<b>KISYSMOD</b> is the base path of locally installed system "
  240. "footprint libraries (.pretty folders)." );
  241. msg << wxT( "<br><br>" );
  242. msg << _( "<b>KIPRJMOD</b> is internally defined by KiCad (cannot be edited) and is set "
  243. "to the absolute path of the currently loaded project file. This environment "
  244. "variable can be used to define files and paths relative to the currently loaded "
  245. "project. For instance, ${KIPRJMOD}/libs/footprints.pretty can be defined as a "
  246. "folder containing a project specific footprint library named footprints.pretty." );
  247. msg << wxT( "<br><br>" );
  248. msg << _( "<b>KICAD_TEMPLATE_DIR</b> is required and is the path containing the project "
  249. "templates installed with KiCad." );
  250. msg << wxT( "<br><br>" );
  251. msg << _( "<b>KICAD_USER_TEMPLATE_DIR</b> is required and is the path containing any user "
  252. "specific project templates." );
  253. HTML_MESSAGE_BOX dlg( GetParent(), _( "Environment Variable Help" ) );
  254. dlg.SetDialogSizeInDU( 400, 350 );
  255. dlg.AddHTML_Text( msg );
  256. dlg.ShowModal();
  257. }
  258. bool DIALOG_ENV_VAR_CONFIG::IsEnvVarImmutable( const wxString aEnvVar )
  259. {
  260. /*
  261. * TODO - Instead of defining these values here,
  262. * extract them from elsewhere in the program
  263. * (where they are originally defined)
  264. */
  265. static const wxString immutable[] = {
  266. "KIGITHUB",
  267. "KISYS3DMOD",
  268. "KISYSMOD",
  269. "KIPRJMOD",
  270. "KICAD_SYMBOL_DIR",
  271. "KICAD_TEMPLATE_DIR",
  272. "KICAD_USER_TEMPLATE_DIR"
  273. };
  274. for( unsigned int ii=0; ii<6; ii++ )
  275. {
  276. if( aEnvVar.Cmp( immutable[ii] ) == 0 )
  277. {
  278. return true;
  279. }
  280. }
  281. return false;
  282. }
  283. void DIALOG_ENV_VAR_CONFIG::OnRemoveButton( wxCommandEvent& event )
  284. {
  285. wxString envName;
  286. wxString envPath;
  287. if( GetPathAtIndex( m_pathIndex, envName, envPath ) )
  288. {
  289. if( IsEnvVarImmutable( envName ) )
  290. {
  291. return;
  292. }
  293. m_envVarMap.erase( envName );
  294. PopulatePathList();
  295. }
  296. }
  297. void DIALOG_ENV_VAR_CONFIG::SelectListIndex( unsigned int aIndex )
  298. {
  299. if( aIndex >= m_envVarMap.size() )
  300. {
  301. aIndex = 0;
  302. }
  303. m_pathIndex = aIndex;
  304. wxString envName;
  305. wxString envPath;
  306. if( GetPathAtIndex( m_pathIndex, envName, envPath ) )
  307. {
  308. // Disable the 'delete' button if the path cannot be deleted
  309. m_deletePathButton->Enable( !IsEnvVarImmutable( envName ) );
  310. }
  311. }
  312. void DIALOG_ENV_VAR_CONFIG::OnPathSelected( wxListEvent& event )
  313. {
  314. SelectListIndex( event.GetIndex() );
  315. }
  316. void DIALOG_ENV_VAR_CONFIG::OnPathActivated( wxListEvent& event )
  317. {
  318. SelectListIndex( event.GetIndex() );
  319. EditSelectedEntry();
  320. }
  321. ///////////////////////////
  322. // DIALOG_ENV_VAR_SINGLE //
  323. ///////////////////////////
  324. DIALOG_ENV_VAR_SINGLE::DIALOG_ENV_VAR_SINGLE( wxWindow* parent,
  325. const wxString& aEnvVarName,
  326. const wxString& aEnvVarPath ) :
  327. DIALOG_ENV_VAR_SINGLE_BASE( parent )
  328. {
  329. m_envVarName->SetValue( aEnvVarName );
  330. m_envVarPath->SetValue( aEnvVarPath );
  331. m_envVarName->SetValidator( ENV_VAR_NAME_VALIDATOR() );
  332. }
  333. void DIALOG_ENV_VAR_SINGLE::OnSelectPath( wxCommandEvent& event )
  334. {
  335. wxString title = _( "Select Path for Environment Variable" );
  336. wxString path; // Currently the first opened path is not initialized
  337. wxDirDialog dlg( nullptr, title, path, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );
  338. if( dlg.ShowModal() == wxID_OK )
  339. m_envVarPath->SetValue( dlg.GetPath() );
  340. }
  341. void DIALOG_ENV_VAR_SINGLE::onVarNameChange( wxCommandEvent& event )
  342. {
  343. wxString upper_var = m_envVarName->GetValue().Upper();
  344. if( upper_var != m_envVarName->GetValue() )
  345. {
  346. int pos = m_envVarName->GetInsertionPoint();
  347. m_envVarName->ChangeValue( upper_var );
  348. m_envVarName->SetInsertionPoint( pos );
  349. }
  350. }
  351. bool DIALOG_ENV_VAR_SINGLE::TransferDataFromWindow()
  352. {
  353. // The user pressed the OK button, test data validity
  354. wxString name = m_envVarName->GetValue();
  355. wxString path = m_envVarPath->GetValue();
  356. // Neither name nor path can be empty
  357. if( name.IsEmpty() )
  358. {
  359. DisplayError( this, _( "Environment variable name cannot be empty." ) );
  360. // Veto:
  361. return false;
  362. }
  363. if( path.IsEmpty() )
  364. {
  365. DisplayError( this, _( "Environment variable value cannot be empty." ) );
  366. // Veto:
  367. return false;
  368. }
  369. // Name cannot start with a number
  370. if( name.Left( 1 ).IsNumber() )
  371. {
  372. DisplayError( this, _( "Environment variable names cannot start with a digit (0-9)." ) );
  373. // Veto:
  374. return false;
  375. }
  376. // No errors detected
  377. return true;
  378. }
  379. void DIALOG_ENV_VAR_SINGLE::onHelpClick( wxCommandEvent& event )
  380. {
  381. wxString msg = _( "An environment variable is used for string substitutions.<br>"
  382. "Environment variables are primarily used for paths to make KiCad portable "
  383. "between platforms.<br><br>"
  384. "If an environment variable is defined as <b>MYLIBPATH</b> with a "
  385. "value <b>e:/kicad_libs</b>, then a library name "
  386. "<b>${MYLIBPATH}/mylib.lib</b> gets expanded to "
  387. "<b>e:/kicad_libs/mylib.lib</b>"
  388. "<br><br>"
  389. "<b>Note:</b><br>"
  390. "Only characters <b>ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_</b> are "
  391. "allowed in environment variable names and the environment variable name "
  392. "cannot start with a digit (0-9)."
  393. );
  394. HTML_MESSAGE_BOX dlg( GetParent(), _( "Environment Variable Help" ) );
  395. dlg.SetDialogSizeInDU( 400, 350 );
  396. dlg.AddHTML_Text( msg );
  397. dlg.ShowModal();
  398. }