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 <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 <lib_view_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 
47 #include <schematic.h>
48 #include <connection_graph.h>
49 
50 // The main sheet of the project
52 
53 // a transform matrix, to display components in lib editor
55 
56 
57 namespace SCH {
58 
59 
60 static std::unique_ptr<SCHEMATIC> readSchematicFromFile( const std::string& aFilename )
61 {
62  auto pi = SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD );
63  std::unique_ptr<SCHEMATIC> schematic = std::make_unique<SCHEMATIC>( nullptr );
64 
65  auto &manager = Pgm().GetSettingsManager();
66 
67  manager.LoadProject( "" );
68  schematic->Reset();
69  schematic->SetProject( &manager.Prj() );
70  schematic->SetRoot( pi->Load( aFilename, schematic.get() ) );
71  schematic->CurrentSheet().push_back( &schematic->Root() );
72 
73  SCH_SCREENS screens( schematic->Root() );
74 
75  for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
76  screen->UpdateLocalLibSymbolLinks();
77 
78  SCH_SHEET_LIST sheets = schematic->GetSheets();
79 
80  // Restore all of the loaded symbol instances from the root sheet screen.
81  sheets.UpdateSymbolInstances( schematic->RootScreen()->GetSymbolInstances() );
82 
83  sheets.AnnotatePowerSymbols();
84 
85  // NOTE: This is required for multi-unit symbols to be correct
86  // Normally called from SCH_EDIT_FRAME::FixupJunctions() but could be refactored
87  for( SCH_SHEET_PATH& sheet : sheets )
88  sheet.UpdateAllScreenReferences();
89 
90  // NOTE: SchematicCleanUp is not called; QA schematics must already be clean or else
91  // SchematicCleanUp must be freed from its UI dependencies.
92 
93  schematic->ConnectionGraph()->Recalculate( sheets, true );
94 
95  return schematic;
96 }
97 
98 
99 bool generateSchematicNetlist( const wxString& aFilename, wxString& aNetlist )
100 {
101  std::unique_ptr<SCHEMATIC> schematic = readSchematicFromFile( aFilename.ToStdString() );
102  NETLIST_EXPORTER_KICAD exporter( schematic.get() );
103  STRING_FORMATTER formatter;
104 
105  exporter.Format( &formatter, GNL_ALL | GNL_OPT_KICAD );
106  aNetlist = formatter.GetString();
107 
108  return true;
109 }
111 
112 static struct IFACE : public KIFACE_I
113 {
114  // Of course all are virtual overloads, implementations of the KIFACE.
115 
116  IFACE( const char* aName, KIWAY::FACE_T aType ) :
117  KIFACE_I( aName, aType )
118  {}
119 
120  bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
121 
122  void OnKifaceEnd() override;
123 
124  wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) override
125  {
126  switch( aClassId )
127  {
128  case FRAME_SCH:
129  {
130  SCH_EDIT_FRAME* frame = new SCH_EDIT_FRAME( aKiway, aParent );
131 
132  if( Kiface().IsSingle() )
133  {
134  // only run this under single_top, not under a project manager.
136  }
137 
138  return frame;
139  }
140 
142  {
143  SYMBOL_EDIT_FRAME* frame = new SYMBOL_EDIT_FRAME( aKiway, aParent );
144  return frame;
145  }
146 
147 #ifdef KICAD_SPICE
148  case FRAME_SIMULATOR:
149  {
150  SIM_PLOT_FRAME* frame = new SIM_PLOT_FRAME( aKiway, aParent );
151  return frame;
152  }
153 #endif
154  case FRAME_SCH_VIEWER:
156  {
157  LIB_VIEW_FRAME* frame = new LIB_VIEW_FRAME( aKiway, aParent, FRAME_T( aClassId ) );
158  return frame;
159  }
160 
162  InvokeSchEditSymbolLibTable( aKiway, aParent );
163  // Dialog has completed; nothing to return.
164  return nullptr;
166  default:
167  return NULL;
168  }
169  }
170 
179  void* IfaceOrAddress( int aDataId ) override
180  {
181  switch( aDataId )
182  {
184  return (void*) generateSchematicNetlist;
185  }
186  return NULL;
187  }
188 
195  void SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
196  const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
197  const wxString& aSrcFilePath, wxString& aErrors ) override;
198 
199 } kiface( "eeschema", KIWAY::FACE_SCH );
200 
201 } // namespace
202 
203 using namespace SCH;
204 
206 
207 
208 KIFACE_I& Kiface() { return kiface; }
209 
210 
211 // KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h.
212 // KIFACE_GETTER will not have name mangling due to declaration in kiway.h.
213 MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram )
214 {
215  process = aProgram;
216  return &kiface;
217 }
218 
219 
221 {
222  wxASSERT( process ); // KIFACE_GETTER has already been called.
223  return *process;
224 }
225 
226 // Similar to PGM_BASE& Pgm(), but return nullptr when a *.ki_face is run from
227 // a python script or something else.
229 {
230  return process;
231 }
232 
233 
234 bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
235 {
236  // This is process-level-initialization, not project-level-initialization of the DSO.
237  // Do nothing in here pertinent to a project!
240 
241  start_common( aCtlBits );
242 
244 
245  if( !fn.FileExists() )
246  {
248 
249  fpDialog.ShowModal();
250  }
251  else
252  {
253  try
254  {
255  // The global table is not related to a specific project. All projects
256  // will use the same global table. So the KIFACE::OnKifaceStart() contract
257  // of avoiding anything project specific is not violated here.
259  return false;
260  }
261  catch( const IO_ERROR& ioe )
262  {
263  // if we are here, a incorrect global symbol library table was found.
264  // Incorrect global symbol library table is not a fatal error:
265  // the user just has to edit the (partially) loaded table.
266  wxString msg = _(
267  "An error occurred attempting to load the global symbol library table.\n"
268  "Please edit this global symbol library table in Preferences menu."
269  );
270 
271  DisplayErrorMessage( NULL, msg, ioe.What() );
272  }
273  }
274 
275  return true;
276 }
277 
278 
280 {
281  end_common();
282 }
283 
284 static void traverseSEXPR( SEXPR::SEXPR* aNode,
285  const std::function<void( SEXPR::SEXPR* )>& aVisitor )
286 {
287  aVisitor( aNode );
288 
289  if( aNode->IsList() )
290  {
291  for( unsigned i = 0; i < aNode->GetNumberOfChildren(); i++ )
292  traverseSEXPR( aNode->GetChild( i ), aVisitor );
293  }
294 }
295 
296 
297 void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
298  const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
299  const wxString& aSrcFilePath, wxString& aErrors )
300 {
301  wxFileName destFile( aSrcFilePath );
302  wxString destPath = destFile.GetPathWithSep();
303  wxUniChar pathSep = wxFileName::GetPathSeparator();
304  wxString ext = destFile.GetExt();
305 
306  if( destPath.StartsWith( aProjectBasePath + pathSep ) )
307  destPath.Replace( aProjectBasePath, aNewProjectBasePath, false );
308 
309  destFile.SetPath( destPath );
310 
311  if( ext == "sch" || ext == "sch-bak" || ext == "kicad_sch" || ext == "kicad_sch-bak" )
312  {
313  if( destFile.GetName() == aProjectName )
314  destFile.SetName( aNewProjectName );
315 
316  // Sheet paths when auto-generated are relative to the root, so those will stay
317  // pointing to whatever they were pointing at.
318  // The author can create their own absolute and relative sheet paths. Absolute
319  // sheet paths aren't an issue, and relative ones will continue to work as long
320  // as the author didn't include any '..'s. If they did, it's still not clear
321  // whether they should be adjusted or not (as the author may be duplicating an
322  // entire tree with several projects within it), so we leave this as an exercise
323  // to the author.
324 
325  KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
326  }
327  else if( ext == "sym" )
328  {
329  // Symbols are not project-specific. Keep their source names.
330  KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
331  }
332  else if( ext == "lib" || ext == "dcm" || ext == "kicad_sym" )
333  {
334  if( destFile.GetName() == aProjectName + "-cache" )
335  destFile.SetName( aNewProjectName + "-cache" );
336 
337  KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
338  }
339  else if( ext == "net" )
340  {
341  bool success = false;
342 
343  if( destFile.GetName() == aProjectName )
344  destFile.SetName( aNewProjectName );
345 
346  try
347  {
348  SEXPR::PARSER parser;
349  std::unique_ptr<SEXPR::SEXPR> sexpr( parser.ParseFromFile( TO_UTF8( aSrcFilePath ) ) );
350 
351  traverseSEXPR( sexpr.get(), [&]( SEXPR::SEXPR* node )
352  {
353  if( node->IsList() && node->GetNumberOfChildren() > 1
354  && node->GetChild( 0 )->IsSymbol()
355  && node->GetChild( 0 )->GetSymbol() == "source" )
356  {
357  auto pathNode = dynamic_cast<SEXPR::SEXPR_STRING*>( node->GetChild( 1 ) );
358  auto symNode = dynamic_cast<SEXPR::SEXPR_SYMBOL*>( node->GetChild( 1 ) );
359  wxString path;
360 
361  if( pathNode )
362  path = pathNode->m_value;
363  else if( symNode )
364  path = symNode->m_value;
365 
366  if( path == aProjectName + ".sch" )
367  path = aNewProjectName + ".sch";
368  else if( path == aProjectBasePath + "/" + aProjectName + ".sch" )
369  path = aNewProjectBasePath + "/" + aNewProjectName + ".sch";
370  else if( path.StartsWith( aProjectBasePath ) )
371  path.Replace( aProjectBasePath, aNewProjectBasePath, false );
372 
373  if( pathNode )
374  pathNode->m_value = path;
375  else if( symNode )
376  symNode->m_value = path;
377  }
378  } );
379 
380  wxFile destNetList( destFile.GetFullPath(), wxFile::write );
381 
382  if( destNetList.IsOpened() )
383  success = destNetList.Write( sexpr->AsString( 0 ) );
384 
385  // wxFile dtor will close the file
386  }
387  catch( ... )
388  {
389  success = false;
390  }
391 
392  if( !success )
393  {
394  wxString msg;
395 
396  if( !aErrors.empty() )
397  aErrors += "\n";
398 
399  msg.Printf( _( "Cannot copy file \"%s\"." ), destFile.GetFullPath() );
400  aErrors += msg;
401  }
402  }
403  else if( destFile.GetName() == "sym-lib-table" )
404  {
405  SYMBOL_LIB_TABLE symbolLibTable;
406  symbolLibTable.Load( aSrcFilePath );
407 
408  for( unsigned i = 0; i < symbolLibTable.GetCount(); i++ )
409  {
410  LIB_TABLE_ROW& row = symbolLibTable.At( i );
411  wxString uri = row.GetFullURI();
412 
413  uri.Replace( "/" + aProjectName + "-cache.lib", "/" + aNewProjectName + "-cache.lib" );
414  uri.Replace( "/" + aProjectName + "-rescue.lib", "/" + aNewProjectName + "-rescue.lib" );
415  uri.Replace( "/" + aProjectName + ".lib", "/" + aNewProjectName + ".lib" );
416 
417  row.SetFullURI( uri );
418  }
419 
420  try
421  {
422  symbolLibTable.Save( destFile.GetFullPath() );
423  }
424  catch( ... )
425  {
426  wxString msg;
427 
428  if( !aErrors.empty() )
429  aErrors += "\n";
430 
431  msg.Printf( _( "Cannot copy file \"%s\"." ), destFile.GetFullPath() );
432  aErrors += msg;
433  }
434  }
435  else
436  {
437  wxFAIL_MSG( "Unexpected filetype for Eeschema::SaveFileAs()" );
438  }
439 }
440 
SCH::IFACE KIFACE_I kiface("eeschema", KIWAY::FACE_SCH)
PGM_BASE & Pgm()
The global Program "get" accessor.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
static std::unique_ptr< SCHEMATIC > readSchematicFromFile(const std::string &aFilename)
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:88
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:253
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
IFACE(const char *aName, KIWAY::FACE_T aType)
void KiCopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
Function CopyFile.
Definition: gestfich.cpp:363
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_i.h:103
TRANSFORM DefaultTransform
bool generateSchematicNetlist(const wxString &aFilename, wxString &aNetlist)
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
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:95
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:29
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 ...
SEXPR * GetChild(size_t aIndex) const
Definition: sexpr.cpp:48
Generate the KiCad netlist format supported by Pcbnew.
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
const std::string & GetString()
Definition: richio.h:476
#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.
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:219
JSON_SETTINGS * RegisterSettings(JSON_SETTINGS *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
eeschema DSO
Definition: kiway.h:281
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
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.
void InitSettings(APP_SETTINGS_BASE *aSettings)
Definition: kiface_i.h:105
void AnnotatePowerSymbols()
Silently annotate the not yet annotated power symbols of the entire hierarchy of the sheet path list.
SCH_SHEET * g_RootSheet
void CreateServer(int service, bool local=true)
Definition: eda_dde.cpp:48
size_t GetNumberOfChildren() const
Definition: sexpr.cpp:70
STRING_FORMATTER implements OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:446
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)
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:521
The symbol library editor main window.