KiCad PCB EDA Suite
dlg_3d_pathconfig.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) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 
25 #include <wx/msgdlg.h>
26 #include <pgm_base.h>
27 #include <html_messagebox.h>
30 
32  DLG_3D_PATH_CONFIG_BASE( aParent ), m_resolver( aResolver )
33 {
34  initDialog();
35 
36  GetSizer()->SetSizeHints( this );
37  Centre();
38 
39  return;
40 }
41 
42 
44 {
45  m_Aliases->EnableEditing( true );
46 
47  // Gives a min width to each column, when the user drags a column
48  m_Aliases->SetColMinimalWidth( 0, 80 );
49  m_Aliases->SetColMinimalWidth( 1, 300 );
50  m_Aliases->SetColMinimalWidth( 2, 120 );
51  m_Aliases->SetColMinimalAcceptableWidth( 80 );
52 
53  // Set column sizes to this min value
54  m_Aliases->SetColSize( 0, 80 );
55  m_Aliases->SetColSize( 1, 300 );
56  m_Aliases->SetColSize( 2, 120 );
57 
58  m_EnvVars->SetColMinimalWidth( 0, 80 );
59  m_EnvVars->SetColMinimalWidth( 1, 300 );
60  m_EnvVars->SetColMinimalAcceptableWidth( 80 );
61  m_EnvVars->SetColSize( 0, 80 );
62  m_EnvVars->SetColSize( 1, 300 );
63 
64  if( m_resolver )
65  {
66  updateEnvVars();
67 
68  // prohibit these characters in the alias names: []{}()%~<>"='`;:.,&?/\|$
69  m_aliasValidator.SetStyle( wxFILTER_EXCLUDE_CHAR_LIST );
70  m_aliasValidator.SetCharExcludes( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) );
71 
72  const std::list< S3D_ALIAS >* rpaths = m_resolver->GetPaths();
73  std::list< S3D_ALIAS >::const_iterator rI = rpaths->begin();
74  std::list< S3D_ALIAS >::const_iterator rE = rpaths->end();
75  size_t listsize = rpaths->size();
76  size_t listidx = 0;
77 
78  while( rI != rE && ( (*rI).m_alias.StartsWith( "${" )
79  || (*rI).m_alias.StartsWith( "$(" ) ) )
80  {
81  ++listidx;
82  ++rI;
83  }
84 
85  if( listidx < listsize )
86  m_curdir = (*rI).m_pathexp;
87  else
88  return;
89 
90  listsize = listsize - listidx - m_Aliases->GetNumberRows();
91 
92  // note: if the list allocation fails we have bigger problems
93  // and there is no point in trying to notify the user here
94  if( listsize > 0 && !m_Aliases->InsertRows( 0, listsize ) )
95  return;
96 
97  int nitems = 0;
98  wxGridCellTextEditor* pEdAlias;
99 
100  while( rI != rE )
101  {
102  m_Aliases->SetCellValue( nitems, 0, rI->m_alias );
103 
104  if( 0 == nitems )
105  {
106  m_Aliases->SetCellEditor( nitems, 0, new wxGridCellTextEditor );
107  pEdAlias = (wxGridCellTextEditor*) m_Aliases->GetCellEditor( nitems, 0 );
108  pEdAlias->SetValidator( m_aliasValidator );
109  pEdAlias->DecRef();
110  }
111  else
112  {
113  pEdAlias->IncRef();
114  m_Aliases->SetCellEditor( nitems, 0, pEdAlias );
115  }
116 
117  m_Aliases->SetCellValue( nitems, 1, rI->m_pathvar );
118  m_Aliases->SetCellValue( nitems++, 2, rI->m_description );
119 
120  // TODO: implement a wxGridCellEditor which invokes a wxDirDialog
121 
122  ++rI;
123  }
124 
125  m_Aliases->AutoSize();
126  }
127 }
128 
129 
131 {
132  if( NULL == m_resolver )
133  {
134  wxMessageBox( _( "[BUG] No valid resolver; data will not be updated" ),
135  _( "Update 3D search path list" ) );
136 
137  return false;
138  }
139 
140  std::vector<S3D_ALIAS> alist;
141  S3D_ALIAS alias;
142 
143  int ni = m_Aliases->GetNumberRows();
144 
145  if( ni <= 0 )
146  {
147  // note: UI usability: we should ask a user if they're sure they
148  // want to clear the entire path list
149  m_resolver->UpdatePathList( alist );
150  return true;
151  }
152 
153  for( int i = 0; i < ni; ++i )
154  {
155  alias.m_alias = m_Aliases->GetCellValue( i, 0 );
156  alias.m_pathvar = m_Aliases->GetCellValue( i, 1 );
157  alias.m_description = m_Aliases->GetCellValue( i, 2 );
158 
159  if( !alias.m_alias.empty() && !alias.m_pathvar.empty() )
160  alist.push_back( alias );
161 
162  }
163 
164  return m_resolver->UpdatePathList( alist );
165 }
166 
167 
168 void DLG_3D_PATH_CONFIG::OnAddAlias( wxCommandEvent& event )
169 {
170  int ni = m_Aliases->GetNumberRows();
171 
172  if( m_Aliases->InsertRows( ni, 1 ) )
173  {
174  wxGridCellTextEditor* pEdAlias;
175  pEdAlias = (wxGridCellTextEditor*) m_Aliases->GetCellEditor( 0, 0 );
176  m_Aliases->SetCellEditor( ni, 0, pEdAlias );
177  m_Aliases->SelectRow( ni, false );
178  m_Aliases->AutoSize();
179  Fit();
180 
181  // TODO: set the editors on any newly created rows
182  }
183 
184  event.Skip();
185 }
186 
187 
188 void DLG_3D_PATH_CONFIG::OnDelAlias( wxCommandEvent& event )
189 {
190  wxArrayInt sel = m_Aliases->GetSelectedRows();
191 
192  if( sel.empty() )
193  {
194  wxMessageBox( _( "No entry selected" ), _( "Delete alias entry" ) );
195  return;
196  }
197 
198  if( sel.size() > 1 )
199  {
200  wxMessageBox( _( "Multiple entries selected; please\nselect only one entry" ),
201  _( "Delete alias entry" ) );
202  return;
203  }
204 
205  if( m_Aliases->GetNumberRows() > 1 )
206  {
207  int ni = sel.front();
208  m_Aliases->DeleteRows( ni, 1 );
209 
210  if( ni >= m_Aliases->GetNumberRows() )
211  ni = m_Aliases->GetNumberRows() - 1;
212 
213  m_Aliases->SelectRow( ni, false );
214  m_Aliases->AutoSize();
215  Fit();
216  }
217  else
218  {
219  m_Aliases->SetCellValue( 0, 0, wxEmptyString );
220  m_Aliases->SetCellValue( 0, 1, wxEmptyString );
221  m_Aliases->SetCellValue( 0, 2, wxEmptyString );
222  }
223 
224  event.Skip();
225 }
226 
227 
228 void DLG_3D_PATH_CONFIG::OnAliasMoveUp( wxCommandEvent& event )
229 {
230  wxArrayInt sel = m_Aliases->GetSelectedRows();
231 
232  if( sel.empty() )
233  {
234  wxMessageBox( _( "No entry selected" ), _( "Move alias up" ) );
235  return;
236  }
237 
238  if( sel.size() > 1 )
239  {
240  wxMessageBox( _( "Multiple entries selected; please\nselect only one entry" ),
241  _( "Move alias up" ) );
242  return;
243  }
244 
245  int ci = sel.front();
246 
247  if( ci > 0 )
248  {
249  S3D_ALIAS al0;
250  al0.m_alias = m_Aliases->GetCellValue( ci, 0 );
251  al0.m_pathvar = m_Aliases->GetCellValue( ci, 1 );
252  al0.m_description = m_Aliases->GetCellValue( ci, 2 );
253 
254  int ni = ci - 1;
255  m_Aliases->SetCellValue( ci, 0, m_Aliases->GetCellValue( ni, 0 ) );
256  m_Aliases->SetCellValue( ci, 1, m_Aliases->GetCellValue( ni, 1 ) );
257  m_Aliases->SetCellValue( ci, 2, m_Aliases->GetCellValue( ni, 2 ) );
258 
259  m_Aliases->SetCellValue( ni, 0, al0.m_alias );
260  m_Aliases->SetCellValue( ni, 1, al0.m_pathvar );
261  m_Aliases->SetCellValue( ni, 2, al0.m_description );
262  m_Aliases->SelectRow( ni, false );
263  }
264 
265  event.Skip();
266 }
267 
268 
269 void DLG_3D_PATH_CONFIG::OnAliasMoveDown( wxCommandEvent& event )
270 {
271  wxArrayInt sel = m_Aliases->GetSelectedRows();
272 
273  if( sel.empty() )
274  {
275  wxMessageBox( _( "No entry selected" ), _( "Move alias down" ) );
276  return;
277  }
278 
279  if( sel.size() > 1 )
280  {
281  wxMessageBox( _( "Multiple entries selected; please\nselect only one entry" ),
282  _( "Move alias down" ) );
283  return;
284  }
285 
286  int ni = m_Aliases->GetNumberRows() - 1;
287  int ci = sel.front();
288 
289  if( ci < ni )
290  {
291  S3D_ALIAS al0;
292  al0.m_alias = m_Aliases->GetCellValue( ci, 0 );
293  al0.m_pathvar = m_Aliases->GetCellValue( ci, 1 );
294  al0.m_description = m_Aliases->GetCellValue( ci, 2 );
295 
296  ni = ci + 1;
297  m_Aliases->SetCellValue( ci, 0, m_Aliases->GetCellValue( ni, 0 ) );
298  m_Aliases->SetCellValue( ci, 1, m_Aliases->GetCellValue( ni, 1 ) );
299  m_Aliases->SetCellValue( ci, 2, m_Aliases->GetCellValue( ni, 2 ) );
300 
301  m_Aliases->SetCellValue( ni, 0, al0.m_alias );
302  m_Aliases->SetCellValue( ni, 1, al0.m_pathvar );
303  m_Aliases->SetCellValue( ni, 2, al0.m_description );
304  m_Aliases->SelectRow( ni, false );
305  }
306 
307  event.Skip();
308 }
309 
310 
311 void DLG_3D_PATH_CONFIG::OnConfigEnvVar( wxCommandEvent& event )
312 {
313  Pgm().ConfigurePaths( this );
314  updateEnvVars();
315  event.Skip();
316 }
317 
318 
320 {
321  if( !m_resolver )
322  return;
323 
324  std::list< wxString > epaths;
325 
326  m_resolver->GetKicadPaths( epaths );
327  size_t nitems = epaths.size();
328  size_t nrows = m_EnvVars->GetNumberRows();
329  bool resize = nrows != nitems; // true after adding/removing env vars
330 
331  if( nrows > nitems )
332  {
333  size_t ni = nrows - nitems;
334  m_EnvVars->DeleteRows( 0, ni );
335  }
336  else if( nrows < nitems )
337  {
338  size_t ni = nitems - nrows;
339  m_EnvVars->InsertRows( 0, ni );
340  }
341 
342  int j = 0;
343 
344  for( auto i : epaths )
345  {
346  wxString val = ExpandEnvVarSubstitutions( i );
347  m_EnvVars->SetCellValue( j, 0, i );
348  m_EnvVars->SetCellValue( j, 1, val );
349  m_EnvVars->SetReadOnly( j, 0, true );
350  m_EnvVars->SetReadOnly( j, 1, true );
351  wxGridCellAttr* ap = m_EnvVars->GetOrCreateCellAttr( j, 0 );
352  ap->SetReadOnly( true );
353  ap->SetBackgroundColour( *wxLIGHT_GREY );
354  m_EnvVars->SetRowAttr( j, ap );
355  ++j;
356  }
357 
358  m_EnvVars->AutoSize();
359 
360  // Resizing the full dialog is sometimes needed for a clean display
361  // i.e. when adding/removing Kicad environment variables
362  if( resize )
363  GetSizer()->SetSizeHints( this );
364 
365  return;
366 }
367 
368 
369 void DLG_3D_PATH_CONFIG::OnHelp( wxCommandEvent& event )
370 {
371  wxString msg = _( "Enter the name and path for each 3D alias variable.<br>KiCad "
372  "environment variables and their values are shown for "
373  "reference only and cannot be edited." );
374  msg << "<br><br><b>";
375  msg << _( "Alias names may not contain any of the characters " );
376  msg << "{}[]()%~<>\"='`;:.,&?/\\|$";
377  msg << "</b>";
378 
379  HTML_MESSAGE_BOX dlg( GetParent(), _( "Environment Variable Help" ) );
380  dlg.AddHTML_Text( msg );
381  dlg.ShowModal();
382 
383  event.Skip();
384 }
wxString m_pathvar
bool TransferDataFromWindow() override
DLG_3D_PATH_CONFIG(wxWindow *aParent, S3D_FILENAME_RESOLVER *aResolver)
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:65
void OnAliasMoveDown(wxCommandEvent &event) override
void OnHelp(wxCommandEvent &event) override
VTBL_ENTRY void ConfigurePaths(wxWindow *aParent=NULL)
Function ConfigurePaths.
Definition: pgm_base.cpp:903
wxTextValidator m_aliasValidator
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Function ExpandEnvVarSubstitutions replaces any environment variable references with their values...
Definition: common.cpp:254
wxString m_description
Subclass of DIALOG_DISPLAY_HTML_TEXT_BASE, which is generated by wxFormBuilder.
bool UpdatePathList(std::vector< S3D_ALIAS > &aPathList)
Function UpdatePathList clears the current path list and substitutes the given path list...
Class HTML_MESSAGE_BOX.
const std::list< S3D_ALIAS > * GetPaths(void)
Function GetPaths returns a pointer to the internal path list; the items in:load. ...
S3D_FILENAME_RESOLVER * m_resolver
see class PGM_BASE
void OnDelAlias(wxCommandEvent &event) override
provides an extensible class to resolve 3D model paths.
void AddHTML_Text(const wxString &message)
Function AddHTML_Text adds html text (without any change) to message list.
Class DLG_3D_PATH_CONFIG_BASE.
void OnAddAlias(wxCommandEvent &event) override
void OnAliasMoveUp(wxCommandEvent &event) override
void OnConfigEnvVar(wxCommandEvent &event) override
bool GetKicadPaths(std::list< wxString > &paths)
Function GetKicadPaths returns a list of path environment variables local to Kicad; this list always ...