KiCad PCB EDA Suite
eeschema/eeschema.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) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
5  * Copyright (C) 2008 Wayne Stambaugh <stambaughw@verizon.net>
6  * Copyright (C) 2004-2017 KiCad Developers, see change_log.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 
26 #include <fctsys.h>
27 #include <pgm_base.h>
28 #include <kiface_i.h>
29 #include <confirm.h>
30 #include <gestfich.h>
31 #include <eda_dde.h>
32 #include <sch_edit_frame.h>
33 #include <lib_edit_frame.h>
34 #include <lib_view_frame.h>
35 #include <general.h>
36 #include <class_libentry.h>
37 #include <transform.h>
38 #include <symbol_lib_table.h>
41 #include <kiway.h>
42 #include <sim/sim_plot_frame.h>
43 #include <sexpr/sexpr.h>
44 #include <sexpr/sexpr_parser.h>
45 
46 // The main sheet of the project
48 
49 // a transform matrix, to display components in lib editor
51 
52 
53 namespace SCH {
54 
55 static struct IFACE : public KIFACE_I
56 {
57  // Of course all are virtual overloads, implementations of the KIFACE.
58 
59  IFACE( const char* aName, KIWAY::FACE_T aType ) :
60  KIFACE_I( aName, aType )
61  {}
62 
63  bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
64 
65  void OnKifaceEnd() override;
66 
67  wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) override
68  {
69  switch( aClassId )
70  {
71  case FRAME_SCH:
72  {
73  SCH_EDIT_FRAME* frame = new SCH_EDIT_FRAME( aKiway, aParent );
74 
75  if( Kiface().IsSingle() )
76  {
77  // only run this under single_top, not under a project manager.
79  }
80 
81  return frame;
82  }
83 
85  {
86  LIB_EDIT_FRAME* frame = new LIB_EDIT_FRAME( aKiway, aParent );
87  return frame;
88  }
89 
90 #ifdef KICAD_SPICE
91  case FRAME_SIMULATOR:
92  {
93  SIM_PLOT_FRAME* frame = new SIM_PLOT_FRAME( aKiway, aParent );
94  return frame;
95  }
96 #endif
97  case FRAME_SCH_VIEWER:
99  {
100  LIB_VIEW_FRAME* frame = new LIB_VIEW_FRAME( aKiway, aParent, FRAME_T( aClassId ) );
101  return frame;
102  }
103 
105  InvokeSchEditSymbolLibTable( aKiway, aParent );
106  // Dialog has completed; nothing to return.
107  return nullptr;
108 
109  default:
110  return NULL;
111  }
112  }
113 
122  void* IfaceOrAddress( int aDataId ) override
123  {
124  return NULL;
125  }
126 
133  void SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
134  const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
135  const wxString& aSrcFilePath, wxString& aErrors ) override;
136 
137 } kiface( "eeschema", KIWAY::FACE_SCH );
138 
139 } // namespace
140 
141 using namespace SCH;
142 
144 
145 
146 KIFACE_I& Kiface() { return kiface; }
147 
148 
149 // KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h.
150 // KIFACE_GETTER will not have name mangling due to declaration in kiway.h.
151 MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram )
152 {
153  process = aProgram;
154  return &kiface;
155 }
156 
157 
159 {
160  wxASSERT( process ); // KIFACE_GETTER has already been called.
161  return *process;
162 }
163 
164 
166 
168 {
169  unsigned layer = ( aLayer );
170  wxASSERT( layer < arrayDim( s_layerColor ) );
171  return s_layerColor[layer];
172 }
173 
174 void SetLayerColor( COLOR4D aColor, SCH_LAYER_ID aLayer )
175 {
176  // Do not allow non-background layers to be completely white.
177  // This ensures the BW printing recognizes that the colors should be printed black.
178  if( aColor == COLOR4D::WHITE && aLayer != LAYER_SCHEMATIC_BACKGROUND )
179  aColor.Darken( 0.01 );
180 
181  unsigned layer = aLayer;
182  wxASSERT( layer < arrayDim( s_layerColor ) );
183  s_layerColor[layer] = aColor;
184 }
185 
186 
187 static std::vector<PARAM_CFG*>& cfg_params()
188 {
189  static std::vector<PARAM_CFG*> ca;
190 
191  if( !ca.size() )
192  {
193  // These are KIFACE specific, they need to be loaded once when the
194  // eeschema KIFACE comes in.
195 
196 #define CLR(x, y, z)\
197  ca.push_back( new PARAM_CFG_SETCOLOR( true, wxT( x ),\
198  &s_layerColor[( y )], z ) );
199 
200  CLR( "Color4DWireEx", LAYER_WIRE, COLOR4D( GREEN ) )
201  CLR( "Color4DBusEx", LAYER_BUS, COLOR4D( BLUE ) )
202  CLR( "Color4DConnEx", LAYER_JUNCTION, COLOR4D( GREEN ) )
203  CLR( "Color4DLLabelEx", LAYER_LOCLABEL, COLOR4D( BLACK ) )
204  CLR( "Color4DHLabelEx", LAYER_HIERLABEL, COLOR4D( BROWN ) )
205  CLR( "Color4DGLabelEx", LAYER_GLOBLABEL, COLOR4D( RED ) )
206  CLR( "Color4DPinNumEx", LAYER_PINNUM, COLOR4D( RED ) )
207  CLR( "Color4DPinNameEx", LAYER_PINNAM, COLOR4D( CYAN ) )
208  CLR( "Color4DFieldEx", LAYER_FIELDS, COLOR4D( MAGENTA ) )
209  CLR( "Color4DReferenceEx", LAYER_REFERENCEPART, COLOR4D( CYAN ) )
210  CLR( "Color4DValueEx", LAYER_VALUEPART, COLOR4D( CYAN ) )
211  CLR( "Color4DNoteEx", LAYER_NOTES, COLOR4D( LIGHTBLUE ) )
212  CLR( "Color4DBodyEx", LAYER_DEVICE, COLOR4D( RED ) )
213  CLR( "Color4DBodyBgEx", LAYER_DEVICE_BACKGROUND, COLOR4D( LIGHTYELLOW ) )
214  CLR( "Color4DNetNameEx", LAYER_NETNAM, COLOR4D( DARKGRAY ) )
215  CLR( "Color4DPinEx", LAYER_PIN, COLOR4D( RED ) )
216  CLR( "Color4DSheetEx", LAYER_SHEET, COLOR4D( MAGENTA ) )
217  CLR( "Color4DSheetFileNameEx", LAYER_SHEETFILENAME, COLOR4D( BROWN ) )
218  CLR( "Color4DSheetNameEx", LAYER_SHEETNAME, COLOR4D( CYAN ) )
219  CLR( "Color4DSheetLabelEx", LAYER_SHEETLABEL, COLOR4D( BROWN ) )
220  CLR( "Color4DNoConnectEx", LAYER_NOCONNECT, COLOR4D( BLUE ) )
221  CLR( "Color4DErcWEx", LAYER_ERC_WARN, COLOR4D( GREEN ).WithAlpha(0.8 ) )
222  CLR( "Color4DErcEEx", LAYER_ERC_ERR, COLOR4D( RED ).WithAlpha(0.8 ) )
223  CLR( "Color4DGridEx", LAYER_SCHEMATIC_GRID, COLOR4D( DARKGRAY ) )
224  CLR( "Color4DBgCanvasEx", LAYER_SCHEMATIC_BACKGROUND, COLOR4D( WHITE ) )
225  CLR( "Color4DCursorEx", LAYER_SCHEMATIC_CURSOR, COLOR4D( BLACK ) )
226  CLR( "Color4DBrightenedEx", LAYER_BRIGHTENED, COLOR4D( PUREMAGENTA ) )
227  CLR( "Color4DHiddenEx", LAYER_HIDDEN, COLOR4D( LIGHTGRAY ) )
228  CLR( "Color4DWorksheetEx", LAYER_WORKSHEET, COLOR4D( RED ) )
229 // Macs look better with a lighter shadow
230 #ifdef __WXMAC__
231  CLR( "Color4DShadowEx", LAYER_SELECTION_SHADOWS, COLOR4D( .78, .92, 1.0, 0.8 ) )
232 #else
233  CLR( "Color4DShadowEx", LAYER_SELECTION_SHADOWS, COLOR4D( .4, .7, 1.0, 0.8 ) )
234 #endif
235  }
236 
237  return ca;
238 }
239 
240 
241 bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
242 {
243  // This is process-level-initialization, not project-level-initialization of the DSO.
244  // Do nothing in here pertinent to a project!
245 
246  start_common( aCtlBits );
247 
248  // Give a default colour for all layers (actual color will be initialized by config)
249  for( SCH_LAYER_ID ii = SCH_LAYER_ID_START; ii < SCH_LAYER_ID_END; ++ii )
250  SetLayerColor( COLOR4D( DARKGRAY ), ii );
251 
254 
256 
258 
259  if( !fn.FileExists() )
260  {
262 
263  fpDialog.ShowModal();
264  }
265  else
266  {
267  try
268  {
269  // The global table is not related to a specific project. All projects
270  // will use the same global table. So the KIFACE::OnKifaceStart() contract
271  // of avoiding anything project specific is not violated here.
273  return false;
274  }
275  catch( const IO_ERROR& ioe )
276  {
277  // if we are here, a incorrect global symbol library table was found.
278  // Incorrect global symbol library table is not a fatal error:
279  // the user just has to edit the (partially) loaded table.
280  wxString msg = _(
281  "An error occurred attempting to load the global symbol library table.\n"
282  "Please edit this global symbol library table in Preferences menu."
283  );
284 
285  DisplayErrorMessage( NULL, msg, ioe.What() );
286  }
287  }
288 
289  return true;
290 }
291 
292 
294 {
296  end_common();
297 }
298 
299 static void traverseSEXPR( SEXPR::SEXPR* aNode,
300  const std::function<void( SEXPR::SEXPR* )>& aVisitor )
301 {
302  aVisitor( aNode );
303 
304  if( aNode->IsList() )
305  {
306  for( unsigned i = 0; i < aNode->GetNumberOfChildren(); i++ )
307  traverseSEXPR( aNode->GetChild( i ), aVisitor );
308  }
309 }
310 
311 
312 void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
313  const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
314  const wxString& aSrcFilePath, wxString& aErrors )
315 {
316  wxFileName destFile( aSrcFilePath );
317  wxString destPath = destFile.GetPath();
318  wxString ext = destFile.GetExt();
319 
320  if( destPath.StartsWith( aProjectBasePath ) )
321  {
322  destPath.Replace( aProjectBasePath, aNewProjectBasePath, false );
323  destFile.SetPath( destPath );
324  }
325 
326  if( ext == "sch" || ext == "sch-bak" )
327  {
328  if( destFile.GetName() == aProjectName )
329  destFile.SetName( aNewProjectName );
330 
331  // Sheet paths when auto-generated are relative to the root, so those will stay
332  // pointing to whatever they were pointing at.
333  // The author can create their own absolute and relative sheet paths. Absolute
334  // sheet paths aren't an issue, and relative ones will continue to work as long
335  // as the author didn't include any '..'s. If they did, it's still not clear
336  // whether they should be adjusted or not (as the author may be duplicating an
337  // entire tree with several projects within it), so we leave this as an exercise
338  // to the author.
339 
340  CopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
341  }
342  else if( ext == "sym" )
343  {
344  // Symbols are not project-specific. Keep their source names.
345  CopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
346  }
347  else if( ext == "lib" )
348  {
349  if( destFile.GetName() == aProjectName )
350  destFile.SetName( aNewProjectName );
351  else if( destFile.GetName() == aProjectName + "-cache" )
352  destFile.SetName( aNewProjectName + "-cache" );
353  else if( destFile.GetName() == aProjectName + "-rescue" )
354  destFile.SetName( aNewProjectName + "-rescue" );
355 
356  CopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
357  }
358  else if( ext == "net" )
359  {
360  bool success = false;
361 
362  if( destFile.GetName() == aProjectName )
363  destFile.SetName( aNewProjectName );
364 
365  try
366  {
367  SEXPR::PARSER parser;
368  std::unique_ptr<SEXPR::SEXPR> sexpr( parser.ParseFromFile( TO_UTF8( aSrcFilePath ) ) );
369 
370  traverseSEXPR( sexpr.get(), [&]( SEXPR::SEXPR* node )
371  {
372  if( node->IsList() && node->GetNumberOfChildren() > 1
373  && node->GetChild( 0 )->IsSymbol()
374  && node->GetChild( 0 )->GetSymbol() == "source" )
375  {
376  auto pathNode = dynamic_cast<SEXPR::SEXPR_STRING*>( node->GetChild( 1 ) );
377  auto symNode = dynamic_cast<SEXPR::SEXPR_SYMBOL*>( node->GetChild( 1 ) );
378  wxString path;
379 
380  if( pathNode )
381  path = pathNode->m_value;
382  else if( symNode )
383  path = symNode->m_value;
384 
385  if( path == aProjectName + ".sch" )
386  path = aNewProjectName + ".sch";
387  else if( path == aProjectBasePath + "/" + aProjectName + ".sch" )
388  path = aNewProjectBasePath + "/" + aNewProjectName + ".sch";
389  else if( path.StartsWith( aProjectBasePath ) )
390  path.Replace( aProjectBasePath, aNewProjectBasePath, false );
391 
392  if( pathNode )
393  pathNode->m_value = path;
394  else if( symNode )
395  symNode->m_value = path;
396  }
397  } );
398 
399  wxFile destNetList( destFile.GetFullPath(), wxFile::write );
400 
401  if( destNetList.IsOpened() )
402  success = destNetList.Write( sexpr->AsString( 0 ) );
403 
404  // wxFile dtor will close the file
405  }
406  catch( ... )
407  {
408  success = false;
409  }
410 
411  if( !success )
412  {
413  wxString msg;
414 
415  if( !aErrors.empty() )
416  aErrors += "\n";
417 
418  msg.Printf( _( "Cannot copy file \"%s\"." ), destFile.GetFullPath() );
419  aErrors += msg;
420  }
421  }
422  else if( destFile.GetName() == "sym-lib-table" )
423  {
424  SYMBOL_LIB_TABLE symbolLibTable;
425  symbolLibTable.Load( aSrcFilePath );
426 
427  for( unsigned i = 0; i < symbolLibTable.GetCount(); i++ )
428  {
429  LIB_TABLE_ROW& row = symbolLibTable.At( i );
430  wxString uri = row.GetFullURI();
431 
432  uri.Replace( "/" + aProjectName + "-cache.lib", "/" + aNewProjectName + "-cache.lib" );
433  uri.Replace( "/" + aProjectName + "-rescue.lib", "/" + aNewProjectName + "-rescue.lib" );
434  uri.Replace( "/" + aProjectName + ".lib", "/" + aNewProjectName + ".lib" );
435 
436  row.SetFullURI( uri );
437  }
438 
439  try
440  {
441  symbolLibTable.Save( destFile.GetFullPath() );
442  }
443  catch( ... )
444  {
445  wxString msg;
446 
447  if( !aErrors.empty() )
448  aErrors += "\n";
449 
450  msg.Printf( _( "Cannot copy file \"%s\"." ), destFile.GetFullPath() );
451  aErrors += msg;
452  }
453  }
454  else
455  {
456  wxFAIL_MSG( "Unexpected filetype for Eeschema::SaveFileAs()" );
457  }
458 }
459 
Definition: colors.h:57
SCH::IFACE KIFACE_I kiface("eeschema", KIWAY::FACE_SCH)
PGM_BASE & Pgm()
The global Program "get" accessor.
static SYMBOL_LIB_TABLE & GetGlobalLibTable()
KIFACE_I is a KIFACE (I)mplementation, with some features useful for DSOs which implement a KIFACE.
Definition: kiface_i.h:37
int aKiwayVersion
DDE server & client.
bool start_common(int aCtlBits)
Common things to do for a top program module, during OnKifaceStart().
Definition: kiface_i.cpp:90
Hold a record identifying a library accessed by the appropriate plug in object in the LIB_TABLE.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:249
This file is part of the common library TODO brief description.
This file is part of the common library.
void OnKifaceEnd() override
Function OnKifaceEnd is called just once just before the DSO is to be unloaded.
PGM_BASE keeps program (whole process) data for KiCad programs.
Definition: pgm_base.h:156
void wxConfigLoadSetups(wxConfigBase *aCfg, const std::vector< PARAM_CFG * > &aList)
Function wxConfigLoadSetups uses aList of PARAM_CFG to load configuration values from aCfg.
FRAME_T
Enum FRAME_T is the set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition: frame_type.h:34
#define CLR(x, y, z)
unsigned GetCount() const
Get the number of rows contained in the table.
Definition: colors.h:61
wxWindow * CreateWindow(wxWindow *aParent, int aClassId, KIWAY *aKiway, int aCtlBits=0) override
Function CreateWindow creates a wxWindow for the current project.
void * IfaceOrAddress(int aDataId) override
Function IfaceOrAddress return a pointer to the requested object.
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
void InvokeSchEditSymbolLibTable(KIWAY *aKiway, wxWindow *aParent)
bool IsList() const
Definition: sexpr.h:54
void CopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
Function CopyFile.
Definition: gestfich.cpp:363
IFACE(const char *aName, KIWAY::FACE_T aType)
TRANSFORM DefaultTransform
static std::vector< PARAM_CFG * > & cfg_params()
Schematic editor (Eeschema) main window.
COLOR4D GetLayerColor(SCH_LAYER_ID aLayer)
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Symbol library viewer main window.
void wxConfigSaveSetups(wxConfigBase *aCfg, const std::vector< PARAM_CFG * > &aList)
Function wxConfigSaveSetups writes aList of PARAM_CFG to save configuration values to aCfg.
const wxString GetFullURI(bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
int PGM_BASE * aProgram
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:48
for transforming drawing coordinates for a wxDC device context.
Definition: transform.h:45
static bool LoadGlobalTable(SYMBOL_LIB_TABLE &aTable)
Load the global symbol library table into aTable.
#define KICAD_SCH_PORT_SERVICE_NUMBER
Definition: eda_dde.h:42
bool OnKifaceStart(PGM_BASE *aProgram, int aCtlBits) override
Function OnKifaceStart is called just once shortly after the DSO is loaded.
#define NULL
bool IsSingle() const
Function IsSingle is this KIFACE_I running under single_top?
Definition: kiface_i.h:115
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
void end_common()
Common things to do for a top program module, during OnKifaceEnd();.
Definition: kiface_i.cpp:100
void SaveFileAs(const wxString &aProjectBasePath, const wxString &aProjectName, const wxString &aNewProjectBasePath, const wxString &aNewProjectName, const wxString &aSrcFilePath, wxString &aErrors) override
Function SaveFileAs Saving a file under a different name is delegated to the various KIFACEs because ...
static COLOR4D s_layerColor[LAYER_ID_COUNT]
SEXPR * GetChild(size_t aIndex) const
Definition: sexpr.cpp:47
Class LIB_PIN definition.
Definition: colors.h:59
static PGM_BASE * process
KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the s...
Definition: kiway.h:274
static void traverseSEXPR(SEXPR::SEXPR *aNode, const std::function< void(SEXPR::SEXPR *)> &aVisitor)
Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder.
Definition: colors.h:60
#define KIFACE_GETTER
Definition: kiway.h:112
SCH_LAYER_ID
Eeschema drawing layers.
void Load(const wxString &aFileName)
Load the library table using the path defined by aFileName aFallBackTable.
#define LAYER_ID_COUNT
Must update this if you add any enums after GerbView!
Implementing SIM_PLOT_FRAME_BASE.
FACE_T
Known KIFACE implementations.
Definition: kiway.h:280
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:206
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Definition: macros.h:108
eeschema DSO
Definition: kiway.h:282
void SetLayerColor(COLOR4D aColor, SCH_LAYER_ID aLayer)
The symbol library editor main window.
void SetFullURI(const wxString &aFullURI)
Change the full URI for the library.
Definition: colors.h:58
see class PGM_BASE
LIB_TABLE_ROW & At(unsigned aIndex)
Get the 'n'th LIB_TABLE_ROW object.
#define _(s)
Definition: 3d_actions.cpp:31
COLOR4D & Darken(double aFactor)
Function Darken Makes the color darker by a given factor.
Definition: color4d.h:163
MY_API(KIFACE *) KIFACE_GETTER(int *aKIFACEversion
KIFACE is used by a participant in the KIWAY alchemy.
Definition: kiway.h:151
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
Definition: colors.h:49
SCH_SHEET * g_RootSheet
void CreateServer(int service, bool local=true)
Definition: eda_dde.cpp:49
Definition: colors.h:45
size_t GetNumberOfChildren() const
Definition: sexpr.cpp:69
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
static wxString GetGlobalTableFileName()
Fetch the global symbol library table file name.
std::unique_ptr< SEXPR > ParseFromFile(const std::string &aFilename)
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
Definition: colors.h:62