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-2017 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 <eda_base_frame.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 #include <wx/url.h>
43 
44 #include <pgm_base.h>
45 
46 using KIGFX::COLOR4D;
47 
48 
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 void wxStringSplit( const wxString& aText, wxArrayString& aStrings, wxChar aSplitter )
139 {
140  wxString tmp;
141 
142  for( unsigned ii = 0; ii < aText.Length(); ii++ )
143  {
144  if( aText[ii] == aSplitter )
145  {
146  aStrings.Add( tmp );
147  tmp.Clear();
148  }
149 
150  else
151  tmp << aText[ii];
152  }
153 
154  if( !tmp.IsEmpty() )
155  {
156  aStrings.Add( tmp );
157  }
158 }
159 
160 
161 int ProcessExecute( const wxString& aCommandLine, int aFlags, wxProcess *callback )
162 {
163  return wxExecute( aCommandLine, aFlags, callback );
164 }
165 
166 
168 {
169  static timestamp_t oldTimeStamp;
170  timestamp_t newTimeStamp;
171 
172  newTimeStamp = time( NULL );
173 
174  if( newTimeStamp <= oldTimeStamp )
175  newTimeStamp = oldTimeStamp + 1;
176 
177  oldTimeStamp = newTimeStamp;
178 
179  return newTimeStamp;
180 }
181 
182 
183 double RoundTo0( double x, double precision )
184 {
185  assert( precision != 0 );
186 
187  long long ix = KiROUND( x * precision );
188 
189  if ( x < 0.0 )
190  ix = -ix;
191 
192  int remainder = ix % 10; // remainder is in precision mm
193 
194  if( remainder <= 2 )
195  ix -= remainder; // truncate to the near number
196  else if( remainder >= 8 )
197  ix += 10 - remainder; // round to near number
198 
199  if ( x < 0 )
200  ix = -ix;
201 
202  return (double) ix / precision;
203 }
204 
205 
206 wxConfigBase* GetNewConfig( const wxString& aProgName )
207 {
208  wxConfigBase* cfg = 0;
209  wxFileName configname;
210  configname.AssignDir( GetKicadConfigPath() );
211  configname.SetFullName( aProgName );
212 
213  cfg = new wxFileConfig( wxT( "" ), wxT( "" ), configname.GetFullPath() );
214  return cfg;
215 }
216 
217 
219 {
220  wxFileName cfgpath;
221 
222  // From the wxWidgets wxStandardPaths::GetUserConfigDir() help:
223  // Unix: ~ (the home directory)
224  // Windows: "C:\Documents and Settings\username\Application Data"
225  // Mac: ~/Library/Preferences
226  cfgpath.AssignDir( wxStandardPaths::Get().GetUserConfigDir() );
227 
228 #if !defined( __WINDOWS__ ) && !defined( __WXMAC__ )
229  wxString envstr;
230 
231  if( !wxGetEnv( wxT( "XDG_CONFIG_HOME" ), &envstr ) || envstr.IsEmpty() )
232  {
233  // XDG_CONFIG_HOME is not set, so use the fallback
234  cfgpath.AppendDir( wxT( ".config" ) );
235  }
236  else
237  {
238  // Override the assignment above with XDG_CONFIG_HOME
239  cfgpath.AssignDir( envstr );
240  }
241 #endif
242 
243  cfgpath.AppendDir( wxT( "kicad" ) );
244 
245  if( !cfgpath.DirExists() )
246  {
247  cfgpath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
248  }
249 
250  return cfgpath.GetPath();
251 }
252 
253 
254 #include <ki_mutex.h>
255 const wxString ExpandEnvVarSubstitutions( const wxString& aString )
256 {
257  // wxGetenv( wchar_t* ) is not re-entrant on linux.
258  // Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
259  static MUTEX getenv_mutex;
260 
261  MUTLOCK lock( getenv_mutex );
262 
263  // We reserve the right to do this another way, by providing our own member
264  // function.
265  return wxExpandEnvVars( aString );
266 }
267 
268 
269 const wxString ResolveUriByEnvVars( const wxString& aUri )
270 {
271  // URL-like URI: return as is.
272  wxURL url( aUri );
273  if( url.GetError() == wxURL_NOERR )
274  return aUri;
275 
276  // Otherwise, the path points to a local file. Resolve environment
277  // variables if any.
278  return ExpandEnvVarSubstitutions( aUri );
279 }
280 
281 
282 bool EnsureFileDirectoryExists( wxFileName* aTargetFullFileName,
283  const wxString& aBaseFilename,
284  REPORTER* aReporter )
285 {
286  wxString msg;
287  wxString baseFilePath = wxFileName( aBaseFilename ).GetPath();
288 
289  // make aTargetFullFileName path, which is relative to aBaseFilename path (if it is not
290  // already an absolute path) absolute:
291  if( !aTargetFullFileName->MakeAbsolute( baseFilePath ) )
292  {
293  if( aReporter )
294  {
295  msg.Printf( _( "Cannot make path \"%s\" absolute with respect to \"%s\"." ),
296  GetChars( aTargetFullFileName->GetPath() ),
297  GetChars( baseFilePath ) );
298  aReporter->Report( msg, REPORTER::RPT_ERROR );
299  }
300 
301  return false;
302  }
303 
304  // Ensure the path of aTargetFullFileName exists, and create it if needed:
305  wxString outputPath( aTargetFullFileName->GetPath() );
306 
307  if( !wxFileName::DirExists( outputPath ) )
308  {
309  if( wxMkdir( outputPath ) )
310  {
311  if( aReporter )
312  {
313  msg.Printf( _( "Output directory \"%s\" created.\n" ), GetChars( outputPath ) );
314  aReporter->Report( msg, REPORTER::RPT_INFO );
315  return true;
316  }
317  }
318  else
319  {
320  if( aReporter )
321  {
322  msg.Printf( _( "Cannot create output directory \"%s\".\n" ),
323  GetChars( outputPath ) );
324  aReporter->Report( msg, REPORTER::RPT_ERROR );
325  }
326 
327  return false;
328  }
329  }
330 
331  return true;
332 }
333 
334 
335 #ifdef __WXMAC__
336 wxString GetOSXKicadUserDataDir()
337 {
338  // According to wxWidgets documentation for GetUserDataDir:
339  // Mac: ~/Library/Application Support/appname
340  wxFileName udir( wxStandardPaths::Get().GetUserDataDir(), wxEmptyString );
341 
342  // Since appname is different if started via launcher or standalone binary
343  // map all to "kicad" here
344  udir.RemoveLastDir();
345  udir.AppendDir( wxT( "kicad" ) );
346 
347  return udir.GetPath();
348 }
349 
350 
351 wxString GetOSXKicadMachineDataDir()
352 {
353  return wxT( "/Library/Application Support/kicad" );
354 }
355 
356 
357 wxString GetOSXKicadDataDir()
358 {
359  // According to wxWidgets documentation for GetDataDir:
360  // Mac: appname.app/Contents/SharedSupport bundle subdirectory
361  wxFileName ddir( wxStandardPaths::Get().GetDataDir(), wxEmptyString );
362 
363  // This must be mapped to main bundle for everything but kicad.app
364  const wxArrayString dirs = ddir.GetDirs();
365  if( dirs[dirs.GetCount() - 3] != wxT( "kicad.app" ) )
366  {
367  // Bundle structure resp. current path is
368  // kicad.app/Contents/Applications/<standalone>.app/Contents/SharedSupport
369  // and will be mapped to
370  // kicad.app/Contents/SharedSupprt
371  ddir.RemoveLastDir();
372  ddir.RemoveLastDir();
373  ddir.RemoveLastDir();
374  ddir.RemoveLastDir();
375  ddir.AppendDir( wxT( "SharedSupport" ) );
376  }
377 
378  return ddir.GetPath();
379 }
380 #endif
381 
382 // add this only if it is not in wxWidgets (for instance before 3.1.0)
383 #ifdef USE_KICAD_WXSTRING_HASH
384 size_t std::hash<wxString>::operator()( const wxString& s ) const
385 {
386  return std::hash<std::wstring>{}( s.ToStdWstring() );
387 }
388 #endif
389 
390 
391 #ifdef USE_KICAD_WXPOINT_LESS
392 bool std::less<wxPoint>::operator()( const wxPoint& aA, const wxPoint& aB ) const
393 {
394  if( aA.x == aB.x )
395  return aA.y < aB.y;
396 
397  return aA.x < aB.x;
398 }
399 #endif
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Function wxStringSplit splits aString to a string list separated at aSplitter.
Definition: common.cpp:138
long timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: base_struct.h:155
int ProcessExecute(const wxString &aCommandLine, int aFlags, wxProcess *callback)
Function ProcessExecute runs a child process.
Definition: common.cpp:161
~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:107
const wxString ResolveUriByEnvVars(const wxString &aUri)
Function ResolveUriByEnvVars replaces any environment variables in file-path uris (leaving network-pa...
Definition: common.cpp:269
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:183
wxConfigBase * GetNewConfig(const wxString &aProgName)
Function GetNewConfig.
Definition: common.cpp:206
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
static std::atomic< unsigned int > m_c_count
Definition: common.h:176
timestamp_t GetNewTimeStamp()
Definition: common.cpp:167
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:255
bool EnsureFileDirectoryExists(wxFileName *aTargetFullFileName, const wxString &aBaseFilename, REPORTER *aReporter)
Helper function EnsureFileDirectoryExists make aTargetFullFileName absolute and creates the path of t...
Definition: common.cpp:282
Base window classes and related definitions.
LOCALE_IO()
Definition: common.cpp:71
wxString GetKicadConfigPath()
Function GetKicadConfigPath.
Definition: common.cpp:218
EDA_UNITS_T g_UserUnit
Global variables definitions.
Definition: common.cpp:57
bool operator()(const wxPoint &aA, const wxPoint &aB) const
Definition: common.cpp:392
boost::interprocess::scoped_lock< MUTEX > MUTLOCK
Definition: ki_mutex.h:43
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
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.
size_t operator()(const wxString &s) const
Definition: common.cpp:384
Basic classes for most KiCad items.
EDA_UNITS_T
Definition: common.h:144
COLOR4D g_GhostColor
Draw color for moving objects.
Definition: common.cpp:58
std::string m_user_locale
Definition: common.h:180
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39