KiCad PCB EDA Suite
project.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) 2014-2017 KiCad Developers, see AUTHORS.txt for contributors.
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 #include <wx/stdpaths.h>
25 
26 #include <fctsys.h>
27 #include <macros.h>
28 #include <pgm_base.h>
29 #include <project.h>
30 #include <common.h> // NAMELESS_PROJECT
31 #include <confirm.h>
32 #include <kicad_string.h>
33 #include <config_params.h>
35 #include <fp_lib_table.h>
36 #include <kiway.h>
37 #include <kiface_ids.h>
38 
39 
41 {
42  memset( m_elems, 0, sizeof(m_elems) );
43 }
44 
45 
47 {
48  DBG( printf( "%s: clearing all _ELEMS for project %s\n", __func__, TO_UTF8( GetProjectFullName() ) );)
49 
50  // careful here, this should work, but the virtual destructor may not
51  // be in the same link image as PROJECT.
52  for( unsigned i = 0; i < DIM( m_elems ); ++i )
53  {
54  SetElem( ELEM_T( i ), NULL );
55  }
56 }
57 
58 
60 {
61  ElemsClear();
62 }
63 
64 
65 void PROJECT::SetProjectFullName( const wxString& aFullPathAndName )
66 {
67  // Compare paths, rather than inodes, to be less surprising to the user.
68  // Create a temporary wxFileName to normalize the path
69  wxFileName candidate_path( aFullPathAndName );
70 
71  // Edge transitions only. This is what clears the project
72  // data using the Clear() function.
73  if( m_project_name.GetFullPath() != candidate_path.GetFullPath() )
74  {
75  Clear(); // clear the data when the project changes.
76 
77  DBG(printf( "%s: old:'%s' new:'%s'\n", __func__, TO_UTF8( GetProjectFullName() ), TO_UTF8( aFullPathAndName ) );)
78 
79  m_project_name = aFullPathAndName;
80 
81  wxASSERT( m_project_name.IsAbsolute() );
82 
83  wxASSERT( m_project_name.GetExt() == ProjectFileExtension );
84 
85  // until multiple projects are in play, set an environment variable for the
86  // the project pointer.
87  {
88  wxString path = m_project_name.GetPath();
89 
90  wxSetEnv( PROJECT_VAR_NAME, path );
91  }
92  }
93 }
94 
95 
96 const wxString PROJECT::GetProjectFullName() const
97 {
98  return m_project_name.GetFullPath();
99 }
100 
101 
102 const wxString PROJECT::GetProjectPath() const
103 {
104  return m_project_name.GetPathWithSep();
105 }
106 
107 
108 const wxString PROJECT::GetProjectName() const
109 {
110  return m_project_name.GetName();
111 }
112 
113 
114 const wxString PROJECT::SymbolLibTableName() const
115 {
116  return libTableName( "sym-lib-table" );
117 }
118 
119 
120 const wxString PROJECT::FootprintLibTblName() const
121 {
122  return libTableName( "fp-lib-table" );
123 }
124 
125 
126 const wxString PROJECT::libTableName( const wxString& aLibTableName ) const
127 {
128  wxFileName fn = GetProjectFullName();
129  wxString path = fn.GetPath();
130 
131  // DBG(printf( "path:'%s' fn:'%s'\n", TO_UTF8(path), TO_UTF8(fn.GetFullPath()) );)
132 
133  // if there's no path to the project name, or the name as a whole is bogus or its not
134  // write-able then use a template file.
135  if( !fn.GetDirCount() || !fn.IsOk() || !wxFileName::IsDirWritable( path ) )
136  {
137  // return a template filename now.
138 
139  // this next line is likely a problem now, since it relies on an
140  // application title which is no longer constant or known. This next line needs
141  // to be re-thought out.
142 
143 #ifndef __WXMAC__
144  fn.AssignDir( wxStandardPaths::Get().GetUserConfigDir() );
145 #else
146  // don't pollute home folder, temp folder seems to be more appropriate
147  fn.AssignDir( wxStandardPaths::Get().GetTempDir() );
148 #endif
149 
150 #if defined( __WINDOWS__ )
151  fn.AppendDir( wxT( "kicad" ) );
152 #endif
153 
154  /*
155  * The library table name used when no project file is passed to the appropriate
156  * code. This is used temporarily to store the project specific library table
157  * until the project file being edited is saved. It is then moved to the correct
158  * file in the folder where the project file is saved.
159  */
160  fn.SetName( "prj-" + aLibTableName );
161  }
162  else // normal path.
163  {
164  fn.SetName( aLibTableName );
165  }
166 
167  fn.ClearExt();
168 
169  return fn.GetFullPath();
170 }
171 
172 
173 void PROJECT::SetRString( RSTRING_T aIndex, const wxString& aString )
174 {
175  unsigned ndx = unsigned( aIndex );
176 
177  if( ndx < DIM( m_rstrings ) )
178  {
179  m_rstrings[ndx] = aString;
180  }
181  else
182  {
183  wxASSERT( 0 ); // bad index
184  }
185 }
186 
187 
188 const wxString& PROJECT::GetRString( RSTRING_T aIndex )
189 {
190  unsigned ndx = unsigned( aIndex );
191 
192  if( ndx < DIM( m_rstrings ) )
193  {
194  return m_rstrings[ndx];
195  }
196  else
197  {
198  static wxString no_cookie_for_you;
199 
200  wxASSERT( 0 ); // bad index
201 
202  return no_cookie_for_you;
203  }
204 }
205 
206 
208 {
209  // This is virtual, so implement it out of line
210 
211  if( unsigned( aIndex ) < DIM( m_elems ) )
212  {
213  return m_elems[aIndex];
214  }
215  return NULL;
216 }
217 
218 
219 void PROJECT::SetElem( ELEM_T aIndex, _ELEM* aElem )
220 {
221  // This is virtual, so implement it out of line
222 
223  if( unsigned( aIndex ) < DIM( m_elems ) )
224  {
225 #if defined(DEBUG) && 0
226  if( aIndex == ELEM_SCH_PART_LIBS )
227  {
228  printf( "%s: &m_elems[%i]:%p aElem:%p\n", __func__, aIndex, &m_elems[aIndex], aElem );
229  }
230 #endif
231  delete m_elems[aIndex];
232  m_elems[aIndex] = aElem;
233  }
234 }
235 
236 
237 static bool copy_pro_file_template( const SEARCH_STACK& aSearchS, const wxString& aDestination )
238 {
239  if( aDestination.IsEmpty() )
240  {
241  DBG( printf( "%s: destination is empty.\n", __func__ );)
242  return false;
243  }
244 
245  wxString templateFile = wxT( "kicad." ) + ProjectFileExtension;
246 
247  wxString kicad_pro_template = aSearchS.FindValidPath( templateFile );
248 
249  if( !kicad_pro_template )
250  {
251  DBG( printf( "%s: template file '%s' not found using search paths.\n", __func__, TO_UTF8( templateFile ) );)
252 
253  wxFileName templ( wxStandardPaths::Get().GetDocumentsDir(),
254  wxT( "kicad" ), ProjectFileExtension );
255 
256  if( !templ.IsFileReadable() )
257  {
258  wxString msg = wxString::Format( _(
259  "Unable to find '%s' template config file." ),
260  GetChars( templateFile ) );
261 
262  DisplayErrorMessage( nullptr, _( "Error copying project file template" ), msg );
263 
264  return false;
265  }
266 
267  kicad_pro_template = templ.GetFullPath();
268  }
269 
270  DBG( printf( "%s: using template file '%s' as project file.\n", __func__, TO_UTF8( kicad_pro_template ) );)
271 
272  // Verify aDestination can be created. if this is not the case, wxCopyFile
273  // will generate a crappy log error message, and we *do not want* this kind
274  // of stupid message
275  wxFileName fn( aDestination );
276  bool success = true;
277 
278  if( fn.IsOk() && fn.IsDirWritable() )
279  success = wxCopyFile( kicad_pro_template, aDestination );
280  else
281  {
282  wxLogMessage( _( "Cannot create prj file '%s' (Directory not writable)" ),
283  GetChars( aDestination) );
284  success = false;
285  }
286 
287  return success;
288 }
289 
290 
291 wxConfigBase* PROJECT::configCreate( const SEARCH_STACK& aSList,
292  const wxString& aGroupName, const wxString& aProjectFileName )
293 {
294  wxConfigBase* cfg = 0;
295  wxString cur_pro_fn = !aProjectFileName ? GetProjectFullName() : aProjectFileName;
296 
297  if( wxFileName( cur_pro_fn ).IsFileReadable() )
298  {
299  // Note: currently, aGroupName is not used.
300  // Previoulsy, the version of aGroupName was tested, but it
301  // was useless, and if the version is important,
302  // this is not the right place here, because configCreate does know anything
303  // about info stored in this config file.
304  cfg = new wxFileConfig( wxEmptyString, wxEmptyString, cur_pro_fn, wxEmptyString );
305  return cfg;
306  }
307 
308  // No suitable pro file was found, either does not exist, or not readable.
309  // Use the template kicad.pro file. Find it by using caller's SEARCH_STACK.
310  copy_pro_file_template( aSList, cur_pro_fn );
311 
312  cfg = new wxFileConfig( wxEmptyString, wxEmptyString, cur_pro_fn, wxEmptyString );
313 
314  return cfg;
315 }
316 
317 
318 void PROJECT::ConfigSave( const SEARCH_STACK& aSList, const wxString& aGroupName,
319  const PARAM_CFG_ARRAY& aParams, const wxString& aFileName )
320 {
321  std::unique_ptr<wxConfigBase> cfg( configCreate( aSList, aGroupName, aFileName ) );
322 
323  if( !cfg.get() )
324  {
325  // could not find template
326  return;
327  }
328 
329  cfg->SetPath( wxT( "/" ) );
330 
331  cfg->Write( wxT( "update" ), DateAndTime() );
332 
333  // @todo: pass in aLastClient wxString:
334  cfg->Write( wxT( "last_client" ), Pgm().App().GetAppName() );
335 
336  // Save parameters
337  cfg->DeleteGroup( aGroupName ); // Erase all data
338  cfg->Flush();
339 
340  cfg->SetPath( aGroupName );
341  cfg->Write( wxT( "version" ), CONFIG_VERSION );
342 
343  cfg->SetPath( wxT( "/" ) );
344 
345  wxConfigSaveParams( cfg.get(), aParams, aGroupName );
346 
347  cfg->SetPath( wxT( "/" ) );
348 
349  // cfg is deleted here by std::unique_ptr, that saves the *.pro file to disk
350 }
351 
352 
353 bool PROJECT::ConfigLoad( const SEARCH_STACK& aSList, const wxString& aGroupName,
354  const PARAM_CFG_ARRAY& aParams, const wxString& aForeignProjectFileName )
355 {
356  std::unique_ptr<wxConfigBase> cfg( configCreate( aSList, aGroupName, aForeignProjectFileName ) );
357 
358  if( !cfg.get() )
359  {
360  // could not find template
361  return false;
362  }
363 
364  cfg->SetPath( wxCONFIG_PATH_SEPARATOR );
365 
366  wxString timestamp = cfg->Read( wxT( "update" ) );
367 
368  m_pro_date_and_time = timestamp;
369 
370  // We do not want expansion of env var values when reading our project config file
371  bool state = cfg.get()->IsExpandingEnvVars();
372  cfg.get()->SetExpandEnvVars( false );
373 
374  wxConfigLoadParams( cfg.get(), aParams, aGroupName );
375 
376  cfg.get()->SetExpandEnvVars( state );
377 
378  return true;
379 }
380 
381 
382 const wxString PROJECT::AbsolutePath( const wxString& aFileName ) const
383 {
384  wxFileName fn = aFileName;
385 
386  if( !fn.IsAbsolute() )
387  {
388  wxString pro_dir = wxPathOnly( GetProjectFullName() );
389  fn.Normalize( wxPATH_NORM_ALL, pro_dir );
390  }
391 
392  return fn.GetFullPath();
393 }
394 
395 
397 {
398  // This is a lazy loading function, it loads the project specific table when
399  // that table is asked for, not before.
400 
402 
403  // its gotta be NULL or a FP_LIB_TABLE, or a bug.
404  wxASSERT( !tbl || dynamic_cast<FP_LIB_TABLE*>( tbl ) );
405 
406  if( !tbl )
407  {
408  // Stack the project specific FP_LIB_TABLE overlay on top of the global table.
409  // ~FP_LIB_TABLE() will not touch the fallback table, so multiple projects may
410  // stack this way, all using the same global fallback table.
411  KIFACE* kiface = aKiway.KiFACE( KIWAY::FACE_PCB );
412  if( kiface )
414 
415  wxASSERT( tbl );
416  SetElem( ELEM_FPTBL, tbl );
417 
418  wxString projectFpLibTableFileName = FootprintLibTblName();
419 
420  try
421  {
422  tbl->Load( projectFpLibTableFileName );
423  }
424  catch( const IO_ERROR& ioe )
425  {
426  DisplayErrorMessage( NULL, _( "Error loading project footprint library table" ), ioe.What() );
427  }
428  }
429 
430  return tbl;
431 }
wxConfigBase * configCreate(const SEARCH_STACK &aSList, const wxString &aGroupName, const wxString &aProjectFileName=wxEmptyString)
Function configCreate loads a *.pro file and returns a wxConfigBase.
Definition: project.cpp:291
_ELEM * m_elems[ELEM_COUNT]
Definition: project.h:324
#define DIM(x)
of elements in an array
Definition: macros.h:98
A list of parameters type.
void Clear()
Function Clear clears the _ELEMs and RSTRINGs.
Definition: project.h:233
VTBL_ENTRY void ConfigSave(const SEARCH_STACK &aSList, const wxString &aGroupName, const PARAM_CFG_ARRAY &aParams, const wxString &aFileName=wxEmptyString)
Function ConfigSave saves the current "project" parameters into the wxConfigBase* derivative...
Definition: project.cpp:318
This file is part of the common library.
const wxString ProjectFileExtension
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
Definition: project.h:36
VTBL_ENTRY const wxString GetProjectFullName() const
Function GetProjectFullName returns the full path and name of the project.
Definition: project.cpp:96
The common library.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:65
void wxConfigSaveParams(wxConfigBase *aCfg, const PARAM_CFG_ARRAY &aList, const wxString &aGroup)
Function wxConfigSaveParams writes aList of PARAM_CFG_ARRAY elements to save configuration values to ...
Class SEARCH_STACK looks for files in a number of places.
Definition: search_stack.h:41
VTBL_ENTRY _ELEM * GetElem(ELEM_T aIndex)
Typically wrapped somewhere else in a more meaningful function wrapper.
Definition: project.cpp:207
VTBL_ENTRY void * IfaceOrAddress(int aDataId)=0
Function IfaceOrAddress returns a pointer to the requested object.
void wxConfigLoadParams(wxConfigBase *aCfg, const PARAM_CFG_ARRAY &aList, const wxString &aGroup)
Function wxConfigLoadParams uses aList of PARAM_CFG_ARRAY elements to load configuration values from ...
This file contains miscellaneous commonly used macros and functions.
VTBL_ENTRY void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:219
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
VTBL_ENTRY const wxString SymbolLibTableName() const
Return the path and file name of this projects symbol library table.
Definition: project.cpp:114
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString aExtraInfo)
Function DisplayErrorMessage displays an error message with aMessage.
Definition: confirm.cpp:87
wxFileName m_project_name
/.pro
Definition: project.h:317
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:382
The common library.
Class KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within...
Definition: kiway.h:257
pcbnew DSO
Definition: kiway.h:266
VTBL_ENTRY KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Function KiFACE returns the KIFACE* given a FACE_T.
Definition: kiway.cpp:150
VTBL_ENTRY const wxString FootprintLibTblName() const
Function FootprintLibTblName returns the path and filename of this project's fp-lib-table, i.e.
Definition: project.cpp:120
void Load(const wxString &aFileName)
Load the library table using the path defined by aFileName aFallBackTable.
VTBL_ENTRY void SetProjectFullName(const wxString &aFullPathAndName)
Function SetProjectFullName sets the: 1) full directory, 2) basename, and 3) extension of the project...
Definition: project.cpp:65
VTBL_ENTRY void ElemsClear()
Function ElemsClear deletes all the _ELEMs and set their pointers to NULL.
Definition: project.cpp:46
static bool copy_pro_file_template(const SEARCH_STACK &aSearchS, const wxString &aDestination)
Definition: project.cpp:237
PROJECT()
Definition: project.cpp:40
Return a new FP_LIB_TABLE copying the global table.
Definition: kiface_ids.h:46
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:173
VTBL_ENTRY FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
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:188
ELEM_T
Enum ELEM_T is the set of _ELEMs that a PROJECT can hold.
Definition: project.h:199
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
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
RSTRING_T
Retain a number of project specific wxStrings, enumerated here:
Definition: project.h:160
wxString m_rstrings[RSTRING_COUNT]
Definition: project.h:321
Class KIFACE is used by a participant in the KIWAY alchemy.
Definition: kiway.h:150
#define CONFIG_VERSION
Definition: config_params.h:56
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
The common library.
A PROJECT can hold stuff it knows nothing about, in the form of _ELEM derivatives.
Definition: project.h:66
return & kiface
Definition: pcbnew.cpp:197
#define DBG(x)
Definition: fctsys.h:33
VTBL_ENTRY bool ConfigLoad(const SEARCH_STACK &aSearchS, const wxString &aGroupName, const PARAM_CFG_ARRAY &aParams, const wxString &aForeignConfigFileName=wxEmptyString)
Function ConfigLoad reads a subset of parameters from the "project" file.
Definition: project.cpp:353
wxString m_pro_date_and_time
Definition: project.h:318
wxString FindValidPath(const wxString &aFileName) const
Definition: search_stack.h:71
~PROJECT()
Definition: project.cpp:59
const wxString libTableName(const wxString &aLibTableName) const
Return the full path and file name of the project specific library table aLibTableName.
Definition: project.cpp:126
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
wxString DateAndTime()
Function DateAndTime.
Definition: string.cpp:229
VTBL_ENTRY const wxString GetProjectName() const
Function GetProjectName returns the short name of the project.
Definition: project.cpp:108