KiCad PCB EDA Suite
dialog_env_var_config.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) 2015 Wayne Stambaugh <stambaughw@gmail.com>
5  * Copyright (C) 2015-2017 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 
29 #include <dialog_env_var_config.h>
30 
31 #include <confirm.h>
32 
33 #include <validators.h>
34 #include <html_messagebox.h>
35 
36 #include <wx/regex.h>
37 
41 {
42 public:
43  DIALOG_ENV_VAR_SINGLE( wxWindow* parent, const wxString& aEnvVarName,
44  const wxString& aEnvVarPath );
45 
47  wxString GetEnvVarName() const
48  {
49  return m_envVarName->GetValue();
50  }
51 
53  wxString GetEnvVarValue() const
54  {
55  return m_envVarPath->GetValue();
56  }
57 
61  {
62  m_envVarName->Enable( false );
63  }
64 
65 protected:
66  void OnSelectPath( wxCommandEvent& event ) override;
67  void onHelpClick( wxCommandEvent& event ) override;
68 
69  // Currently, only upper case variable names are acepted. onVarNameChange
70  // changes on the fly any lower case char by the corresponding upper case
71  void onVarNameChange( wxCommandEvent& event ) override;
72 
73  bool TransferDataFromWindow() override;
74 };
75 
76 
77 DIALOG_ENV_VAR_CONFIG::DIALOG_ENV_VAR_CONFIG( wxWindow* aParent, const ENV_VAR_MAP& aEnvVarMap ) :
79 {
80  // Copy environment variables across
81  m_envVarMap = aEnvVarMap;
82 }
83 
84 
86 {
87  wxLogDebug( wxT( "In DIALOG_ENV_VAR_CONFIG::TransferDataToWindow()." ) );
88 
89  if( !wxDialog::TransferDataToWindow() )
90  return false;
91 
92  //TODO
93  /*
94  // Grab the project path var (not editable)
95  wxString prjPath;
96 
97  wxGetEnv( PROJECT_VAR_NAME, &prjPath );
98 
99  m_kiprjmod->SetLabel( prjPath );
100  */
101 
102  //TODO - Call SetAlternateRowColour first to prevent assertion error
103  //m_pathList->EnableAlternateRowColours( true );
104 
106 
107  // Select the first item in the list
108  SelectListIndex( 0 );
109 
110  GetSizer()->Layout();
111  GetSizer()->Fit( this );
112  GetSizer()->SetSizeHints( this );
113 
114  return true;
115 }
116 
117 
119 {
120  if( !wxDialog::TransferDataFromWindow() )
121  {
122  return false;
123  }
124 
126 
127  return true;
128 }
129 
130 
132 {
133  m_pathList->Freeze();
134 
135  m_pathList->ClearAll();
136 
137  m_pathList->AppendColumn( _( "Name:" ) );
138  m_pathList->AppendColumn( _( "Path:" ) );
139 
140  int row = 0;
141 
142  for( auto it = m_envVarMap.begin(); it != m_envVarMap.end(); ++it )
143  {
144  long index = m_pathList->InsertItem( row, it->first );
145 
146  m_pathList->SetItem( index, 1, it->second.GetValue() );
147 
148  if( it->second.GetDefinedExternally() )
149  {
150  wxColour color = wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT );
151 
152  m_pathList->SetItemBackgroundColour( index, color );
153  }
154 
155  row++;
156  }
157 
158  m_pathList->SetColumnWidth( 0, wxLIST_AUTOSIZE );
159  m_pathList->SetColumnWidth( 1, wxLIST_AUTOSIZE );
160 
161  m_pathList->Update();
162 
163  m_pathList->Thaw();
164 }
165 
166 
167 bool DIALOG_ENV_VAR_CONFIG::GetPathAtIndex( unsigned int aIndex, wxString& aEnvVar,
168  wxString& aEnvPath )
169 {
170  if( aIndex > m_envVarMap.size() )
171  {
172  return false;
173  }
174 
175  unsigned int idx = 0;
176 
177  for( auto it = m_envVarMap.begin(); it != m_envVarMap.end(); ++it )
178  {
179  if( idx == aIndex )
180  {
181  aEnvVar = it->first;
182  aEnvPath = it->second.GetValue();
183 
184  return true;
185  }
186 
187  idx++;
188  }
189 
190  return false;
191 }
192 
193 
194 void DIALOG_ENV_VAR_CONFIG::OnAddButton( wxCommandEvent& event )
195 {
196  DIALOG_ENV_VAR_SINGLE dlg( nullptr, wxEmptyString, wxEmptyString );
197 
198  if( dlg.ShowModal() == wxID_OK )
199  {
200  wxString newName = dlg.GetEnvVarName();
201  wxString newPath = dlg.GetEnvVarValue();
202 
203  // Check that the name does not already exist
204  if( m_envVarMap.count( newName ) > 0 )
205  {
206  //TODO - Improve this message, use DisplayErrorMessage instead
207  DisplayError( this, _( "Path already exists." ) );
208  }
209  else
210  {
211  m_envVarMap[newName] = ENV_VAR_ITEM( newPath );
212 
213  // Update path list
215  }
216  }
217 }
218 
219 
220 void DIALOG_ENV_VAR_CONFIG::OnEditButton( wxCommandEvent& event )
221 {
223 }
224 
225 
227 {
228  wxString envName;
229  wxString envPath;
230 
231  if( GetPathAtIndex( m_pathIndex, envName, envPath ) )
232  {
233  auto dlg = new DIALOG_ENV_VAR_SINGLE( nullptr, envName, envPath );
234 
235  if( IsEnvVarImmutable( envName ) )
236  {
237  dlg->SetEnvVarProtected();
238  }
239 
240  if( dlg->ShowModal() == wxID_OK )
241  {
242  wxString newName = dlg->GetEnvVarName();
243  wxString newPath = dlg->GetEnvVarValue();
244 
245  // If the path name has not been changed
246  if( envName.Cmp( newName ) == 0 )
247  {
248  m_envVarMap[envName].SetValue( newPath );
249 
250  if( m_envVarMap[envName].GetDefinedExternally() )
251  {
252  m_extDefsChanged = true;
253  }
254  }
255  // Path-name needs to be updated
256  else
257  {
258  if( IsEnvVarImmutable( envName ) )
259  {
260  DisplayErrorMessage( this,
261  wxString::Format( _( "Environment variable \"%s\" cannot "
262  "be renamed." ),
263  envName.ToStdString() ),
264  _( "The selected environment variable name "
265  "is required for KiCad functionality and "
266  "can not be renamed." ) );
267 
268  return;
269  }
270 
271  auto envVar = m_envVarMap[envName];
272 
273  m_envVarMap.erase( envName );
274 
275  envVar.SetValue( newPath );
276  envVar.SetDefinedExternally( false );
277  m_envVarMap[newName] = envVar;
278  }
279 
280  // Update the path list
282  }
283 
284  dlg->Destroy();
285  }
286 }
287 
288 void DIALOG_ENV_VAR_CONFIG::OnHelpButton( wxCommandEvent& event )
289 {
290  wxString msg = _( "Enter the name and value for each environment variable. Grey entries "
291  "are names that have been defined externally at the system or user "
292  "level. Environment variables defined at the system or user level "
293  "take precedence over the ones defined in this table. This means the "
294  "values in this table are ignored." );
295  msg << wxT( "<br><br><b>" );
296  msg << _( "To ensure environment variable names are valid on all platforms, the name field "
297  "will only accept upper case letters, digits, and the underscore characters." );
298  msg << wxT( "</b><br><br>" );
299  msg << _( "<b>KICAD_SYMBOL_DIR</b> is the base path of the locally installed symbol libraries." );
300  msg << wxT( "<br><br>" );
301  msg << _( "<b>KIGITHUB</b> is used by KiCad to define the URL of the repository "
302  "of the official KiCad footprint libraries." );
303  msg << wxT( "<br><br>" );
304  msg << _( "<b>KISYS3DMOD</b> is the base path of system footprint 3D "
305  "shapes (.3Dshapes folders)." );
306  msg << wxT( "<br><br>" );
307  msg << _( "<b>KISYSMOD</b> is the base path of locally installed system "
308  "footprint libraries (.pretty folders)." );
309  msg << wxT( "<br><br>" );
310  msg << _( "<b>KIPRJMOD</b> is internally defined by KiCad (cannot be edited) and is set "
311  "to the absolute path of the currently loaded project file. This environment "
312  "variable can be used to define files and paths relative to the currently loaded "
313  "project. For instance, ${KIPRJMOD}/libs/footprints.pretty can be defined as a "
314  "folder containing a project specific footprint library named footprints.pretty." );
315  msg << wxT( "<br><br>" );
316  msg << _( "<b>KICAD_PTEMPLATES</b> is optional and can be defined if you want to "
317  "create your own project templates folder." );
318 
319  HTML_MESSAGE_BOX dlg( GetParent(), _( "Environment Variable Help" ) );
320  dlg.SetDialogSizeInDU( 400, 350 );
321 
322  dlg.AddHTML_Text( msg );
323  dlg.ShowModal();
324 }
325 
326 
327 bool DIALOG_ENV_VAR_CONFIG::IsEnvVarImmutable( const wxString aEnvVar )
328 {
329  /*
330  * TODO - Instead of defining these values here,
331  * extract them from elsewhere in the program
332  * (where they are originally defined)
333  */
334 
335  static const wxString immutable[] = {
336  "KIGITHUB",
337  "KISYS3DMOD",
338  "KISYSMOD",
339  "KIPRJMOD",
340  "KICAD_PTEMPLATES",
341  "KICAD_SYMBOL_DIR"
342  };
343 
344  for( unsigned int ii=0; ii<6; ii++ )
345  {
346  if( aEnvVar.Cmp( immutable[ii] ) == 0 )
347  {
348  return true;
349  }
350  }
351 
352  return false;
353 }
354 
355 
356 void DIALOG_ENV_VAR_CONFIG::OnRemoveButton( wxCommandEvent& event )
357 {
358  wxString envName;
359  wxString envPath;
360 
361  if( GetPathAtIndex( m_pathIndex, envName, envPath ) )
362  {
363  if( IsEnvVarImmutable( envName ) )
364  {
365  return;
366  }
367 
368  m_envVarMap.erase( envName );
369 
371  }
372 }
373 
374 
375 void DIALOG_ENV_VAR_CONFIG::SelectListIndex( unsigned int aIndex )
376 {
377  if( aIndex >= m_envVarMap.size() )
378  {
379  aIndex = 0;
380  }
381 
382  m_pathIndex = aIndex;
383 
384  wxString envName;
385  wxString envPath;
386 
387  if( GetPathAtIndex( m_pathIndex, envName, envPath ) )
388  {
389  // Disable the 'delete' button if the path cannot be deleted
390  m_deletePathButton->Enable( !IsEnvVarImmutable( envName ) );
391  }
392 }
393 
394 void DIALOG_ENV_VAR_CONFIG::OnPathSelected( wxListEvent& event )
395 {
396  SelectListIndex( event.GetIndex() );
397 }
398 
399 
400 void DIALOG_ENV_VAR_CONFIG::OnPathActivated( wxListEvent& event )
401 {
402  SelectListIndex( event.GetIndex() );
403 
405 }
406 
407 
409 // DIALOG_ENV_VAR_SINGLE //
411 
413  const wxString& aEnvVarName,
414  const wxString& aEnvVarPath ) :
416 {
417  m_envVarName->SetValue( aEnvVarName );
418  m_envVarPath->SetValue( aEnvVarPath );
420 }
421 
422 
423 void DIALOG_ENV_VAR_SINGLE::OnSelectPath( wxCommandEvent& event )
424 {
425  wxString title = _( "Select Path for Environment Variable" );
426  wxString path; // Currently the first opened path is not initialized
427 
428  wxDirDialog dlg( nullptr, title, path, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );
429 
430  if( dlg.ShowModal() == wxID_OK )
431  m_envVarPath->SetValue( dlg.GetPath() );
432 }
433 
434 
435 void DIALOG_ENV_VAR_SINGLE::onVarNameChange( wxCommandEvent& event )
436 {
437  wxString upper_var = m_envVarName->GetValue().Upper();
438 
439  if( upper_var != m_envVarName->GetValue() )
440  {
441  int pos = m_envVarName->GetInsertionPoint();
442  m_envVarName->ChangeValue( upper_var );
443  m_envVarName->SetInsertionPoint( pos );
444  }
445 
446 }
447 
448 
450 {
451  // The user pressed the OK button, test data validity
452  wxString name = m_envVarName->GetValue();
453  wxString path = m_envVarPath->GetValue();
454 
455  // Neither name nor path can be empty
456  if( name.IsEmpty() )
457  {
458  DisplayError( this, _( "Environment variable name cannot be empty." ) );
459  // Veto:
460  return false;
461  }
462 
463  if( path.IsEmpty() )
464  {
465  DisplayError( this, _( "Environment variable value cannot be empty." ) );
466  // Veto:
467  return false;
468  }
469 
470  // Name cannot start with a number
471  if( name.Left( 1 ).IsNumber() )
472  {
473  DisplayError( this, _( "Environment variable names cannot start with a digit (0-9)." ) );
474  // Veto:
475  return false;
476  }
477 
478  // No errors detected
479  return true;
480 }
481 
482 
483 void DIALOG_ENV_VAR_SINGLE::onHelpClick( wxCommandEvent& event )
484 {
485  wxString msg = _( "An environment variable is used for string substitutions.<br>"
486  "Environment variables are primarily used for paths to make KiCad portable "
487  "between platforms.<br><br>"
488  "If an environment variable is defined as <b>MYLIBPATH</b> with a "
489  "value <b>e:/kicad_libs</b>, then a library name "
490  "<b>${MYLIBPATH}/mylib.lib</b> gets expanded to "
491  "<b>e:/kicad_libs/mylib.lib</b>"
492  "<br><br>"
493  "<b>Note:</b><br>"
494  "Only characters <b>ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_</b> are "
495  "allowed in environment variable names and the environment variable name "
496  "cannot start with a digit (0-9)."
497  );
498 
499  HTML_MESSAGE_BOX dlg( GetParent(), _( "Environment Variable Help" ) );
500  dlg.SetDialogSizeInDU( 400, 350 );
501 
502  dlg.AddHTML_Text( msg );
503  dlg.ShowModal();
504 }
void EditSelectedEntry()
Edit the currently selected ENV_VAR entry.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Function DisplayErrorMessage displays an error message with aMessage.
Definition: confirm.cpp:199
bool GetPathAtIndex(unsigned int aIndex, wxString &aEnvVar, wxString &aEnvPath)
Extract the NAME and PATH data from the ENV_VAR at the provided index.
wxString GetEnvVarName() const
bool TransferDataFromWindow() override
This file is part of the common library.
virtual void OnEditButton(wxCommandEvent &event) override
Class ENV_VAR_ITEM.
Definition: pgm_base.h:58
int color
Definition: DXF_plotter.cpp:62
Class DIALOG_ENV_VAR_CONFIG_BASE.
virtual void OnRemoveButton(wxCommandEvent &event) override
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:65
void OnSelectPath(wxCommandEvent &event) override
wxString GetEnvVarValue() const
Class ENVIRONMENT_VARIABLE_CHAR_VALIDATOR.
Definition: validators.h:75
void SetEnvVarProtected()
disable the environment variable name (must be called for predefined environment variable names...
void PopulatePathList()
Update the displayed list of ENV_VAR paths.
virtual void OnPathActivated(wxListEvent &event) override
void SelectListIndex(unsigned int aIndex)
Select the ENV_VAR at the provided index.
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
Definition: pgm_base.h:87
bool IsEnvVarImmutable(const wxString aEnvVar)
Determine if a particular ENV_VAR is protected.
Subclass of DIALOG_DISPLAY_HTML_TEXT_BASE, which is generated by wxFormBuilder.
virtual void OnHelpButton(wxCommandEvent &event) override
Class DIALOG_ENV_VAR_SINGLE_BASE.
Class HTML_MESSAGE_BOX.
A helper dialog to edit a env var name and/or its value (often a path)
VTBL_ENTRY void SetLocalEnvVariables(const ENV_VAR_MAP &aEnvVarMap)
Function SetLocalEnvVariables.
Definition: pgm_base.cpp:891
void SetDialogSizeInDU(int aWidth, int aHeight)
set the dialog size, using a "logical value.
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
virtual void OnAddButton(wxCommandEvent &event) override
DIALOG_ENV_VAR_SINGLE(wxWindow *parent, const wxString &aEnvVarName, const wxString &aEnvVarPath)
void AddHTML_Text(const wxString &message)
Function AddHTML_Text adds html text (without any change) to message list.
DIALOG_ENV_VAR_CONFIG(wxWindow *parent, const ENV_VAR_MAP &aEnvVarMap)
virtual void OnPathSelected(wxListEvent &event) override
bool TransferDataFromWindow() override
bool TransferDataToWindow() override
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:185
void onHelpClick(wxCommandEvent &event) override
void onVarNameChange(wxCommandEvent &event) override
Custom text control validator definitions.