KiCad PCB EDA Suite
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 <pgm_base.h>
27 #include <kiface_i.h>
28 #include <confirm.h>
29 #include <gestfich.h>
30 #include <eda_dde.h>
31 #include <eeschema_settings.h>
32 #include <sch_edit_frame.h>
33 #include <symbol_edit_frame.h>
34 #include <symbol_viewer_frame.h>
35 #include <transform.h>
36 #include <symbol_lib_table.h>
39 #include <kiway.h>
40 #include <sim/sim_plot_frame.h>
42 #include <sexpr/sexpr.h>
43 #include <sexpr/sexpr_parser.h>
44 #include <kiface_ids.h>
46 #include <wx/ffile.h>
48 
49 #include <schematic.h>
50 #include <connection_graph.h>
51 
52 // The main sheet of the project
54 
55 // a transform matrix, to display components in lib editor
57 
58 
59 namespace SCH {
60 
61 
62 static std::unique_ptr<SCHEMATIC> readSchematicFromFile( const std::string& aFilename )
63 {
64  auto pi = SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD );
65  std::unique_ptr<SCHEMATIC> schematic = std::make_unique<SCHEMATIC>( nullptr );
66 
67  auto &manager = Pgm().GetSettingsManager();
68 
69  manager.LoadProject( "" );
70  schematic->Reset();
71  schematic->SetProject( &manager.Prj() );
72  schematic->SetRoot( pi->Load( aFilename, schematic.get() ) );
73  schematic->CurrentSheet().push_back( &schematic->Root() );
74 
75  SCH_SCREENS screens( schematic->Root() );
76 
77  for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
78  screen->UpdateLocalLibSymbolLinks();
79 
80  SCH_SHEET_LIST sheets = schematic->GetSheets();
81 
82  // Restore all of the loaded symbol instances from the root sheet screen.
83  sheets.UpdateSymbolInstances( schematic->RootScreen()->GetSymbolInstances() );
84 
85  sheets.AnnotatePowerSymbols();
86 
87  // NOTE: This is required for multi-unit symbols to be correct
88  // Normally called from SCH_EDIT_FRAME::FixupJunctions() but could be refactored
89  for( SCH_SHEET_PATH& sheet : sheets )
90  sheet.UpdateAllScreenReferences();
91 
92  // NOTE: SchematicCleanUp is not called; QA schematics must already be clean or else
93  // SchematicCleanUp must be freed from its UI dependencies.
94 
95  schematic->ConnectionGraph()->Recalculate( sheets, true );
96 
97  return schematic;
98 }
99 
100 
101 bool generateSchematicNetlist( const wxString& aFilename, wxString& aNetlist )
102 {
103  std::unique_ptr<SCHEMATIC> schematic = readSchematicFromFile( aFilename.ToStdString() );
104  NETLIST_EXPORTER_KICAD exporter( schematic.get() );
105  STRING_FORMATTER formatter;
106 
107  exporter.Format( &formatter, GNL_ALL | GNL_OPT_KICAD );
108  aNetlist = formatter.GetString();
109 
110  return true;
111 }
113 
114 static struct IFACE : public KIFACE_I
115 {
116  // Of course all are virtual overloads, implementations of the KIFACE.
117 
118  IFACE( const char* aName, KIWAY::FACE_T aType ) :
119  KIFACE_I( aName, aType )
120  {}
121 
122  bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
123 
124  void OnKifaceEnd() override;
125 
126  wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) override
127  {
128  switch( aClassId )
129  {
130  case FRAME_SCH:
131  {
132  SCH_EDIT_FRAME* frame = new SCH_EDIT_FRAME( aKiway, aParent );
133 
134  if( Kiface().IsSingle() )
135  {
136  // only run this under single_top, not under a project manager.
138  }
139 
140  return frame;
141  }
142 
144  {
145  SYMBOL_EDIT_FRAME* frame = new SYMBOL_EDIT_FRAME( aKiway, aParent );
146  return frame;
147  }
148 
149 #ifdef KICAD_SPICE
150  case FRAME_SIMULATOR:
151  {
152  SIM_PLOT_FRAME* frame = new SIM_PLOT_FRAME( aKiway, aParent );
153  return frame;
154  }
155 #endif
156  case FRAME_SCH_VIEWER:
158  {
159  SYMBOL_VIEWER_FRAME* frame = new SYMBOL_VIEWER_FRAME( aKiway, aParent,
160  FRAME_T( aClassId ) );
161  return frame;
162  }
163 
165  InvokeSchEditSymbolLibTable( aKiway, aParent );
166  // Dialog has completed; nothing to return.
167  return nullptr;
169  default:
170  return NULL;
171  }
172  }
173 
182  void* IfaceOrAddress( int aDataId ) override
183  {
184  switch( aDataId )
185  {
187  return (void*) generateSchematicNetlist;
188  }
189  return NULL;
190  }
191 
198  void SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
199  const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
200  const wxString& aSrcFilePath, wxString& aErrors ) override;
201 
202 } kiface( "eeschema", KIWAY::FACE_SCH );
203 
204 } // namespace
205 
206 using namespace SCH;
207 
209 
210 
211 KIFACE_I& Kiface() { return kiface; }
212 
213 
214 // KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h.
215 // KIFACE_GETTER will not have name mangling due to declaration in kiway.h.
216 MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram )
217 {
218  process = aProgram;
219  return &kiface;
220 }
221 
222 
224 {
225  wxASSERT( process ); // KIFACE_GETTER has already been called.
226  return *process;
227 }
228 
229 // Similar to PGM_BASE& Pgm(), but return nullptr when a *.ki_face is run from
230 // a python script or something else.
232 {
233  return process;
234 }
235 
236 
237 bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
238 {
239  // This is process-level-initialization, not project-level-initialization of the DSO.
240  // Do nothing in here pertinent to a project!
243 
244  start_common( aCtlBits );
245 
247 
248  if( !fn.FileExists() )
249  {
251 
252  fpDialog.ShowModal();
253  }
254  else
255  {
256  try
257  {
258  // The global table is not related to a specific project. All projects
259  // will use the same global table. So the KIFACE::OnKifaceStart() contract
260  // of avoiding anything project specific is not violated here.
262  return false;
263  }
264  catch( const IO_ERROR& ioe )
265  {
266  // if we are here, a incorrect global symbol library table was found.
267  // Incorrect global symbol library table is not a fatal error:
268  // the user just has to edit the (partially) loaded table.
269  wxString msg = _(
270  "An error occurred attempting to load the global symbol library table.\n"
271  "Please edit this global symbol library table in Preferences menu."
272  );
273 
274  DisplayErrorMessage( NULL, msg, ioe.What() );
275  }
276  }
277 
278  return true;
279 }
280 
281 
283 {
284  end_common();
285 }
286 
287 static void traverseSEXPR( SEXPR::SEXPR* aNode,
288  const std::function<void( SEXPR::SEXPR* )>& aVisitor )
289 {
290  aVisitor( aNode );
291 
292  if( aNode->IsList() )
293  {
294  for( unsigned i = 0; i < aNode->GetNumberOfChildren(); i++ )
295  traverseSEXPR( aNode->GetChild( i ), aVisitor );
296  }
297 }
298 
299 
300 void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
301  const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
302  const wxString& aSrcFilePath, wxString& aErrors )
303 {
304  wxFileName destFile( aSrcFilePath );
305  wxString destPath = destFile.GetPathWithSep();
306  wxUniChar pathSep = wxFileName::GetPathSeparator();
307  wxString ext = destFile.GetExt();
308 
309  if( destPath.StartsWith( aProjectBasePath + pathSep ) )
310  destPath.Replace( aProjectBasePath, aNewProjectBasePath, false );
311 
312  destFile.SetPath( destPath );
313 
316  {
317  if( destFile.GetName() == aProjectName )
318  destFile.SetName( aNewProjectName );
319 
320  // Sheet paths when auto-generated are relative to the root, so those will stay
321  // pointing to whatever they were pointing at.
322  // The author can create their own absolute and relative sheet paths. Absolute
323  // sheet paths aren't an issue, and relative ones will continue to work as long
324  // as the author didn't include any '..'s. If they did, it's still not clear
325  // whether they should be adjusted or not (as the author may be duplicating an
326  // entire tree with several projects within it), so we leave this as an exercise
327  // to the author.
328 
329  KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
330  }
331  else if( ext == SchematicSymbolFileExtension )
332  {
333  // Symbols are not project-specific. Keep their source names.
334  KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
335  }
338  {
339  if( destFile.GetName() == aProjectName + "-cache" )
340  destFile.SetName( aNewProjectName + "-cache" );
341 
342  KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
343  }
344  else if( ext == NetlistFileExtension )
345  {
346  bool success = false;
347 
348  if( destFile.GetName() == aProjectName )
349  destFile.SetName( aNewProjectName );
350 
351  try
352  {
353  SEXPR::PARSER parser;
354  std::unique_ptr<SEXPR::SEXPR> sexpr( parser.ParseFromFile( TO_UTF8( aSrcFilePath ) ) );
355 
356  traverseSEXPR( sexpr.get(), [&]( SEXPR::SEXPR* node )
357  {
358  if( node->IsList() && node->GetNumberOfChildren() > 1
359  && node->GetChild( 0 )->IsSymbol()
360  && node->GetChild( 0 )->GetSymbol() == "source" )
361  {
362  auto pathNode = dynamic_cast<SEXPR::SEXPR_STRING*>( node->GetChild( 1 ) );
363  auto symNode = dynamic_cast<SEXPR::SEXPR_SYMBOL*>( node->GetChild( 1 ) );
364  wxString path;
365 
366  if( pathNode )
367  path = pathNode->m_value;
368  else if( symNode )
369  path = symNode->m_value;
370 
371  if( path == aProjectName + ".sch" )
372  path = aNewProjectName + ".sch";
373  else if( path == aProjectBasePath + "/" + aProjectName + ".sch" )
374  path = aNewProjectBasePath + "/" + aNewProjectName + ".sch";
375  else if( path.StartsWith( aProjectBasePath ) )
376  path.Replace( aProjectBasePath, aNewProjectBasePath, false );
377 
378  if( pathNode )
379  pathNode->m_value = path;
380  else if( symNode )
381  symNode->m_value = path;
382  }
383  } );
384 
385  wxFFile destNetList( destFile.GetFullPath(), "wb" );
386 
387  if( destNetList.IsOpened() )
388  success = destNetList.Write( sexpr->AsString( 0 ) );
389 
390  // wxFFile dtor will close the file
391  }
392  catch( ... )
393  {
394  success = false;
395  }
396 
397  if( !success )
398  {
399  wxString msg;
400 
401  if( !aErrors.empty() )
402  aErrors += "\n";
403 
404  msg.Printf( _( "Cannot copy file \"%s\"." ), destFile.GetFullPath() );
405  aErrors += msg;
406  }
407  }
408  else if( destFile.GetName() == "sym-lib-table" )
409  {
410  SYMBOL_LIB_TABLE symbolLibTable;
411  symbolLibTable.Load( aSrcFilePath );
412 
413  for( unsigned i = 0; i < symbolLibTable.GetCount(); i++ )
414  {
415  LIB_TABLE_ROW& row = symbolLibTable.At( i );
416  wxString uri = row.GetFullURI();
417 
418  uri.Replace( "/" + aProjectName + "-cache.lib", "/" + aNewProjectName + "-cache.lib" );
419  uri.Replace( "/" + aProjectName + "-rescue.lib", "/" + aNewProjectName + "-rescue.lib" );
420  uri.Replace( "/" + aProjectName + ".lib", "/" + aNewProjectName + ".lib" );
421 
422  row.SetFullURI( uri );
423  }
424 
425  try
426  {
427  symbolLibTable.Save( destFile.GetFullPath() );
428  }
429  catch( ... )
430  {
431  wxString msg;
432 
433  if( !aErrors.empty() )
434  aErrors += "\n";
435 
436  msg.Printf( _( "Cannot copy file \"%s\"." ), destFile.GetFullPath() );
437  aErrors += msg;
438  }
439  }
440  else
441  {
442  wxFAIL_MSG( "Unexpected filetype for Eeschema::SaveFileAs()" );
443  }
444 }
445 
const std::string NetlistFileExtension
static void traverseSEXPR(SEXPR::SEXPR *aNode, const std::function< void(SEXPR::SEXPR *)> &aVisitor)
Definition: eeschema.cpp:287
SCH::IFACE KIFACE_I kiface("eeschema", KIWAY::FACE_SCH)
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:167
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
static std::unique_ptr< SCHEMATIC > readSchematicFromFile(const std::string &aFilename)
Definition: eeschema.cpp:62
static SYMBOL_LIB_TABLE & GetGlobalLibTable()
A KIFACE (I)mplementation.
Definition: kiface_i.h:37
DDE server & client.
bool start_common(int aCtlBits)
Common things to do for a top program module, during OnKifaceStart().
Definition: kiface_i.cpp:88
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:266
This file is part of the common library TODO brief description.
This file is part of the common library.
int aKiwayVersion
Definition: eeschema.cpp:216
void OnKifaceEnd() override
Called just once just before the DSO is to be unloaded.
Definition: eeschema.cpp:282
Container for data for KiCad programs.
Definition: pgm_base.h:131
const std::string LegacySymbolLibFileExtension
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition: frame_type.h:32
std::unique_ptr< SEXPR > ParseFromFile(const std::string &aFilename)
const std::string BackupFileSuffix
unsigned GetCount() const
Get the number of rows contained in the table.
wxWindow * CreateWindow(wxWindow *aParent, int aClassId, KIWAY *aKiway, int aCtlBits=0) override
Create a wxWindow for the current project.
Definition: eeschema.cpp:126
void * IfaceOrAddress(int aDataId) override
Function IfaceOrAddress return a pointer to the requested object.
Definition: eeschema.cpp:182
void InvokeSchEditSymbolLibTable(KIWAY *aKiway, wxWindow *aParent)
bool IsList() const
Definition: sexpr.h:54
IFACE(const char *aName, KIWAY::FACE_T aType)
Definition: eeschema.cpp:118
void KiCopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
Definition: gestfich.cpp:363
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_i.h:92
const std::string SchematicSymbolFileExtension
Symbol library viewer main window.
bool generateSchematicNetlist(const wxString &aFilename, wxString &aNetlist)
Definition: eeschema.cpp:101
Schematic editor (Eeschema) main window.
int PGM_BASE * aProgram
Definition: eeschema.cpp:217
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...
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
PGM_BASE * PgmOrNull()
similar to PGM_BASE& Pgm(), but return a reference that can be nullptr when running a shared lib from...
Definition: eeschema.cpp:231
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
Typically start_common() is called from here.
Definition: eeschema.cpp:237
SCH_SHEET * g_RootSheet
Definition: eeschema.cpp:53
#define NULL
bool IsSingle() const
Is this KIFACE_I running under single_top?
Definition: kiface_i.h:104
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
Definition: eeschema.cpp:59
void end_common()
Common things to do for a top program module, during OnKifaceEnd();.
Definition: kiface_i.cpp:98
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 ...
Definition: eeschema.cpp:300
SEXPR * GetChild(size_t aIndex) const
Definition: sexpr.cpp:48
const std::string LegacySymbolDocumentFileExtension
Generate the KiCad netlist format supported by Pcbnew.
Definition of file extensions used in Kicad.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:260
Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder.
#define KIFACE_GETTER
Definition: kiway.h:109
const std::string & GetString()
Definition: richio.h:435
#define GNL_ALL
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void Load(const wxString &aFileName)
Load the library table using the path defined by aFileName aFallBackTable.
void UpdateSymbolInstances(const std::vector< SYMBOL_INSTANCE_REFERENCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
const std::string LegacySchematicFileExtension
Implementing SIM_PLOT_FRAME_BASE.
FACE_T
Known KIFACE implementations.
Definition: kiway.h:266
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:219
JSON_SETTINGS * RegisterSettings(JSON_SETTINGS *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
eeschema DSO
Definition: kiway.h:268
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Loads a project or sets up a new project with a specified path.
void SetFullURI(const wxString &aFullURI)
Change the full URI for the library.
see class PGM_BASE
TRANSFORM DefaultTransform
Definition: eeschema.cpp:56
LIB_TABLE_ROW & At(unsigned aIndex)
Get the 'n'th LIB_TABLE_ROW object.
MY_API(KIFACE *) KIFACE_GETTER(int *aKIFACEversion
#define _(s)
Definition: 3d_actions.cpp:33
Implement a participant in the KIWAY alchemy.
Definition: kiway.h:147
const std::string KiCadSchematicFileExtension
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
static PGM_BASE * process
Definition: eeschema.cpp:208
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: eeschema.cpp:211
void InitSettings(APP_SETTINGS_BASE *aSettings)
Definition: kiface_i.h:94
void AnnotatePowerSymbols()
Silently annotate the not yet annotated power symbols of the entire hierarchy of the sheet path list.
void CreateServer(int service, bool local=true)
Definition: eda_dde.cpp:48
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: eeschema.cpp:223
size_t GetNumberOfChildren() const
Definition: sexpr.cpp:70
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:411
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
static wxString GetGlobalTableFileName()
Fetch the global symbol library table file name.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:534
const std::string KiCadSymbolLibFileExtension
The symbol library editor main window.