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 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 1992-2018 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 std::atomic<unsigned int> LOCALE_IO::m_c_count(0);
62 
64 {
65  // use thread safe, atomic operation
66  if( m_c_count++ == 0 )
67  {
68  // Store the user locale name, to restore this locale later, in dtor
69  m_user_locale = setlocale( LC_ALL, 0 );
70  // Switch the locale to C locale, to read/write files with fp numbers
71  setlocale( LC_ALL, "C" );
72  }
73 }
74 
75 
77 {
78  // use thread safe, atomic operation
79  if( --m_c_count == 0 )
80  {
81  // revert to the user locale
82  setlocale( LC_ALL, m_user_locale.c_str() );
83  }
84 }
85 
86 
87 wxSize GetTextSize( const wxString& aSingleLine, wxWindow* aWindow )
88 {
89  wxCoord width;
90  wxCoord height;
91 
92  {
93  wxClientDC dc( aWindow );
94  dc.SetFont( aWindow->GetFont() );
95  dc.GetTextExtent( aSingleLine, &width, &height );
96  }
97 
98  return wxSize( width, height );
99 }
100 
101 
102 bool EnsureTextCtrlWidth( wxTextCtrl* aCtrl, const wxString* aString )
103 {
104  wxWindow* window = aCtrl->GetParent();
105 
106  if( !window )
107  window = aCtrl;
108 
109  wxString ctrlText;
110 
111  if( !aString )
112  {
113  ctrlText = aCtrl->GetValue();
114  aString = &ctrlText;
115  }
116 
117  wxSize textz = GetTextSize( *aString, window );
118  wxSize ctrlz = aCtrl->GetSize();
119 
120  if( ctrlz.GetWidth() < textz.GetWidth() + 10 )
121  {
122  ctrlz.SetWidth( textz.GetWidth() + 10 );
123  aCtrl->SetSizeHints( ctrlz );
124  return true;
125  }
126 
127  return false;
128 }
129 
130 
131 void wxStringSplit( const wxString& aText, wxArrayString& aStrings, wxChar aSplitter )
132 {
133  wxString tmp;
134 
135  for( unsigned ii = 0; ii < aText.Length(); ii++ )
136  {
137  if( aText[ii] == aSplitter )
138  {
139  aStrings.Add( tmp );
140  tmp.Clear();
141  }
142 
143  else
144  tmp << aText[ii];
145  }
146 
147  if( !tmp.IsEmpty() )
148  {
149  aStrings.Add( tmp );
150  }
151 }
152 
153 
154 int ProcessExecute( const wxString& aCommandLine, int aFlags, wxProcess *callback )
155 {
156  return wxExecute( aCommandLine, aFlags, callback );
157 }
158 
159 
161 {
162  static timestamp_t oldTimeStamp;
163  timestamp_t newTimeStamp;
164 
165  newTimeStamp = time( NULL );
166 
167  if( newTimeStamp <= oldTimeStamp )
168  newTimeStamp = oldTimeStamp + 1;
169 
170  oldTimeStamp = newTimeStamp;
171 
172  return newTimeStamp;
173 }
174 
175 
176 double RoundTo0( double x, double precision )
177 {
178  assert( precision != 0 );
179 
180  long long ix = KiROUND( x * precision );
181 
182  if ( x < 0.0 )
183  ix = -ix;
184 
185  int remainder = ix % 10; // remainder is in precision mm
186 
187  if( remainder <= 2 )
188  ix -= remainder; // truncate to the near number
189  else if( remainder >= 8 )
190  ix += 10 - remainder; // round to near number
191 
192  if ( x < 0 )
193  ix = -ix;
194 
195  return (double) ix / precision;
196 }
197 
198 
199 wxConfigBase* GetNewConfig( const wxString& aProgName )
200 {
201  wxConfigBase* cfg = 0;
202  wxFileName configname;
203  configname.AssignDir( GetKicadConfigPath() );
204  configname.SetFullName( aProgName );
205 
206  cfg = new wxFileConfig( wxT( "" ), wxT( "" ), configname.GetFullPath() );
207  return cfg;
208 }
209 
210 
212 {
213  wxFileName cfgpath;
214 
215  // http://docs.wxwidgets.org/3.0/classwx_standard_paths.html#a7c7cf595d94d29147360d031647476b0
216  cfgpath.AssignDir( wxStandardPaths::Get().GetUserConfigDir() );
217 
218  // GetUserConfigDir() does not default to ~/.config which is the current standard
219  // configuration file location on Linux. This has been fixed in later versions of wxWidgets.
220 #if !defined( __WXMSW__ ) && !defined( __WXMAC__ )
221  wxArrayString dirs = cfgpath.GetDirs();
222 
223  if( dirs.Last() != ".config" )
224  cfgpath.AppendDir( ".config" );
225 #endif
226 
227  wxString envstr;
228 
229  // This shouldn't cause any issues on Windows or MacOS.
230  if( wxGetEnv( wxT( "XDG_CONFIG_HOME" ), &envstr ) && !envstr.IsEmpty() )
231  {
232  // Override the assignment above with XDG_CONFIG_HOME
233  cfgpath.AssignDir( envstr );
234  }
235 
236  cfgpath.AppendDir( wxT( "kicad" ) );
237 
238  // Use KICAD_CONFIG_HOME to allow the user to force a specific configuration path.
239  if( wxGetEnv( wxT( "KICAD_CONFIG_HOME" ), &envstr ) && !envstr.IsEmpty() )
240  {
241  // Override the assignment above with KICAD_CONFIG_HOME
242  cfgpath.AssignDir( envstr );
243  }
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)
Split aString to a string list separated at aSplitter.
Definition: common.cpp:131
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)
Run a command in a child process.
Definition: common.cpp:154
~LOCALE_IO()
Definition: common.cpp:76
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:106
const wxString ResolveUriByEnvVars(const wxString &aUri)
Replace any environment variables in file-path uris (leaving network-path URIs alone).
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:176
wxConfigBase * GetNewConfig(const wxString &aProgName)
Create a new wxConfig so we can put configuration files in a more proper place for each platform...
Definition: common.cpp:199
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)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
Definition: common.cpp:87
static std::atomic< unsigned int > m_c_count
Definition: common.h:177
timestamp_t GetNewTimeStamp()
Definition: common.cpp:160
bool EnsureTextCtrlWidth(wxTextCtrl *aCtrl, const wxString *aString)
Set the minimum pixel width on a text control in order to make a text string be fully visible within ...
Definition: common.cpp:102
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:255
bool EnsureFileDirectoryExists(wxFileName *aTargetFullFileName, const wxString &aBaseFilename, REPORTER *aReporter)
Make aTargetFullFileName absolute and create the path of this file if it doesn&#39;t yet exist...
Definition: common.cpp:282
Base window classes and related definitions.
LOCALE_IO()
Definition: common.cpp:63
wxString GetKicadConfigPath()
Return the user configuration path used to store KiCad&#39;s configuration files.
Definition: common.cpp:211
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:145
COLOR4D g_GhostColor
Draw color for moving objects.
Definition: common.cpp:58
std::string m_user_locale
Definition: common.h:181
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39