KiCad PCB EDA Suite
common.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-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2008-2015 Wayne Stambaugh <stambaughw@verizon.net>
6  * Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
30 #include <fctsys.h>
31 #include <wxstruct.h>
32 #include <base_struct.h>
33 #include <common.h>
34 #include <macros.h>
35 #include <base_units.h>
36 #include <reporter.h>
37 
38 #include <wx/process.h>
39 #include <wx/config.h>
40 #include <wx/utils.h>
41 #include <wx/stdpaths.h>
42 
43 #include <pgm_base.h>
44 
45 using KIGFX::COLOR4D;
46 
47 
56 bool g_ShowPageLimits = true;
59 
60 
61 /* Class LOCALE_IO
62  * is a class that can be instantiated within a scope in which you are expecting
63  * exceptions to be thrown. Its constructor sets a "C" locale, to read/print files
64  * with fp numbers.
65  * Its destructor insures that the default locale is restored if an exception
66  * is thrown, or not.
67  */
68 
69 std::atomic<unsigned int> LOCALE_IO::m_c_count(0);
70 
72 {
73  // use thread safe, atomic operation
74  if( m_c_count++ == 0 )
75  {
76  // Store the user locale name, to restore this locale later, in dtor
77  m_user_locale = setlocale( LC_ALL, 0 );
78  // Switch the locale to C locale, to read/write files with fp numbers
79  setlocale( LC_ALL, "C" );
80  }
81 }
82 
84 {
85  // use thread safe, atomic operation
86  if( --m_c_count == 0 )
87  {
88  // revert to the user locale
89  setlocale( LC_ALL, m_user_locale.c_str() );
90  }
91 }
92 
93 
94 wxSize GetTextSize( const wxString& aSingleLine, wxWindow* aWindow )
95 {
96  wxCoord width;
97  wxCoord height;
98 
99  {
100  wxClientDC dc( aWindow );
101  dc.SetFont( aWindow->GetFont() );
102  dc.GetTextExtent( aSingleLine, &width, &height );
103  }
104 
105  return wxSize( width, height );
106 }
107 
108 
109 bool EnsureTextCtrlWidth( wxTextCtrl* aCtrl, const wxString* aString )
110 {
111  wxWindow* window = aCtrl->GetParent();
112 
113  if( !window )
114  window = aCtrl;
115 
116  wxString ctrlText;
117 
118  if( !aString )
119  {
120  ctrlText = aCtrl->GetValue();
121  aString = &ctrlText;
122  }
123 
124  wxSize textz = GetTextSize( *aString, window );
125  wxSize ctrlz = aCtrl->GetSize();
126 
127  if( ctrlz.GetWidth() < textz.GetWidth() + 10 )
128  {
129  ctrlz.SetWidth( textz.GetWidth() + 10 );
130  aCtrl->SetSizeHints( ctrlz );
131  return true;
132  }
133 
134  return false;
135 }
136 
137 
138 wxString ReturnUnitSymbol( EDA_UNITS_T aUnit, const wxString& formatString )
139 {
140  wxString tmp;
141  wxString label;
142 
143  switch( aUnit )
144  {
145  case INCHES:
146  tmp = _( "\"" );
147  break;
148 
149  case MILLIMETRES:
150  tmp = _( "mm" );
151  break;
152 
153  case UNSCALED_UNITS:
154  break;
155 
156  case DEGREES:
157  wxASSERT( false );
158  break;
159  }
160 
161  if( formatString.IsEmpty() )
162  return tmp;
163 
164  label.Printf( formatString, GetChars( tmp ) );
165 
166  return label;
167 }
168 
169 
170 wxString GetUnitsLabel( EDA_UNITS_T aUnit )
171 {
172  wxString label;
173 
174  switch( aUnit )
175  {
176  case INCHES:
177  label = _( "inches" );
178  break;
179 
180  case MILLIMETRES:
181  label = _( "millimeters" );
182  break;
183 
184  case UNSCALED_UNITS:
185  label = _( "units" );
186  break;
187 
188  case DEGREES:
189  label = _( "degrees" );
190  break;
191  }
192 
193  return label;
194 }
195 
196 
198 {
199  wxString label;
200 
201  switch( aUnit )
202  {
203  case INCHES:
204  label = _( "in" );
205  break;
206 
207  case MILLIMETRES:
208  label = _( "mm" );
209  break;
210 
211  case UNSCALED_UNITS:
212  break;
213 
214  case DEGREES:
215  label = _( "deg" );
216  break;
217 
218  default:
219  label = wxT( "??" );
220  break;
221  }
222 
223  return label;
224 }
225 
226 
227 void AddUnitSymbol( wxStaticText& Stext, EDA_UNITS_T aUnit )
228 {
229  wxString msg = Stext.GetLabel();
230 
231  msg += ReturnUnitSymbol( aUnit );
232 
233  Stext.SetLabel( msg );
234 }
235 
236 
237 void wxStringSplit( const wxString& aText, wxArrayString& aStrings, wxChar aSplitter )
238 {
239  wxString tmp;
240 
241  for( unsigned ii = 0; ii < aText.Length(); ii++ )
242  {
243  if( aText[ii] == aSplitter )
244  {
245  aStrings.Add( tmp );
246  tmp.Clear();
247  }
248 
249  else
250  tmp << aText[ii];
251  }
252 
253  if( !tmp.IsEmpty() )
254  {
255  aStrings.Add( tmp );
256  }
257 }
258 
259 
260 int ProcessExecute( const wxString& aCommandLine, int aFlags, wxProcess *callback )
261 {
262  return wxExecute( aCommandLine, aFlags, callback );
263 }
264 
265 
267 {
268  static time_t oldTimeStamp;
269  time_t newTimeStamp;
270 
271  newTimeStamp = time( NULL );
272 
273  if( newTimeStamp <= oldTimeStamp )
274  newTimeStamp = oldTimeStamp + 1;
275 
276  oldTimeStamp = newTimeStamp;
277 
278  return newTimeStamp;
279 }
280 
281 
282 double RoundTo0( double x, double precision )
283 {
284  assert( precision != 0 );
285 
286  long long ix = KiROUND( x * precision );
287 
288  if ( x < 0.0 )
289  ix = -ix;
290 
291  int remainder = ix % 10; // remainder is in precision mm
292 
293  if( remainder <= 2 )
294  ix -= remainder; // truncate to the near number
295  else if( remainder >= 8 )
296  ix += 10 - remainder; // round to near number
297 
298  if ( x < 0 )
299  ix = -ix;
300 
301  return (double) ix / precision;
302 }
303 
304 
305 wxConfigBase* GetNewConfig( const wxString& aProgName )
306 {
307  wxConfigBase* cfg = 0;
308  wxFileName configname;
309  configname.AssignDir( GetKicadConfigPath() );
310  configname.SetFullName( aProgName );
311 
312  cfg = new wxFileConfig( wxT( "" ), wxT( "" ), configname.GetFullPath() );
313  return cfg;
314 }
315 
317 {
318  wxFileName lockpath;
319  lockpath.AssignDir( wxGetHomeDir() ); // Default wx behavior
320 
321 #if defined( __WXMAC__ )
322  // In OSX use the standard per user cache directory
323  lockpath.AppendDir( wxT( "Library" ) );
324  lockpath.AppendDir( wxT( "Caches" ) );
325  lockpath.AppendDir( wxT( "kicad" ) );
326 #elif defined( __UNIX__ )
327  wxString envstr;
328  // Try first the standard XDG_RUNTIME_DIR, falling back to XDG_CACHE_HOME
329  if( wxGetEnv( wxT( "XDG_RUNTIME_DIR" ), &envstr ) && !envstr.IsEmpty() )
330  {
331  lockpath.AssignDir( envstr );
332  }
333  else if( wxGetEnv( wxT( "XDG_CACHE_HOME" ), &envstr ) && !envstr.IsEmpty() )
334  {
335  lockpath.AssignDir( envstr );
336  }
337  else
338  {
339  // If all fails, just use ~/.cache
340  lockpath.AppendDir( wxT( ".cache" ) );
341  }
342 
343  lockpath.AppendDir( wxT( "kicad" ) );
344 #endif
345 
346 #if defined( __WXMAC__ ) || defined( __UNIX__ )
347  if( !lockpath.DirExists() )
348  {
349  // Lockfiles should be only readable by the user
350  lockpath.Mkdir( 0700, wxPATH_MKDIR_FULL );
351  }
352 #endif
353  return lockpath.GetPath();
354 }
355 
356 
358 {
359  wxFileName cfgpath;
360 
361  // From the wxWidgets wxStandardPaths::GetUserConfigDir() help:
362  // Unix: ~ (the home directory)
363  // Windows: "C:\Documents and Settings\username\Application Data"
364  // Mac: ~/Library/Preferences
365  cfgpath.AssignDir( wxStandardPaths::Get().GetUserConfigDir() );
366 
367 #if !defined( __WINDOWS__ ) && !defined( __WXMAC__ )
368  wxString envstr;
369 
370  if( !wxGetEnv( wxT( "XDG_CONFIG_HOME" ), &envstr ) || envstr.IsEmpty() )
371  {
372  // XDG_CONFIG_HOME is not set, so use the fallback
373  cfgpath.AppendDir( wxT( ".config" ) );
374  }
375  else
376  {
377  // Override the assignment above with XDG_CONFIG_HOME
378  cfgpath.AssignDir( envstr );
379  }
380 #endif
381 
382  cfgpath.AppendDir( wxT( "kicad" ) );
383 
384  if( !cfgpath.DirExists() )
385  {
386  cfgpath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
387  }
388 
389  return cfgpath.GetPath();
390 }
391 
392 
393 #include <ki_mutex.h>
394 const wxString ExpandEnvVarSubstitutions( const wxString& aString )
395 {
396  // wxGetenv( wchar_t* ) is not re-entrant on linux.
397  // Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
398  static MUTEX getenv_mutex;
399 
400  MUTLOCK lock( getenv_mutex );
401 
402  // We reserve the right to do this another way, by providing our own member
403  // function.
404  return wxExpandEnvVars( aString );
405 }
406 
407 bool EnsureFileDirectoryExists( wxFileName* aTargetFullFileName,
408  const wxString& aBaseFilename,
409  REPORTER* aReporter )
410 {
411  wxString msg;
412  wxString baseFilePath = wxFileName( aBaseFilename ).GetPath();
413 
414  // make aTargetFullFileName path, which is relative to aBaseFilename path (if it is not
415  // already an absolute path) absolute:
416  if( !aTargetFullFileName->MakeAbsolute( baseFilePath ) )
417  {
418  if( aReporter )
419  {
420  msg.Printf( _( "Cannot make path '%s' absolute with respect to '%s'." ),
421  GetChars( aTargetFullFileName->GetPath() ),
422  GetChars( baseFilePath ) );
423  aReporter->Report( msg, REPORTER::RPT_ERROR );
424  }
425 
426  return false;
427  }
428 
429  // Ensure the path of aTargetFullFileName exists, and create it if needed:
430  wxString outputPath( aTargetFullFileName->GetPath() );
431 
432  if( !wxFileName::DirExists( outputPath ) )
433  {
434  if( wxMkdir( outputPath ) )
435  {
436  if( aReporter )
437  {
438  msg.Printf( _( "Output directory '%s' created.\n" ), GetChars( outputPath ) );
439  aReporter->Report( msg, REPORTER::RPT_INFO );
440  return true;
441  }
442  }
443  else
444  {
445  if( aReporter )
446  {
447  msg.Printf( _( "Cannot create output directory '%s'.\n" ),
448  GetChars( outputPath ) );
449  aReporter->Report( msg, REPORTER::RPT_ERROR );
450  }
451 
452  return false;
453  }
454  }
455 
456  return true;
457 }
458 
459 
460 #ifdef __WXMAC__
461 wxString GetOSXKicadUserDataDir()
462 {
463  // According to wxWidgets documentation for GetUserDataDir:
464  // Mac: ~/Library/Application Support/appname
465  wxFileName udir( wxStandardPaths::Get().GetUserDataDir(), wxEmptyString );
466 
467  // Since appname is different if started via launcher or standalone binary
468  // map all to "kicad" here
469  udir.RemoveLastDir();
470  udir.AppendDir( wxT( "kicad" ) );
471 
472  return udir.GetPath();
473 }
474 
475 
476 wxString GetOSXKicadMachineDataDir()
477 {
478  return wxT( "/Library/Application Support/kicad" );
479 }
480 
481 
482 wxString GetOSXKicadDataDir()
483 {
484  // According to wxWidgets documentation for GetDataDir:
485  // Mac: appname.app/Contents/SharedSupport bundle subdirectory
486  wxFileName ddir( wxStandardPaths::Get().GetDataDir(), wxEmptyString );
487 
488  // This must be mapped to main bundle for everything but kicad.app
489  const wxArrayString dirs = ddir.GetDirs();
490  if( dirs[dirs.GetCount() - 3] != wxT( "kicad.app" ) )
491  {
492  // Bundle structure resp. current path is
493  // kicad.app/Contents/Applications/<standalone>.app/Contents/SharedSupport
494  // and will be mapped to
495  // kicad.app/Contents/SharedSupprt
496  ddir.RemoveLastDir();
497  ddir.RemoveLastDir();
498  ddir.RemoveLastDir();
499  ddir.RemoveLastDir();
500  ddir.AppendDir( wxT( "SharedSupport" ) );
501  }
502 
503  return ddir.GetPath();
504 }
505 #endif
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Function wxStringSplit splits aString to a string list separated at aSplitter.
Definition: common.cpp:237
int ProcessExecute(const wxString &aCommandLine, int aFlags, wxProcess *callback)
Function ProcessExecute runs a child process.
Definition: common.cpp:260
~LOCALE_IO()
Definition: common.cpp:83
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:128
bool g_ShowPageLimits
Global variables definitions.
Definition: common.cpp:56
Implementation of conversion functions that require both schematic and board internal units...
double RoundTo0(double x, double precision)
Round to the nearest precision.
Definition: common.cpp:282
wxConfigBase * GetNewConfig(const wxString &aProgName)
Function GetNewConfig.
Definition: common.cpp:305
time_t GetNewTimeStamp()
Definition: common.cpp:266
wxString ReturnUnitSymbol(EDA_UNITS_T aUnit, const wxString &formatString)
Returns the units symbol.
Definition: common.cpp:138
boost::interprocess::interprocess_mutex MUTEX
Establish KiCad MUTEX choices here in this file: typedef MUTEX and typedef MUTLOCK.
Definition: ki_mutex.h:42
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
This file contains miscellaneous commonly used macros and functions.
wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Function GetTextSize returns the size of aSingleLine of text when it is rendered in aWindow using wha...
Definition: common.cpp:94
wxString GetUnitsLabel(EDA_UNITS_T aUnit)
Get a human readable units string.
Definition: common.cpp:170
static std::atomic< unsigned int > m_c_count
Definition: common.h:205
wxString GetAbbreviatedUnitsLabel(EDA_UNITS_T aUnit)
Definition: common.cpp:197
bool EnsureTextCtrlWidth(wxTextCtrl *aCtrl, const wxString *aString)
Function EnsureTextCtrlWidth sets the minimum pixel width on a text control in order to make a text s...
Definition: common.cpp:109
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Function ExpandEnvVarSubstitutions replaces any environment variable references with their values...
Definition: common.cpp:394
Base window classes and related definitions.
Definition: common.h:174
bool EnsureFileDirectoryExists(wxFileName *aTargetFullFileName, const wxString &aBaseFilename, REPORTER *aReporter)
Helper function EnsureFileDirectoryExists make aTargetFullFileName absolute and creates the path of t...
Definition: common.cpp:407
LOCALE_IO()
Definition: common.cpp:71
wxString GetKicadConfigPath()
Function GetKicadConfigPath.
Definition: common.cpp:357
EDA_UNITS_T g_UserUnit
display units
Definition: common.cpp:57
boost::interprocess::scoped_lock< MUTEX > MUTLOCK
Definition: ki_mutex.h:43
void AddUnitSymbol(wxStaticText &Stext, EDA_UNITS_T aUnit)
Definition: common.cpp:227
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
wxString GetKicadLockFilePath()
Function GetKicadLockFilePath.
Definition: common.cpp:316
The common library.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
Basic classes for most KiCad items.
EDA_UNITS_T
Definition: common.h:173
COLOR4D g_GhostColor
Draw color for moving objects.
Definition: common.cpp:58
std::string m_user_locale
Definition: common.h:209
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39