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@gmail.com>
6  * Copyright (C) 2004-2020 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 <eeschema_settings.h>
33 #include <sch_edit_frame.h>
34 #include <lib_edit_frame.h>
35 #include <lib_view_frame.h>
36 #include <general.h>
37 #include <class_libentry.h>
38 #include <transform.h>
39 #include <symbol_lib_table.h>
42 #include <kiway.h>
43 #include <sim/sim_plot_frame.h>
45 #include <sexpr/sexpr.h>
46 #include <sexpr/sexpr_parser.h>
47 
48 // The main sheet of the project
50 
51 // a transform matrix, to display components in lib editor
53 
54 
55 namespace SCH {
56 
57 static struct IFACE : public KIFACE_I
58 {
59  // Of course all are virtual overloads, implementations of the KIFACE.
60 
61  IFACE( const char* aName, KIWAY::FACE_T aType ) :
62  KIFACE_I( aName, aType )
63  {}
64 
65  bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
66 
67  void OnKifaceEnd() override;
68 
69  wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) override
70  {
71  switch( aClassId )
72  {
73  case FRAME_SCH:
74  {
75  SCH_EDIT_FRAME* frame = new SCH_EDIT_FRAME( aKiway, aParent );
76 
77  if( Kiface().IsSingle() )
78  {
79  // only run this under single_top, not under a project manager.
81  }
82 
83  return frame;
84  }
85 
87  {
88  LIB_EDIT_FRAME* frame = new LIB_EDIT_FRAME( aKiway, aParent );
89  return frame;
90  }
91 
92 #ifdef KICAD_SPICE
93  case FRAME_SIMULATOR:
94  {
95  SIM_PLOT_FRAME* frame = new SIM_PLOT_FRAME( aKiway, aParent );
96  return frame;
97  }
98 #endif
99  case FRAME_SCH_VIEWER:
101  {
102  LIB_VIEW_FRAME* frame = new LIB_VIEW_FRAME( aKiway, aParent, FRAME_T( aClassId ) );
103  return frame;
104  }
105 
107  InvokeSchEditSymbolLibTable( aKiway, aParent );
108  // Dialog has completed; nothing to return.
109  return nullptr;
110 
111  default:
112  return NULL;
113  }
114  }
115 
124  void* IfaceOrAddress( int aDataId ) override
125  {
126  return NULL;
127  }
128 
135  void SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
136  const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
137  const wxString& aSrcFilePath, wxString& aErrors ) override;
138 
139 } kiface( "eeschema", KIWAY::FACE_SCH );
140 
141 } // namespace
142 
143 using namespace SCH;
144 
146 
147 
148 KIFACE_I& Kiface() { return kiface; }
149 
150 
151 // KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h.
152 // KIFACE_GETTER will not have name mangling due to declaration in kiway.h.
153 MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram )
154 {
155  process = aProgram;
156  return &kiface;
157 }
158 
159 
161 {
162  wxASSERT( process ); // KIFACE_GETTER has already been called.
163  return *process;
164 }
165 
166 // Similar to PGM_BASE& Pgm(), but return nullptr when a *.ki_face is run from
167 // a python script or something else.
169 {
170  return process;
171 }
172 
173 
174 bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
175 {
176  // This is process-level-initialization, not project-level-initialization of the DSO.
177  // Do nothing in here pertinent to a project!
180 
181  start_common( aCtlBits );
182 
184 
185  if( !fn.FileExists() )
186  {
188 
189  fpDialog.ShowModal();
190  }
191  else
192  {
193  try
194  {
195  // The global table is not related to a specific project. All projects
196  // will use the same global table. So the KIFACE::OnKifaceStart() contract
197  // of avoiding anything project specific is not violated here.
199  return false;
200  }
201  catch( const IO_ERROR& ioe )
202  {
203  // if we are here, a incorrect global symbol library table was found.
204  // Incorrect global symbol library table is not a fatal error:
205  // the user just has to edit the (partially) loaded table.
206  wxString msg = _(
207  "An error occurred attempting to load the global symbol library table.\n"
208  "Please edit this global symbol library table in Preferences menu."
209  );
210 
211  DisplayErrorMessage( NULL, msg, ioe.What() );
212  }
213  }
214 
215  return true;
216 }
217 
218 
220 {
221  end_common();
222 }
223 
224 static void traverseSEXPR( SEXPR::SEXPR* aNode,
225  const std::function<void( SEXPR::SEXPR* )>& aVisitor )
226 {
227  aVisitor( aNode );
228 
229  if( aNode->IsList() )
230  {
231  for( unsigned i = 0; i < aNode->GetNumberOfChildren(); i++ )
232  traverseSEXPR( aNode->GetChild( i ), aVisitor );
233  }
234 }
235 
236 
237 void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
238  const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
239  const wxString& aSrcFilePath, wxString& aErrors )
240 {
241  wxFileName destFile( aSrcFilePath );
242  wxString destPath = destFile.GetPathWithSep();
243  wxUniChar pathSep = wxFileName::GetPathSeparator();
244  wxString ext = destFile.GetExt();
245 
246  if( destPath.StartsWith( aProjectBasePath + pathSep ) )
247  destPath.Replace( aProjectBasePath, aNewProjectBasePath, false );
249  destFile.SetPath( destPath );
250 
251  if( ext == "sch" || ext == "sch-bak" || ext == "kicad_sch" || ext == "kicad_sch-bak" )
252  {
253  if( destFile.GetName() == aProjectName )
254  destFile.SetName( aNewProjectName );
255 
256  // Sheet paths when auto-generated are relative to the root, so those will stay
257  // pointing to whatever they were pointing at.
258  // The author can create their own absolute and relative sheet paths. Absolute
259  // sheet paths aren't an issue, and relative ones will continue to work as long
260  // as the author didn't include any '..'s. If they did, it's still not clear
261  // whether they should be adjusted or not (as the author may be duplicating an
262  // entire tree with several projects within it), so we leave this as an exercise
263  // to the author.
264 
265  CopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
266  }
267  else if( ext == "sym" )
268  {
269  // Symbols are not project-specific. Keep their source names.
270  CopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
271  }
272  else if( ext == "lib" || ext == "dcm" || ext == "kicad_sym" )
273  {
274  if( destFile.GetName() == aProjectName + "-cache" )
275  destFile.SetName( aNewProjectName + "-cache" );
276 
277  CopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
278  }
279  else if( ext == "net" )
280  {
281  bool success = false;
282 
283  if( destFile.GetName() == aProjectName )
284  destFile.SetName( aNewProjectName );
285 
286  try
287  {
288  SEXPR::PARSER parser;
289  std::unique_ptr<SEXPR::SEXPR> sexpr( parser.ParseFromFile( TO_UTF8( aSrcFilePath ) ) );
290 
291  traverseSEXPR( sexpr.get(), [&]( SEXPR::SEXPR* node )
292  {
293  if( node->IsList() && node->GetNumberOfChildren() > 1
294  && node->GetChild( 0 )->IsSymbol()
295  && node->GetChild( 0 )->GetSymbol() == "source" )
296  {
297  auto pathNode = dynamic_cast<SEXPR::SEXPR_STRING*>( node->GetChild( 1 ) );
298  auto symNode = dynamic_cast<SEXPR::SEXPR_SYMBOL*>( node->GetChild( 1 ) );
299  wxString path;
300 
301  if( pathNode )
302  path = pathNode->m_value;
303  else if( symNode )
304  path = symNode->m_value;
305 
306  if( path == aProjectName + ".sch" )
307  path = aNewProjectName + ".sch";
308  else if( path == aProjectBasePath + "/" + aProjectName + ".sch" )
309  path = aNewProjectBasePath + "/" + aNewProjectName + ".sch";
310  else if( path.StartsWith( aProjectBasePath ) )
311  path.Replace( aProjectBasePath, aNewProjectBasePath, false );
312 
313  if( pathNode )
314  pathNode->m_value = path;
315  else if( symNode )
316  symNode->m_value = path;
317  }
318  } );
319 
320  wxFile destNetList( destFile.GetFullPath(), wxFile::write );
321 
322  if( destNetList.IsOpened() )
323  success = destNetList.Write( sexpr->AsString( 0 ) );
324 
325  // wxFile dtor will close the file
326  }
327  catch( ... )
328  {
329  success = false;
330  }
331 
332  if( !success )
333  {
334  wxString msg;
335 
336  if( !aErrors.empty() )
337  aErrors += "\n";
338 
339  msg.Printf( _( "Cannot copy file \"%s\"." ), destFile.GetFullPath() );
340  aErrors += msg;
341  }
342  }
343  else if( destFile.GetName() == "sym-lib-table" )
344  {
345  SYMBOL_LIB_TABLE symbolLibTable;
346  symbolLibTable.Load( aSrcFilePath );
347 
348  for( unsigned i = 0; i < symbolLibTable.GetCount(); i++ )
349  {
350  LIB_TABLE_ROW& row = symbolLibTable.At( i );
351  wxString uri = row.GetFullURI();
352 
353  uri.Replace( "/" + aProjectName + "-cache.lib", "/" + aNewProjectName + "-cache.lib" );
354  uri.Replace( "/" + aProjectName + "-rescue.lib", "/" + aNewProjectName + "-rescue.lib" );
355  uri.Replace( "/" + aProjectName + ".lib", "/" + aNewProjectName + ".lib" );
356 
357  row.SetFullURI( uri );
358  }
359 
360  try
361  {
362  symbolLibTable.Save( destFile.GetFullPath() );
363  }
364  catch( ... )
365  {
366  wxString msg;
367 
368  if( !aErrors.empty() )
369  aErrors += "\n";
370 
371  msg.Printf( _( "Cannot copy file \"%s\"." ), destFile.GetFullPath() );
372  aErrors += msg;
373  }
374  }
375  else
376  {
377  wxFAIL_MSG( "Unexpected filetype for Eeschema::SaveFileAs()" );
378  }
379 }
380 
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:89
Hold a record identifying a library accessed by the appropriate plug in object in the LIB_TABLE.
VTBL_ENTRY SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:175
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:252
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:137
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
unsigned GetCount() const
Get the number of rows contained in the table.
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.
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)
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_i.h:103
TRANSFORM DefaultTransform
Schematic editor (Eeschema) main window.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Symbol library viewer main window.
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
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:117
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:99
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 ...
SEXPR * GetChild(size_t aIndex) const
Definition: sexpr.cpp:48
Class LIB_PIN definition.
static PGM_BASE * process
KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the s...
Definition: kiway.h:273
static void traverseSEXPR(SEXPR::SEXPR *aNode, const std::function< void(SEXPR::SEXPR *)> &aVisitor)
Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder.
#define KIFACE_GETTER
Definition: kiway.h:112
void Load(const wxString &aFileName)
Load the library table using the path defined by aFileName aFallBackTable.
Implementing SIM_PLOT_FRAME_BASE.
FACE_T
Known KIFACE implementations.
Definition: kiway.h:279
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:216
JSON_SETTINGS * RegisterSettings(JSON_SETTINGS *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
eeschema DSO
Definition: kiway.h:281
The symbol library editor main window.
void SetFullURI(const wxString &aFullURI)
Change the full URI for the library.
see class PGM_BASE
LIB_TABLE_ROW & At(unsigned aIndex)
Get the 'n'th LIB_TABLE_ROW object.
#define _(s)
Definition: 3d_actions.cpp:33
PGM_BASE * PgmOrNull()
similat to PGM_BASE& Pgm(), but return a reference that can be nullptr when running a shared lib from...
MY_API(KIFACE *) KIFACE_GETTER(int *aKIFACEversion
KIFACE is used by a participant in the KIWAY alchemy.
Definition: kiway.h:150
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
#define TO_UTF8(wxstring)
void InitSettings(APP_SETTINGS_BASE *aSettings)
Definition: kiface_i.h:105
SCH_SHEET * g_RootSheet
void CreateServer(int service, bool local=true)
Definition: eda_dde.cpp:49
size_t GetNumberOfChildren() const
Definition: sexpr.cpp:70
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)