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_base.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 symbols 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_BASE
115 {
116  // Of course all are virtual overloads, implementations of the KIFACE.
117 
118  IFACE( const char* aName, KIWAY::FACE_T aType ) :
119  KIFACE_BASE( 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,
127  int aCtlBits = 0 ) override
128  {
129  switch( aClassId )
130  {
131  case FRAME_SCH:
132  {
133  SCH_EDIT_FRAME* frame = new SCH_EDIT_FRAME( aKiway, aParent );
134 
135  if( Kiface().IsSingle() )
136  {
137  // only run this under single_top, not under a project manager.
139  }
140 
141  return frame;
142  }
143 
145  {
146  SYMBOL_EDIT_FRAME* frame = new SYMBOL_EDIT_FRAME( aKiway, aParent );
147  return frame;
148  }
149 
150 #ifdef KICAD_SPICE
151  case FRAME_SIMULATOR:
152  {
153  SIM_PLOT_FRAME* frame = new SIM_PLOT_FRAME( aKiway, aParent );
154  return frame;
155  }
156 #endif
157  case FRAME_SCH_VIEWER:
159  {
160  SYMBOL_VIEWER_FRAME* frame = new SYMBOL_VIEWER_FRAME( aKiway, aParent,
161  FRAME_T( aClassId ) );
162  return frame;
163  }
164 
166  InvokeSchEditSymbolLibTable( aKiway, aParent );
167  // Dialog has completed; nothing to return.
168  return nullptr;
169 
170  default:
171  return nullptr;
172  }
173  }
174 
185  void* IfaceOrAddress( int aDataId ) override
186  {
187  switch( aDataId )
188  {
190  return (void*) generateSchematicNetlist;
191  }
192 
193  return nullptr;
194  }
195 
201  void SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
202  const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
203  const wxString& aSrcFilePath, wxString& aErrors ) override;
204 
205 } kiface( "eeschema", KIWAY::FACE_SCH );
206 
207 } // namespace
208 
209 using namespace SCH;
210 
212 
213 
214 KIFACE_BASE& Kiface() { return kiface; }
215 
216 
217 // KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h.
218 // KIFACE_GETTER will not have name mangling due to declaration in kiway.h.
219 MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram )
220 {
221  process = aProgram;
222  return &kiface;
223 }
224 
225 
227 {
228  wxASSERT( process ); // KIFACE_GETTER has already been called.
229  return *process;
230 }
231 
232 // Similar to PGM_BASE& Pgm(), but return nullptr when a *.ki_face is run from
233 // a python script or something else.
235 {
236  return process;
237 }
238 
239 
240 bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
241 {
242  // This is process-level-initialization, not project-level-initialization of the DSO.
243  // Do nothing in here pertinent to a project!
246 
247  start_common( aCtlBits );
248 
250 
251  if( !fn.FileExists() )
252  {
253  DIALOG_GLOBAL_SYM_LIB_TABLE_CONFIG fpDialog( nullptr );
254 
255  fpDialog.ShowModal();
256  }
257  else
258  {
259  try
260  {
261  // The global table is not related to a specific project. All projects
262  // will use the same global table. So the KIFACE::OnKifaceStart() contract
263  // of avoiding anything project specific is not violated here.
265  return false;
266  }
267  catch( const IO_ERROR& ioe )
268  {
269  // if we are here, a incorrect global symbol library table was found.
270  // Incorrect global symbol library table is not a fatal error:
271  // the user just has to edit the (partially) loaded table.
272  wxString msg = _(
273  "An error occurred attempting to load the global symbol library table.\n"
274  "Please edit this global symbol library table in Preferences menu."
275  );
276 
277  DisplayErrorMessage( nullptr, msg, ioe.What() );
278  }
279  }
280 
281  return true;
282 }
283 
284 
286 {
287  end_common();
288 }
289 
290 
291 static void traverseSEXPR( SEXPR::SEXPR* aNode,
292  const std::function<void( SEXPR::SEXPR* )>& aVisitor )
293 {
294  aVisitor( aNode );
295 
296  if( aNode->IsList() )
297  {
298  for( unsigned i = 0; i < aNode->GetNumberOfChildren(); i++ )
299  traverseSEXPR( aNode->GetChild( i ), aVisitor );
300  }
301 }
302 
303 
304 void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
305  const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
306  const wxString& aSrcFilePath, wxString& aErrors )
307 {
308  wxFileName destFile( aSrcFilePath );
309  wxString destPath = destFile.GetPathWithSep();
310  wxUniChar pathSep = wxFileName::GetPathSeparator();
311  wxString ext = destFile.GetExt();
312 
313  if( destPath.StartsWith( aProjectBasePath + pathSep ) )
314  destPath.Replace( aProjectBasePath, aNewProjectBasePath, false );
315 
316  destFile.SetPath( destPath );
317 
318  if( ext == LegacySchematicFileExtension ||
322  {
323  if( destFile.GetName() == aProjectName )
324  destFile.SetName( aNewProjectName );
325 
326  // Sheet paths when auto-generated are relative to the root, so those will stay
327  // pointing to whatever they were pointing at.
328  // The author can create their own absolute and relative sheet paths. Absolute
329  // sheet paths aren't an issue, and relative ones will continue to work as long
330  // as the author didn't include any '..'s. If they did, it's still not clear
331  // whether they should be adjusted or not (as the author may be duplicating an
332  // entire tree with several projects within it), so we leave this as an exercise
333  // to the author.
334 
335  KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
336  }
337  else if( ext == SchematicSymbolFileExtension )
338  {
339  // Symbols are not project-specific. Keep their source names.
340  KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
341  }
344  {
345  if( destFile.GetName() == aProjectName + "-cache" )
346  destFile.SetName( aNewProjectName + "-cache" );
347 
348  KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
349  }
350  else if( ext == NetlistFileExtension )
351  {
352  bool success = false;
353 
354  if( destFile.GetName() == aProjectName )
355  destFile.SetName( aNewProjectName );
356 
357  try
358  {
359  SEXPR::PARSER parser;
360  std::unique_ptr<SEXPR::SEXPR> sexpr( parser.ParseFromFile( TO_UTF8( aSrcFilePath ) ) );
361 
362  traverseSEXPR( sexpr.get(), [&]( SEXPR::SEXPR* node )
363  {
364  if( node->IsList() && node->GetNumberOfChildren() > 1
365  && node->GetChild( 0 )->IsSymbol()
366  && node->GetChild( 0 )->GetSymbol() == "source" )
367  {
368  auto pathNode = dynamic_cast<SEXPR::SEXPR_STRING*>( node->GetChild( 1 ) );
369  auto symNode = dynamic_cast<SEXPR::SEXPR_SYMBOL*>( node->GetChild( 1 ) );
370  wxString path;
371 
372  if( pathNode )
373  path = pathNode->m_value;
374  else if( symNode )
375  path = symNode->m_value;
376 
377  if( path == aProjectName + ".sch" )
378  path = aNewProjectName + ".sch";
379  else if( path == aProjectBasePath + "/" + aProjectName + ".sch" )
380  path = aNewProjectBasePath + "/" + aNewProjectName + ".sch";
381  else if( path.StartsWith( aProjectBasePath ) )
382  path.Replace( aProjectBasePath, aNewProjectBasePath, false );
383 
384  if( pathNode )
385  pathNode->m_value = path;
386  else if( symNode )
387  symNode->m_value = path;
388  }
389  } );
390 
391  wxFFile destNetList( destFile.GetFullPath(), "wb" );
392 
393  if( destNetList.IsOpened() )
394  success = destNetList.Write( sexpr->AsString( 0 ) );
395 
396  // wxFFile dtor will close the file
397  }
398  catch( ... )
399  {
400  success = false;
401  }
402 
403  if( !success )
404  {
405  wxString msg;
406 
407  if( !aErrors.empty() )
408  aErrors += "\n";
409 
410  msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() );
411  aErrors += msg;
412  }
413  }
414  else if( destFile.GetName() == "sym-lib-table" )
415  {
416  SYMBOL_LIB_TABLE symbolLibTable;
417  symbolLibTable.Load( aSrcFilePath );
418 
419  for( unsigned i = 0; i < symbolLibTable.GetCount(); i++ )
420  {
421  LIB_TABLE_ROW& row = symbolLibTable.At( i );
422  wxString uri = row.GetFullURI();
423 
424  uri.Replace( "/" + aProjectName + "-cache.lib", "/" + aNewProjectName + "-cache.lib" );
425  uri.Replace( "/" + aProjectName + "-rescue.lib", "/" + aNewProjectName +
426  "-rescue.lib" );
427  uri.Replace( "/" + aProjectName + ".lib", "/" + aNewProjectName + ".lib" );
428 
429  row.SetFullURI( uri );
430  }
431 
432  try
433  {
434  symbolLibTable.Save( destFile.GetFullPath() );
435  }
436  catch( ... )
437  {
438  wxString msg;
439 
440  if( !aErrors.empty() )
441  aErrors += "\n";
442 
443  msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() );
444  aErrors += msg;
445  }
446  }
447  else
448  {
449  wxFAIL_MSG( "Unexpected filetype for Eeschema::SaveFileAs()" );
450  }
451 }
452 
const std::string NetlistFileExtension
static void traverseSEXPR(SEXPR::SEXPR *aNode, const std::function< void(SEXPR::SEXPR *)> &aVisitor)
Definition: eeschema.cpp:291
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:129
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()
DDE server & client.
Hold a record identifying a library accessed by the appropriate plug in object in the LIB_TABLE.
A KIFACE implementation.
Definition: kiface_base.h:37
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:284
T * RegisterSettings(T *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
This file is part of the common library.
int aKiwayVersion
Definition: eeschema.cpp:219
void OnKifaceEnd() override
Called just once just before the DSO is to be unloaded.
Definition: eeschema.cpp:285
Container for data for KiCad programs.
Definition: pgm_base.h:93
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
Return a pointer to the requested object.
Definition: eeschema.cpp:185
void end_common()
Common things to do for a top program module, during OnKifaceEnd();.
Definition: kiface_base.cpp:94
void InvokeSchEditSymbolLibTable(KIWAY *aKiway, wxWindow *aParent)
bool IsList() const
Definition: sexpr.h:49
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:334
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.
void CreateServer(int service, bool local=true)
Definition: eda_dde.cpp:43
int PGM_BASE * aProgram
Definition: eeschema.cpp:220
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...
void InitSettings(APP_SETTINGS_BASE *aSettings)
Definition: kiface_base.h:94
#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:234
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
Scripting window listens for commands for other apps.
Definition: eda_dde.h:43
bool OnKifaceStart(PGM_BASE *aProgram, int aCtlBits) override
Typically start_common() is called from here.
Definition: eeschema.cpp:240
SCH_SHEET * g_RootSheet
Definition: eeschema.cpp:53
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
Definition: eeschema.cpp:59
void SaveFileAs(const wxString &aProjectBasePath, const wxString &aProjectName, const wxString &aNewProjectBasePath, const wxString &aNewProjectName, const wxString &aSrcFilePath, wxString &aErrors) override
Saving a file under a different name is delegated to the various KIFACEs because the project doesn't ...
Definition: eeschema.cpp:304
SEXPR * GetChild(size_t aIndex) const
Definition: sexpr.cpp:48
bool start_common(int aCtlBits)
Common things to do for a top program module, during OnKifaceStart().
Definition: kiface_base.cpp:84
const std::string LegacySymbolDocumentFileExtension
Generate the KiCad netlist format supported by Pcbnew.
SCH::IFACE KIFACE_BASE kiface("eeschema", KIWAY::FACE_SCH)
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
#define _(s)
Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder.
#define KIFACE_GETTER
Definition: kiway.h:110
const std::string & GetString()
Definition: richio.h:438
#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:54
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
Implement a participant in the KIWAY alchemy.
Definition: kiway.h:148
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:211
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_base.h:92
void AnnotatePowerSymbols()
Silently annotate the not yet annotated power symbols of the entire hierarchy of the sheet path list.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: eeschema.cpp:226
size_t GetNumberOfChildren() const
Definition: sexpr.cpp:70
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:414
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.
bool IsSingle() const
Is this KIFACE running under single_top?
Definition: kiface_base.h:104
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:557
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition: eeschema.cpp:214
const std::string KiCadSymbolLibFileExtension
The symbol library editor main window.