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( "${" ) || (*rI).m_alias.StartsWith( "$(" ) ) )
79  {
80  ++listidx;
81  ++rI;
82  }
83 
84  if( listidx < listsize )
85  m_curdir = (*rI).m_pathexp;
86  else
87  return;
88 
89  listsize = listsize - listidx - m_Aliases->GetNumberRows();
90 
91  // note: if the list allocation fails we have bigger problems
92  // and there is no point in trying to notify the user here
93  if( listsize > 0 && !m_Aliases->InsertRows( 0, listsize ) )
94  return;
95 
96  int nitems = 0;
97  wxGridCellTextEditor* pEdAlias;
98 
99  while( rI != rE )
100  {
101  m_Aliases->SetCellValue( nitems, 0, rI->m_alias );
102 
103  if( 0 == nitems )
104  {
105  m_Aliases->SetCellEditor( nitems, 0, new wxGridCellTextEditor );
106  pEdAlias = (wxGridCellTextEditor*) m_Aliases->GetCellEditor( nitems, 0 );
107  pEdAlias->SetValidator( m_aliasValidator );
108  pEdAlias->DecRef();
109  }
110  else
111  {
112  pEdAlias->IncRef();
113  m_Aliases->SetCellEditor( nitems, 0, pEdAlias );
114  }
115 
116  m_Aliases->SetCellValue( nitems, 1, rI->m_pathvar );
117  m_Aliases->SetCellValue( nitems++, 2, rI->m_description );
118 
119  // TODO: implement a wxGridCellEditor which invokes a wxDirDialog
120 
121  ++rI;
122  }
123 
124  m_Aliases->AutoSize();
125  }
126 }
127 
128 
130 {
131  if( NULL == m_resolver )
132  {
133  wxMessageBox( _( "[BUG] No valid resolver; data will not be updated" ),
134  _( "Update 3D search path list" ) );
135 
136  return false;
137  }
138 
139  std::vector<S3D_ALIAS> alist;
140  S3D_ALIAS alias;
141 
142  int ni = m_Aliases->GetNumberRows();
143 
144  if( ni <= 0 )
145  {
146  // note: UI usability: we should ask a user if they're sure they
147  // want to clear the entire path list
148  m_resolver->UpdatePathList( alist );
149  return true;
150  }
151 
152  for( int i = 0; i < ni; ++i )
153  {
154  alias.m_alias = m_Aliases->GetCellValue( i, 0 );
155  alias.m_pathvar = m_Aliases->GetCellValue( i, 1 );
156  alias.m_description = m_Aliases->GetCellValue( i, 2 );
157 
158  if( !alias.m_alias.empty() && !alias.m_pathvar.empty() )
159  alist.push_back( alias );
160 
161  }
162 
163  return m_resolver->UpdatePathList( alist );
164 }
165 
166 
167 void DLG_3D_PATH_CONFIG::OnAddAlias( wxCommandEvent& event )
168 {
169  int ni = m_Aliases->GetNumberRows();
170 
171  if( m_Aliases->InsertRows( ni, 1 ) )
172  {
173  wxGridCellTextEditor* pEdAlias;
174  pEdAlias = (wxGridCellTextEditor*) m_Aliases->GetCellEditor( 0, 0 );
175  m_Aliases->SetCellEditor( ni, 0, pEdAlias );
176  m_Aliases->SelectRow( ni, false );
177  m_Aliases->AutoSize();
178  Fit();
179 
180  // TODO: set the editors on any newly created rows
181  }
182 
183  event.Skip();
184 }
185 
186 
187 void DLG_3D_PATH_CONFIG::OnDelAlias( wxCommandEvent& event )
188 {
189  wxArrayInt sel = m_Aliases->GetSelectedRows();
190 
191  if( sel.empty() )
192  {
193  wxMessageBox( _( "No entry selected" ), _( "Delete alias entry" ) );
194  return;
195  }
196 
197  if( sel.size() > 1 )
198  {
199  wxMessageBox( _( "Multiple entries selected; please\nselect only one entry" ),
200  _( "Delete alias entry" ) );
201  return;
202  }
203 
204  if( m_Aliases->GetNumberRows() > 1 )
205  {
206  int ni = sel.front();
207  m_Aliases->DeleteRows( ni, 1 );
208 
209  if( ni >= m_Aliases->GetNumberRows() )
210  ni = m_Aliases->GetNumberRows() - 1;
211 
212  m_Aliases->SelectRow( ni, false );
213  m_Aliases->AutoSize();
214  Fit();
215  }
216  else
217  {
218  m_Aliases->SetCellValue( 0, 0, wxEmptyString );
219  m_Aliases->SetCellValue( 0, 1, wxEmptyString );
220  m_Aliases->SetCellValue( 0, 2, wxEmptyString );
221  }
222 
223  event.Skip();
224 }
225 
226 
227 void DLG_3D_PATH_CONFIG::OnAliasMoveUp( wxCommandEvent& event )
228 {
229  wxArrayInt sel = m_Aliases->GetSelectedRows();
230 
231  if( sel.empty() )
232  {
233  wxMessageBox( _( "No entry selected" ), _( "Move alias up" ) );
234  return;
235  }
236 
237  if( sel.size() > 1 )
238  {
239  wxMessageBox( _( "Multiple entries selected; please\nselect only one entry" ),
240  _( "Move alias up" ) );
241  return;
242  }
243 
244  int ci = sel.front();
245 
246  if( ci > 0 )
247  {
248  S3D_ALIAS al0;
249  al0.m_alias = m_Aliases->GetCellValue( ci, 0 );
250  al0.m_pathvar = m_Aliases->GetCellValue( ci, 1 );
251  al0.m_description = m_Aliases->GetCellValue( ci, 2 );
252 
253  int ni = ci - 1;
254  m_Aliases->SetCellValue( ci, 0, m_Aliases->GetCellValue( ni, 0 ) );
255  m_Aliases->SetCellValue( ci, 1, m_Aliases->GetCellValue( ni, 1 ) );
256  m_Aliases->SetCellValue( ci, 2, m_Aliases->GetCellValue( ni, 2 ) );
257 
258  m_Aliases->SetCellValue( ni, 0, al0.m_alias );
259  m_Aliases->SetCellValue( ni, 1, al0.m_pathvar );
260  m_Aliases->SetCellValue( ni, 2, al0.m_description );
261  m_Aliases->SelectRow( ni, false );
262  }
263 
264  event.Skip();
265 }
266 
267 
268 void DLG_3D_PATH_CONFIG::OnAliasMoveDown( wxCommandEvent& event )
269 {
270  wxArrayInt sel = m_Aliases->GetSelectedRows();
271 
272  if( sel.empty() )
273  {
274  wxMessageBox( _( "No entry selected" ), _( "Move alias down" ) );
275  return;
276  }
277 
278  if( sel.size() > 1 )
279  {
280  wxMessageBox( _( "Multiple entries selected; please\nselect only one entry" ),
281  _( "Move alias down" ) );
282  return;
283  }
284 
285  int ni = m_Aliases->GetNumberRows() - 1;
286  int ci = sel.front();
287 
288  if( ci < ni )
289  {
290  S3D_ALIAS al0;
291  al0.m_alias = m_Aliases->GetCellValue( ci, 0 );
292  al0.m_pathvar = m_Aliases->GetCellValue( ci, 1 );
293  al0.m_description = m_Aliases->GetCellValue( ci, 2 );
294 
295  ni = ci + 1;
296  m_Aliases->SetCellValue( ci, 0, m_Aliases->GetCellValue( ni, 0 ) );
297  m_Aliases->SetCellValue( ci, 1, m_Aliases->GetCellValue( ni, 1 ) );
298  m_Aliases->SetCellValue( ci, 2, m_Aliases->GetCellValue( ni, 2 ) );
299 
300  m_Aliases->SetCellValue( ni, 0, al0.m_alias );
301  m_Aliases->SetCellValue( ni, 1, al0.m_pathvar );
302  m_Aliases->SetCellValue( ni, 2, al0.m_description );
303  m_Aliases->SelectRow( ni, false );
304  }
305 
306  event.Skip();
307 }
308 
309 
310 void DLG_3D_PATH_CONFIG::OnConfigEnvVar( wxCommandEvent& event )
311 {
312  Pgm().ConfigurePaths( this );
313  updateEnvVars();
314  event.Skip();
315 }
316 
317 
319 {
320  if( !m_resolver )
321  return;
322 
323  std::list< wxString > epaths;
324 
325  m_resolver->GetKicadPaths( epaths );
326  size_t nitems = epaths.size();
327  size_t nrows = m_EnvVars->GetNumberRows();
328  bool resize = nrows != nitems; // true after adding/removing env vars
329 
330  if( nrows > nitems )
331  {
332  size_t ni = nrows - nitems;
333  m_EnvVars->DeleteRows( 0, ni );
334  }
335  else if( nrows < nitems )
336  {
337  size_t ni = nitems - nrows;
338  m_EnvVars->InsertRows( 0, ni );
339  }
340 
341  int j = 0;
342 
343  for( const auto& i : epaths )
344  {
345  wxString val = ExpandEnvVarSubstitutions( i );
346  m_EnvVars->SetCellValue( j, 0, i );
347  m_EnvVars->SetCellValue( j, 1, val );
348  m_EnvVars->SetReadOnly( j, 0, true );
349  m_EnvVars->SetReadOnly( j, 1, true );
350  wxGridCellAttr* ap = m_EnvVars->GetOrCreateCellAttr( j, 0 );
351  ap->SetReadOnly( true );
352  ap->SetBackgroundColour( *wxLIGHT_GREY );
353  m_EnvVars->SetRowAttr( j, ap );
354  ++j;
355  }
356 
357  m_EnvVars->AutoSize();
358 
359  // Resizing the full dialog is sometimes needed for a clean display
360  // i.e. when adding/removing Kicad environment variables
361  if( resize )
362  GetSizer()->SetSizeHints( this );
363 
364  return;
365 }
366 
367 
368 void DLG_3D_PATH_CONFIG::OnHelp( wxCommandEvent& event )
369 {
370  wxString msg = _( "Enter the name and path for each 3D alias variable.<br>KiCad "
371  "environment variables and their values are shown for "
372  "reference only and cannot be edited." );
373  msg << "<br><br><b>";
374  msg << _( "Alias names may not contain any of the characters " );
375  msg << "{}[]()%~<>\"='`;:.,&?/\\|$";
376  msg << "</b>";
377 
378  HTML_MESSAGE_BOX dlg( GetParent(), _( "Environment Variable Help" ) );
379  dlg.AddHTML_Text( msg );
380  dlg.ShowModal();
381 
382  event.Skip();
383 }
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:66
void OnAliasMoveDown(wxCommandEvent &event) override
void OnHelp(wxCommandEvent &event) override
VTBL_ENTRY void ConfigurePaths(wxWindow *aParent=NULL)
Function ConfigurePaths.
Definition: pgm_base.cpp:970
wxTextValidator m_aliasValidator
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:255
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.
size_t i
Definition: json11.cpp:597
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 ...