KiCad PCB EDA Suite
dialog_eeschema_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) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2006-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 <fctsys.h>
30 #include <pgm_base.h>
31 #include <kiway.h>
32 #include <confirm.h>
33 #include <gestfich.h>
34 #include <schframe.h>
35 #include <invoke_sch_dialog.h>
36 #include <kiface_i.h>
37 
38 #include <general.h>
39 #include <netlist.h>
40 #include <libeditframe.h>
41 #include <viewlib_frame.h>
43 #include <wx/tokenzr.h>
45 #include <eeschema_config.h>
46 
47 
48 class SCH_EDIT_FRAME;
49 class EDA_DRAW_FRAME;
50 
51 
53 {
54 public:
55  DIALOG_EESCHEMA_CONFIG( wxWindow* aParent,
56  wxString* aCallersProjectSpecificLibPaths, wxArrayString* aCallersLibNames );
57 
58 private:
59  wxConfigBase* m_config;
61  wxArrayString* m_callers_lib_names;
62 
65 
66  //------ event handlers, overiding the fbp handlers --------------
67 
68  void OnCloseWindow( wxCloseEvent& event ) override;
69 
70  /* Remove a library to the library list.
71  * The real list (m_Parent->m_ComponentLibFiles) is not changed, so the change can be canceled
72  */
73  void OnRemoveLibClick( wxCommandEvent& event ) override;
74 
75  /* Insert or add a library to the library list:
76  * The new library is put in list before (insert button) the selection,
77  * or added (add button) to end of list
78  * The real list (m_Parent->m_ComponentLibFiles) is not changed, so the change
79  * can be canceled
80  */
81  void OnAddOrInsertLibClick( wxCommandEvent& event ) override;
82 
83  void OnAddOrInsertPath( wxCommandEvent& event ) override;
84  void OnOkClick( wxCommandEvent& event ) override;
85  void OnCancelClick( wxCommandEvent& event ) override;
86  void OnRemoveUserPath( wxCommandEvent& event ) override;
87  void OnButtonUpClick( wxCommandEvent& event ) override;
88  void OnButtonDownClick( wxCommandEvent& event ) override;
89 };
90 
91 
93  wxString* aCallersProjectSpecificLibPaths, wxArrayString* aCallersLibNames ) :
94  DIALOG_EESCHEMA_CONFIG_FBP( aParent ),
95  m_callers_project_specific_lib_paths( aCallersProjectSpecificLibPaths ),
96  m_callers_lib_names( aCallersLibNames ),
97  m_lib_list_changed( false ),
98  m_lib_path_changed( false )
99 {
100  m_ListLibr->InsertItems( *aCallersLibNames, 0 );
101 
102  // Load user libs paths:
103  wxArrayString paths;
104 
105  SEARCH_STACK::Split( &paths, *aCallersProjectSpecificLibPaths );
106 
107  for( unsigned i=0; i<paths.GetCount(); ++i )
108  {
109  wxString path = paths[i];
110 
111  if( wxFileName::DirExists( Prj().AbsolutePath( path ) ) )
112  m_listUserPaths->Append( path );
113  }
114 
115  // Display actual library paths which come in part from KIFACE::KifaceSearch()
116  // along with aCallersProjectSpecificLibPaths at the front.
117  SEARCH_STACK* libpaths = Prj().SchSearchS();
118 
119  DBG( libpaths->Show( __func__ ); )
120 
121  for( unsigned ii = 0; ii < libpaths->GetCount(); ii++ )
122  {
123  m_DefaultLibraryPathslistBox->Append( (*libpaths)[ii] );
124  }
125 
126  // select the first path after the current project's path
127  if( libpaths->GetCount() > 1 )
128  m_DefaultLibraryPathslistBox->Select( 1 );
129 
130  // Load setting for cache rescue
132  bool rescueNeverShow = false;
133  m_config->Read( RescueNeverShowEntry, &rescueNeverShow, false );
134  m_cbRescue->SetValue( !rescueNeverShow );
135 
136  wxString msg = wxString::Format( _(
137  "Project '%s'" ),
138  GetChars( Prj().GetProjectFullName() )
139  );
140 
141  SetTitle( msg );
142 
143  if( GetSizer() )
144  GetSizer()->SetSizeHints( this );
145 
146  m_sdbSizer1OK->SetDefault();
147 }
148 
149 
150 void DIALOG_EESCHEMA_CONFIG::OnButtonUpClick( wxCommandEvent& event )
151 {
152  wxArrayInt selections;
153 
154  m_ListLibr->GetSelections( selections );
155 
156  if ( selections.GetCount() <= 0 ) // No selection.
157  return;
158 
159  if( selections[0] == 0 ) // The first lib is selected. cannot move up it
160  return;
161 
162  wxArrayString libnames = m_ListLibr->GetStrings();
163 
164  for( size_t ii = 0; ii < selections.GetCount(); ii++ )
165  {
166  int jj = selections[ii];
167  std::swap( libnames[jj], libnames[jj-1]);
168  }
169 
170  m_ListLibr->Set(libnames);
171 
172  // Reselect previously selected names
173  for( size_t ii = 0; ii < selections.GetCount(); ii++ )
174  {
175  int jj = selections[ii];
176  m_ListLibr->SetSelection(jj-1);
177  }
178 
179  m_lib_list_changed = true;
180 }
181 
182 
183 void DIALOG_EESCHEMA_CONFIG::OnButtonDownClick( wxCommandEvent& event )
184 {
185  wxArrayInt selections;
186 
187  m_ListLibr->GetSelections(selections);
188 
189  if ( selections.GetCount() <= 0 ) // No selection.
190  return;
191 
192  // The last lib is selected. cannot move down it
193  if( selections.Last() == (int)(m_ListLibr->GetCount()-1) )
194  return;
195 
196  wxArrayString libnames = m_ListLibr->GetStrings();
197 
198  for( int ii = selections.GetCount()-1; ii >= 0; ii-- )
199  {
200  int jj = selections[ii];
201  std::swap( libnames[jj], libnames[jj+1]);
202  }
203 
204  m_ListLibr->Set( libnames );
205 
206  // Reselect previously selected names
207  for( size_t ii = 0; ii < selections.GetCount(); ii++ )
208  {
209  int jj = selections[ii];
210  m_ListLibr->SetSelection(jj+1);
211  }
212 
213  m_lib_list_changed = true;
214 }
215 
216 
217 void DIALOG_EESCHEMA_CONFIG::OnCancelClick( wxCommandEvent& event )
218 {
219  EndModal( wxID_CANCEL );
220 }
221 
222 
223 void DIALOG_EESCHEMA_CONFIG::OnOkClick( wxCommandEvent& event )
224 {
225  // Give caller the changed paths
226  if( m_lib_path_changed )
227  {
228  wxString paths;
229 
230  for( unsigned ii = 0; ii < m_listUserPaths->GetCount(); ii++ )
231  {
232  if( ii > 0 )
233  paths += wxT( ';' );
234 
235  paths += m_listUserPaths->GetString( ii );
236  }
237 
239  }
240 
241  // Update caller's lib_names if changed.
242  if( m_lib_list_changed )
243  {
244  wxArrayString list;
245 
246  for( unsigned ii = 0; ii < m_ListLibr->GetCount(); ii ++ )
247  list.Add( m_ListLibr->GetString( ii ) );
248 
249  // Recreate lib list
250  *m_callers_lib_names = list;
251  }
252 
253  m_config->Write( RescueNeverShowEntry, ! m_cbRescue->GetValue() );
254 
255  EndModal( wxID_OK );
256 }
257 
258 
259 void DIALOG_EESCHEMA_CONFIG::OnCloseWindow( wxCloseEvent& event )
260 {
261  EndModal( wxID_CANCEL );
262 }
263 
264 
265 void DIALOG_EESCHEMA_CONFIG::OnRemoveLibClick( wxCommandEvent& event )
266 {
267  wxArrayInt selections;
268 
269  m_ListLibr->GetSelections( selections );
270 
271  for( int ii = selections.GetCount()-1; ii >= 0; ii-- )
272  {
273  m_ListLibr->Delete( selections[ii] );
274  m_lib_list_changed = true;
275  }
276 
277  // Select next item after deleted in m_ListLibr
278  if( m_ListLibr->GetCount() > 0 && selections.GetCount() > 0 )
279  {
280  int pos = selections[selections.GetCount()-1];
281 
282  if( pos >= (int)m_ListLibr->GetCount() )
283  pos = m_ListLibr->GetCount() - 1;
284 
285  m_ListLibr->SetSelection( pos );
286  }
287 }
288 
289 
291 {
292  int ii;
293  wxString libfilename;
294  wxArrayInt selections;
295 
296  PROJECT& prj = Prj();
297 
298  m_ListLibr->GetSelections( selections );
299 
300  ii = selections.GetCount();
301 
302  if( ii > 0 )
303  ii = selections[0];
304  else
305  ii = 0;
306 
307  wxString selection = m_DefaultLibraryPathslistBox->GetStringSelection();
308  wxString libpath = Prj().AbsolutePath( selection );
309 
310  if( !libpath )
311  {
312  libpath = prj.GetRString( PROJECT::SCH_LIB_PATH );
313  }
314 
315  wxFileDialog filesDialog( this, _( "Library files:" ), libpath,
316  wxEmptyString, SchematicLibraryFileWildcard,
317  wxFD_DEFAULT_STYLE | wxFD_MULTIPLE );
318 
319  if( filesDialog.ShowModal() != wxID_OK )
320  return;
321 
322  wxArrayString filenames;
323 
324  filesDialog.GetPaths( filenames );
325 
326  wxFileName fn;
327 
328  // Build libs paths, to find later a relative path:
329  wxArrayString paths;
330 
331  for( unsigned ll=0; ll < m_DefaultLibraryPathslistBox->GetCount(); ++ll )
332  paths.Add( m_DefaultLibraryPathslistBox->GetString( ll ) );
333 
334  for( unsigned ll=0; ll < m_listUserPaths->GetCount(); ++ll )
335  paths.Add( m_listUserPaths->GetString( ll ) );
336 
337  for( unsigned jj = 0; jj < filenames.GetCount(); jj++ )
338  {
339  fn = filenames[jj];
340 
341  if( jj == 0 )
342  prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() );
343 
344  // Extension is not stored, so remove extension:
345  fn.SetExt( wxEmptyString );
346 
347  // Try to use relative path:
348  for( unsigned ll = 0; ll < paths.GetCount(); ll++ )
349  {
350  wxFileName relfn = fn;
351  relfn.MakeRelativeTo( paths[ll] );
352 
353  if( relfn.GetPath()[0] != '.' )
354  {
355  fn = relfn;
356  break;
357  }
358  }
359 
360  libfilename = fn.GetFullPath();
361 
362  // Add or insert new library name, if not already in list
363  if( m_ListLibr->FindString( libfilename, fn.IsCaseSensitive() ) == wxNOT_FOUND )
364  {
365  m_lib_list_changed = true;
366 
367  if( event.GetId() == ID_ADD_LIB )
368  m_ListLibr->Append( libfilename );
369  else
370  m_ListLibr->Insert( libfilename, ii++ );
371  }
372  else
373  {
374  wxString msg = wxString::Format( _(
375  "'%s' : library already in use" ),
376  GetChars( libfilename )
377  );
378  DisplayError( this, msg );
379  }
380  }
381 }
382 
383 
384 void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertPath( wxCommandEvent& event )
385 {
386  PROJECT& prj = Prj();
387  wxString abs_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
388  wxString path;
389 
390  bool select = EDA_PATH_SELECTOR( _( "Default Path for Libraries" ),
391  abs_path, wxDD_DEFAULT_STYLE,
392  this, wxDefaultPosition );
393 
394  if( !select )
395  return;
396 
397  if( !wxFileName::DirExists( abs_path ) ) // Should not occur
398  return;
399 
400  // Add or insert path if not already in list
401  if( m_listUserPaths->FindString( abs_path ) == wxNOT_FOUND )
402  {
403  int ipos = m_listUserPaths->GetCount();
404 
405  if( event.GetId() == wxID_INSERT_PATH )
406  {
407  if( ipos )
408  ipos--;
409 
410  int jj = m_listUserPaths->GetSelection();
411 
412  if( jj >= 0 )
413  ipos = jj;
414  }
415 
416  // Ask the user if this is a relative path
417  int diag = wxMessageBox( _( "Use a relative path?" ), _( "Path type" ),
418  wxYES_NO | wxICON_QUESTION, this );
419 
420  if( diag == wxYES )
421  {
422  // Make it relative
423  wxFileName fn = abs_path;
424  fn.MakeRelativeTo( wxPathOnly( Prj().GetProjectFullName() ) );
425  path = fn.GetPathWithSep() + fn.GetFullName();
426  }
427  else
428  path = abs_path;
429 
430  m_listUserPaths->Insert( path, ipos );
431  m_lib_path_changed = true;
432 
433  m_DefaultLibraryPathslistBox->InsertItems( 1, &path, ipos+1 );
434  }
435  else
436  {
437  DisplayError( this, _("Path already in use") );
438  }
439 
440  prj.SetRString( PROJECT::SCH_LIB_PATH, abs_path );
441 }
442 
443 
444 static void remove_from_listbox( wxListBox* aListBox, const wxString& aText )
445 {
446  wxArrayString a;
447 
448  for( int i=0, cnt = aListBox->GetCount(); i<cnt; ++i )
449  {
450  wxString item = aListBox->GetString( i );
451 
452  if( item != aText )
453  a.Add( item );
454  }
455 
456  aListBox->Clear();
457 
458  aListBox->InsertItems( a, 0 );
459 }
460 
461 
462 void DIALOG_EESCHEMA_CONFIG::OnRemoveUserPath( wxCommandEvent& event )
463 {
464  int ii = m_listUserPaths->GetSelection();
465 
466  if( ii < 0 )
467  ii = m_listUserPaths->GetCount()-1;
468 
469  if( ii >= 0 )
470  {
471  wxString sel = m_listUserPaths->GetStringSelection();
472 
474 
475  m_listUserPaths->Delete( ii );
476  m_lib_path_changed = true;
477  }
478 }
479 
480 
481 bool InvokeEeschemaConfig( wxWindow* aParent,
482  wxString* aCallersProjectSpecificLibPaths, wxArrayString* aCallersLibNames )
483 {
484  DIALOG_EESCHEMA_CONFIG dlg( aParent,
485  aCallersProjectSpecificLibPaths, aCallersLibNames );
486 
487  int ret = dlg.ShowModal();
488 
489  return wxID_OK == ret;
490 }
const wxString SchematicLibraryFileWildcard
Class DIALOG_EESCHEMA_CONFIG_FBP.
Class PROJECT holds project specific data.
Definition: project.h:51
This file is part of the common library TODO brief description.
This file is part of the common library.
void OnCancelClick(wxCommandEvent &event) override
DIALOG_EESCHEMA_CONFIG(wxWindow *aParent, wxString *aCallersProjectSpecificLibPaths, wxArrayString *aCallersLibNames)
void OnRemoveUserPath(wxCommandEvent &event) override
void OnAddOrInsertLibClick(wxCommandEvent &event) override
const wxChar RescueNeverShowEntry[]
Schematic editor (Eeschema) main window.
Definition: schframe.h:117
Class SEARCH_STACK looks for files in a number of places.
Definition: search_stack.h:41
Class EDA_DRAW_FRAME is the base class for create windows for drawing purpose.
Definition: draw_frame.h:53
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
void OnButtonUpClick(wxCommandEvent &event) override
static int Split(wxArrayString *aResult, const wxString aPathString)
Function Split separates aPathString into individual paths.
VTBL_ENTRY const wxString AbsolutePath(const wxString &aFileName) const
Function AbsolutePath fixes up aFileName if it is relative to the project's directory to be an absolu...
Definition: project.cpp:370
The common library.
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:101
bool EDA_PATH_SELECTOR(const wxString &aTitle, wxString &aPath, int aFlags, wxWindow *aParent, const wxPoint &aPosition)
Function EDA_PATH_SELECTOR.
Definition: gestfich.cpp:54
void OnAddOrInsertPath(wxCommandEvent &event) override
void OnRemoveLibClick(wxCommandEvent &event) override
VTBL_ENTRY void SetRString(RSTRING_T aStringId, const wxString &aString)
Function SetRString stores a "retained string", which is any session and project specific string iden...
Definition: project.cpp:161
VTBL_ENTRY const wxString & GetRString(RSTRING_T aStringId)
Function GetRString returns a "retained string", which is any session and project specific string ide...
Definition: project.cpp:176
void OnCloseWindow(wxCloseEvent &event) override
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
see class PGM_BASE
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
bool InvokeEeschemaConfig(wxWindow *aParent, wxString *aCallersProjectSpecificLibPaths, wxArrayString *aCallersLibNames)
void OnButtonDownClick(wxCommandEvent &event) override
void OnOkClick(wxCommandEvent &event) override
#define DBG(x)
Definition: fctsys.h:33
static void remove_from_listbox(wxListBox *aListBox, const wxString &aText)
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:69
Definition of class LIB_EDIT_FRAME.