KiCad PCB EDA Suite
sch_sexpr_plugin.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) 2020 CERN
5  * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Wayne Stambaugh <[email protected]>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <algorithm>
24 
25 // For some reason wxWidgets is built with wxUSE_BASE64 unset so expose the wxWidgets
26 // base64 code.
27 #define wxUSE_BASE64 1
28 #include <wx/base64.h>
29 #include <wx/log.h>
30 #include <wx/mstream.h>
31 #include <advanced_config.h>
32 #include <trace_helpers.h>
33 #include <locale_io.h>
34 #include <sch_bitmap.h>
35 #include <sch_bus_entry.h>
36 #include <sch_symbol.h>
37 #include <sch_edit_frame.h> // SYMBOL_ORIENTATION_T
38 #include <sch_junction.h>
39 #include <sch_line.h>
40 #include <sch_no_connect.h>
41 #include <sch_text.h>
42 #include <sch_sheet.h>
43 #include <sch_sheet_pin.h>
44 #include <schematic.h>
46 #include <sch_screen.h>
47 #include <symbol_library.h>
48 #include <lib_shape.h>
49 #include <lib_field.h>
50 #include <lib_pin.h>
51 #include <lib_text.h>
52 #include <eeschema_id.h> // for MAX_UNIT_COUNT_PER_PACKAGE definition
53 #include <sch_file_versions.h>
54 #include <schematic_lexer.h>
56 #include <symbol_lib_table.h> // for PropPowerSymsOnly definition.
57 #include <ee_selection.h>
58 #include <string_utils.h>
59 #include <wx_filename.h> // for ::ResolvePossibleSymlinks()
60 #include <progress_reporter.h>
61 
62 
63 using namespace TSCHEMATIC_T;
64 
65 
66 #define SCH_PARSE_ERROR( text, reader, pos ) \
67  THROW_PARSE_ERROR( text, reader.GetSource(), reader.Line(), \
68  reader.LineNumber(), pos - reader.Line() )
69 
70 
71 static const char* emptyString = "";
72 
76 static void formatFill( OUTPUTFORMATTER* aFormatter, int aNestLevel, FILL_T aFillMode,
77  const COLOR4D& aFillColor )
78 {
79  const char* fillType;
80 
81  switch( aFillMode )
82  {
83  default:
84  case FILL_T::NO_FILL: fillType = "none"; break;
85  case FILL_T::FILLED_SHAPE: fillType = "outline"; break;
86  case FILL_T::FILLED_WITH_BG_BODYCOLOR: fillType = "background"; break;
87  }
88 
89  aFormatter->Print( aNestLevel, "(fill (type %s))", fillType );
90 }
91 
92 
93 static const char* getPinElectricalTypeToken( ELECTRICAL_PINTYPE aType )
94 {
95  switch( aType )
96  {
98  return SCHEMATIC_LEXER::TokenName( T_input );
99 
101  return SCHEMATIC_LEXER::TokenName( T_output );
102 
104  return SCHEMATIC_LEXER::TokenName( T_bidirectional );
105 
107  return SCHEMATIC_LEXER::TokenName( T_tri_state );
108 
110  return SCHEMATIC_LEXER::TokenName( T_passive );
111 
113  return SCHEMATIC_LEXER::TokenName( T_free );
114 
116  return SCHEMATIC_LEXER::TokenName( T_unspecified );
117 
119  return SCHEMATIC_LEXER::TokenName( T_power_in );
120 
122  return SCHEMATIC_LEXER::TokenName( T_power_out );
123 
125  return SCHEMATIC_LEXER::TokenName( T_open_collector );
126 
128  return SCHEMATIC_LEXER::TokenName( T_open_emitter );
129 
131  return SCHEMATIC_LEXER::TokenName( T_no_connect );
132 
133  default:
134  wxFAIL_MSG( "Missing symbol library pin connection type" );
135  }
136 
137  return emptyString;
138 }
139 
140 
141 static const char* getPinShapeToken( GRAPHIC_PINSHAPE aShape )
142 {
143  switch( aShape )
144  {
146  return SCHEMATIC_LEXER::TokenName( T_line );
147 
149  return SCHEMATIC_LEXER::TokenName( T_inverted );
150 
152  return SCHEMATIC_LEXER::TokenName( T_clock );
153 
155  return SCHEMATIC_LEXER::TokenName( T_inverted_clock );
156 
158  return SCHEMATIC_LEXER::TokenName( T_input_low );
159 
161  return SCHEMATIC_LEXER::TokenName( T_clock_low );
162 
164  return SCHEMATIC_LEXER::TokenName( T_output_low );
165 
167  return SCHEMATIC_LEXER::TokenName( T_edge_clock_high );
168 
170  return SCHEMATIC_LEXER::TokenName( T_non_logic );
171 
172  default:
173  wxFAIL_MSG( "Missing symbol library pin shape type" );
174  }
175 
176  return emptyString;
177 }
178 
179 
180 static float getPinAngle( int aOrientation )
181 {
182  switch( aOrientation )
183  {
184  case PIN_RIGHT: return 0.0;
185  case PIN_LEFT: return 180.0;
186  case PIN_UP: return 90.0;
187  case PIN_DOWN: return 270.0;
188  default: wxFAIL_MSG( "Missing symbol library pin orientation type" ); return 0.0;
189  }
190 }
191 
192 
193 static const char* getSheetPinShapeToken( PINSHEETLABEL_SHAPE aShape )
194 {
195  switch( aShape )
196  {
197  case PINSHEETLABEL_SHAPE::PS_INPUT: return SCHEMATIC_LEXER::TokenName( T_input );
198  case PINSHEETLABEL_SHAPE::PS_OUTPUT: return SCHEMATIC_LEXER::TokenName( T_output );
199  case PINSHEETLABEL_SHAPE::PS_BIDI: return SCHEMATIC_LEXER::TokenName( T_bidirectional );
200  case PINSHEETLABEL_SHAPE::PS_TRISTATE: return SCHEMATIC_LEXER::TokenName( T_tri_state );
201  case PINSHEETLABEL_SHAPE::PS_UNSPECIFIED: return SCHEMATIC_LEXER::TokenName( T_passive );
202  default: wxFAIL; return SCHEMATIC_LEXER::TokenName( T_passive );
203  }
204 }
205 
206 
207 static double getSheetPinAngle( SHEET_SIDE aSide )
208 {
209  double retv;
210 
211  switch( aSide )
212  {
214  case SHEET_SIDE::LEFT: retv = 180.0; break;
215  case SHEET_SIDE::RIGHT: retv = 0.0; break;
216  case SHEET_SIDE::TOP: retv = 90.0; break;
217  case SHEET_SIDE::BOTTOM: retv = 270.0; break;
218  default: wxFAIL; retv = 0.0; break;
219  }
220 
221  return retv;
222 }
223 
224 
225 static wxString getLineStyleToken( PLOT_DASH_TYPE aStyle )
226 {
227  wxString token;
228 
229  switch( aStyle )
230  {
231  case PLOT_DASH_TYPE::DASH: token = "dash"; break;
232  case PLOT_DASH_TYPE::DOT: token = "dot"; break;
233  case PLOT_DASH_TYPE::DASHDOT: token = "dash_dot"; break;
234  case PLOT_DASH_TYPE::SOLID: token = "solid"; break;
235  case PLOT_DASH_TYPE::DEFAULT: token = "default"; break;
236  }
237 
238  return token;
239 }
240 
241 
242 static const char* getTextTypeToken( KICAD_T aType )
243 {
244  switch( aType )
245  {
246  case SCH_TEXT_T: return SCHEMATIC_LEXER::TokenName( T_text );
247  case SCH_LABEL_T: return SCHEMATIC_LEXER::TokenName( T_label );
248  case SCH_GLOBAL_LABEL_T: return SCHEMATIC_LEXER::TokenName( T_global_label );
249  case SCH_HIER_LABEL_T: return SCHEMATIC_LEXER::TokenName( T_hierarchical_label );
250  default: wxFAIL; return SCHEMATIC_LEXER::TokenName( T_text );
251  }
252 }
253 
254 
262 static void formatStroke( OUTPUTFORMATTER* aFormatter, int aNestLevel,
263  const STROKE_PARAMS& aStroke )
264 {
265  wxASSERT( aFormatter != nullptr );
266 
267  aFormatter->Print( aNestLevel, "(stroke (width %s) (type %s) (color %d %d %d %s))",
268  FormatInternalUnits( aStroke.GetWidth() ).c_str(),
269  TO_UTF8( getLineStyleToken( aStroke.GetPlotStyle() ) ),
270  KiROUND( aStroke.GetColor().r * 255.0 ),
271  KiROUND( aStroke.GetColor().g * 255.0 ),
272  KiROUND( aStroke.GetColor().b * 255.0 ),
273  Double2Str( aStroke.GetColor().a ).c_str() );
274 }
275 
276 
277 static void formatArc( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aArc, int x1, int x2,
278  const STROKE_PARAMS& aStroke, FILL_T aFillMode, const COLOR4D& aFillColor,
279  KIID aUuid = niluuid )
280 {
281  if( x1 > 1800 )
282  x1 -= 3600;
283 
284  if( x2 > 1800 )
285  x2 -= 3600;
286 
287  aFormatter->Print( aNestLevel, "(arc (start %s) (mid %s) (end %s)\n",
288  FormatInternalUnits( aArc->GetStart() ).c_str(),
289  FormatInternalUnits( aArc->GetArcMid() ).c_str(),
290  FormatInternalUnits( aArc->GetEnd() ).c_str() );
291 
292  formatStroke( aFormatter, aNestLevel + 1, aStroke );
293  aFormatter->Print( 0, "\n" );
294  formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
295  aFormatter->Print( 0, "\n" );
296 
297  if( aUuid != niluuid )
298  aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
299 
300  aFormatter->Print( aNestLevel, ")\n" );
301 }
302 
303 
304 static void formatCircle( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aCircle,
305  const STROKE_PARAMS& aStroke, FILL_T aFillMode, const COLOR4D& aFillColor,
306  KIID aUuid = niluuid )
307 {
308  aFormatter->Print( aNestLevel, "(circle (center %s %s) (radius %s)\n",
309  FormatInternalUnits( aCircle->GetStart().x ).c_str(),
310  FormatInternalUnits( aCircle->GetStart().y ).c_str(),
311  FormatInternalUnits( aCircle->GetRadius() ).c_str() );
312 
313  formatStroke( aFormatter, aNestLevel + 1, aStroke );
314  aFormatter->Print( 0, "\n" );
315  formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
316  aFormatter->Print( 0, "\n" );
317 
318  if( aUuid != niluuid )
319  aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
320 
321  aFormatter->Print( aNestLevel, ")\n" );
322 }
323 
324 
325 static void formatRect( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aRect,
326  const STROKE_PARAMS& aStroke, FILL_T aFillMode, const COLOR4D& aFillColor,
327  KIID aUuid = niluuid )
328 {
329  aFormatter->Print( aNestLevel, "(rectangle (start %s %s) (end %s %s)\n",
330  FormatInternalUnits( aRect->GetStart().x ).c_str(),
331  FormatInternalUnits( aRect->GetStart().y ).c_str(),
332  FormatInternalUnits( aRect->GetEnd().x ).c_str(),
333  FormatInternalUnits( aRect->GetEnd().y ).c_str() );
334  formatStroke( aFormatter, aNestLevel + 1, aStroke );
335  aFormatter->Print( 0, "\n" );
336  formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
337  aFormatter->Print( 0, "\n" );
338 
339  if( aUuid != niluuid )
340  aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
341 
342  aFormatter->Print( aNestLevel, ")\n" );
343 }
344 
345 
346 static void formatBezier( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aBezier,
347  const STROKE_PARAMS& aStroke, FILL_T aFillMode, const COLOR4D& aFillColor,
348  KIID aUuid = niluuid )
349 {
350  aFormatter->Print( aNestLevel, "(bezier (pts " );
351 
352  for( const wxPoint& pt : { aBezier->GetStart(), aBezier->GetBezierC1(),
353  aBezier->GetBezierC2(), aBezier->GetEnd() } )
354  {
355  aFormatter->Print( 0, " (xy %s %s)",
356  FormatInternalUnits( pt.x ).c_str(),
357  FormatInternalUnits( pt.y ).c_str() );
358  }
359 
360  aFormatter->Print( 0, ")\n" ); // Closes pts token on same line.
361 
362  formatStroke( aFormatter, aNestLevel + 1, aStroke );
363  aFormatter->Print( 0, "\n" );
364  formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
365  aFormatter->Print( 0, "\n" );
366 
367  if( aUuid != niluuid )
368  aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
369 
370  aFormatter->Print( aNestLevel, ")\n" );
371 }
372 
373 
374 static void formatPoly( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aPolyLine,
375  const STROKE_PARAMS& aStroke, FILL_T aFillMode, const COLOR4D& aFillColor,
376  KIID aUuid = niluuid )
377 {
378  int newLine = 0;
379  int lineCount = 1;
380  aFormatter->Print( aNestLevel, "(polyline\n" );
381  aFormatter->Print( aNestLevel + 1, "(pts" );
382 
383  for( const VECTOR2I& pt : aPolyLine->GetPolyShape().Outline( 0 ).CPoints() )
384  {
385  if( newLine == 4 || !ADVANCED_CFG::GetCfg().m_CompactSave )
386  {
387  aFormatter->Print( 0, "\n" );
388  aFormatter->Print( aNestLevel + 2, "(xy %s %s)",
389  FormatInternalUnits( pt.x ).c_str(),
390  FormatInternalUnits( pt.y ).c_str() );
391  newLine = 0;
392  lineCount += 1;
393  }
394  else
395  {
396  aFormatter->Print( 0, " (xy %s %s)",
397  FormatInternalUnits( pt.x ).c_str(),
398  FormatInternalUnits( pt.y ).c_str() );
399  }
400 
401  newLine += 1;
402  }
403 
404  if( lineCount == 1 )
405  {
406  aFormatter->Print( 0, ")\n" ); // Closes pts token on same line.
407  }
408  else
409  {
410  aFormatter->Print( 0, "\n" );
411  aFormatter->Print( aNestLevel + 1, ")\n" ); // Closes pts token with multiple lines.
412  }
413 
414  formatStroke( aFormatter, aNestLevel + 1, aStroke );
415  aFormatter->Print( 0, "\n" );
416  formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
417  aFormatter->Print( 0, "\n" );
418 
419  if( aUuid != niluuid )
420  aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
421 
422  aFormatter->Print( aNestLevel, ")\n" );
423 }
424 
425 
432 {
433  static int m_modHash; // Keep track of the modification status of the library.
434 
435  wxString m_fileName; // Absolute path and file name.
436  wxFileName m_libFileName; // Absolute path and file name is required here.
437  wxDateTime m_fileModTime;
438  LIB_SYMBOL_MAP m_symbols; // Map of names of #LIB_SYMBOL pointers.
442  SCH_LIB_TYPE m_libType; // Is this cache a symbol or symbol library.
443 
444  LIB_SYMBOL* removeSymbol( LIB_SYMBOL* aAlias );
445 
446  static void saveSymbolDrawItem( LIB_ITEM* aItem, OUTPUTFORMATTER& aFormatter,
447  int aNestLevel );
448  static void saveField( LIB_FIELD* aField, OUTPUTFORMATTER& aFormatter, int aNestLevel );
449  static void savePin( LIB_PIN* aPin, OUTPUTFORMATTER& aFormatter, int aNestLevel = 0 );
450  static void saveText( LIB_TEXT* aText, OUTPUTFORMATTER& aFormatter, int aNestLevel = 0 );
451 
452  static void saveDcmInfoAsFields( LIB_SYMBOL* aSymbol, OUTPUTFORMATTER& aFormatter,
453  int& aNextFreeFieldId, int aNestLevel );
454 
456 
457 public:
458  SCH_SEXPR_PLUGIN_CACHE( const wxString& aLibraryPath );
460 
461  int GetModifyHash() const { return m_modHash; }
462 
463  // Most all functions in this class throw IO_ERROR exceptions. There are no
464  // error codes nor user interface calls from here, nor in any SCH_PLUGIN objects.
465  // Catch these exceptions higher up please.
466 
468  void Save();
469 
470  void Load();
471 
472  void AddSymbol( const LIB_SYMBOL* aSymbol );
473 
474  void DeleteSymbol( const wxString& aName );
475 
476  // If m_libFileName is a symlink follow it to the real source file
477  wxFileName GetRealFile() const;
478 
479  wxDateTime GetLibModificationTime();
480 
481  bool IsFile( const wxString& aFullPathAndFileName ) const;
482 
483  bool IsFileChanged() const;
484 
485  void SetModified( bool aModified = true ) { m_isModified = aModified; }
486 
487  wxString GetLogicalName() const { return m_libFileName.GetName(); }
488 
489  void SetFileName( const wxString& aFileName ) { m_libFileName = aFileName; }
490 
491  wxString GetFileName() const { return m_libFileName.GetFullPath(); }
492 
493  static void SaveSymbol( LIB_SYMBOL* aSymbol, OUTPUTFORMATTER& aFormatter,
494  int aNestLevel = 0, const wxString& aLibName = wxEmptyString );
495 };
496 
497 
499  m_progressReporter( nullptr )
500 {
501  init( nullptr );
502 }
503 
504 
506 {
507  delete m_cache;
508 }
509 
510 
511 void SCH_SEXPR_PLUGIN::init( SCHEMATIC* aSchematic, const PROPERTIES* aProperties )
512 {
513  m_version = 0;
514  m_rootSheet = nullptr;
515  m_schematic = aSchematic;
516  m_cache = nullptr;
517  m_out = nullptr;
518  m_nextFreeFieldId = 100; // number arbitrarily > MANDATORY_FIELDS or SHEET_MANDATORY_FIELDS
519 }
520 
521 
522 SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic,
523  SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties )
524 {
525  wxASSERT( !aFileName || aSchematic != nullptr );
526 
527  LOCALE_IO toggle; // toggles on, then off, the C locale.
528  SCH_SHEET* sheet;
529 
530  wxFileName fn = aFileName;
531 
532  // Unfortunately child sheet file names the legacy schematic file format are not fully
533  // qualified and are always appended to the project path. The aFileName attribute must
534  // always be an absolute path so the project path can be used for load child sheet files.
535  wxASSERT( fn.IsAbsolute() );
536 
537  if( aAppendToMe )
538  {
539  wxLogTrace( traceSchLegacyPlugin, "Append \"%s\" to sheet \"%s\".",
540  aFileName, aAppendToMe->GetFileName() );
541 
542  wxFileName normedFn = aAppendToMe->GetFileName();
543 
544  if( !normedFn.IsAbsolute() )
545  {
546  if( aFileName.Right( normedFn.GetFullPath().Length() ) == normedFn.GetFullPath() )
547  m_path = aFileName.Left( aFileName.Length() - normedFn.GetFullPath().Length() );
548  }
549 
550  if( m_path.IsEmpty() )
551  m_path = aSchematic->Prj().GetProjectPath();
552 
553  wxLogTrace( traceSchLegacyPlugin, "Normalized append path \"%s\".", m_path );
554  }
555  else
556  {
557  m_path = aSchematic->Prj().GetProjectPath();
558  }
559 
560  m_currentPath.push( m_path );
561  init( aSchematic, aProperties );
562 
563  if( aAppendToMe == nullptr )
564  {
565  // Clean up any allocated memory if an exception occurs loading the schematic.
566  std::unique_ptr<SCH_SHEET> newSheet = std::make_unique<SCH_SHEET>( aSchematic );
567 
568  wxFileName relPath( aFileName );
569  // Do not use wxPATH_UNIX as option in MakeRelativeTo(). It can create incorrect
570  // relative paths on Windows, because paths have a disk identifier (C:, D: ...)
571  relPath.MakeRelativeTo( aSchematic->Prj().GetProjectPath() );
572 
573  newSheet->SetFileName( relPath.GetFullPath() );
574  m_rootSheet = newSheet.get();
575  loadHierarchy( newSheet.get() );
576 
577  // If we got here, the schematic loaded successfully.
578  sheet = newSheet.release();
579  m_rootSheet = nullptr; // Quiet Coverity warning.
580  }
581  else
582  {
583  wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
584  m_rootSheet = &aSchematic->Root();
585  sheet = aAppendToMe;
586  loadHierarchy( sheet );
587  }
588 
589  wxASSERT( m_currentPath.size() == 1 ); // only the project path should remain
590 
591  m_currentPath.pop(); // Clear the path stack for next call to Load
592 
593  return sheet;
594 }
595 
596 
597 // Everything below this comment is recursive. Modify with care.
598 
600 {
601  SCH_SCREEN* screen = nullptr;
602 
603  if( !aSheet->GetScreen() )
604  {
605  // SCH_SCREEN objects store the full path and file name where the SCH_SHEET object only
606  // stores the file name and extension. Add the project path to the file name and
607  // extension to compare when calling SCH_SHEET::SearchHierarchy().
608  wxFileName fileName = aSheet->GetFileName();
609 
610  if( !fileName.IsAbsolute() )
611  fileName.MakeAbsolute( m_currentPath.top() );
612 
613  // Save the current path so that it gets restored when descending and ascending the
614  // sheet hierarchy which allows for sheet schematic files to be nested in folders
615  // relative to the last path a schematic was loaded from.
616  wxLogTrace( traceSchLegacyPlugin, "Saving path '%s'", m_currentPath.top() );
617  m_currentPath.push( fileName.GetPath() );
618  wxLogTrace( traceSchLegacyPlugin, "Current path '%s'", m_currentPath.top() );
619  wxLogTrace( traceSchLegacyPlugin, "Loading '%s'", fileName.GetFullPath() );
620 
621  m_rootSheet->SearchHierarchy( fileName.GetFullPath(), &screen );
622 
623  if( screen )
624  {
625  aSheet->SetScreen( screen );
626  aSheet->GetScreen()->SetParent( m_schematic );
627  // Do not need to load the sub-sheets - this has already been done.
628  }
629  else
630  {
631  aSheet->SetScreen( new SCH_SCREEN( m_schematic ) );
632  aSheet->GetScreen()->SetFileName( fileName.GetFullPath() );
633 
634  try
635  {
636  loadFile( fileName.GetFullPath(), aSheet );
637  }
638  catch( const IO_ERROR& ioe )
639  {
640  // If there is a problem loading the root sheet, there is no recovery.
641  if( aSheet == m_rootSheet )
642  throw;
643 
644  // For all subsheets, queue up the error message for the caller.
645  if( !m_error.IsEmpty() )
646  m_error += "\n";
647 
648  m_error += ioe.What();
649  }
650 
651  if( fileName.FileExists() )
652  {
653  aSheet->GetScreen()->SetFileReadOnly( !fileName.IsFileWritable() );
654  aSheet->GetScreen()->SetFileExists( true );
655  }
656  else
657  {
658  aSheet->GetScreen()->SetFileReadOnly( !fileName.IsDirWritable() );
659  aSheet->GetScreen()->SetFileExists( false );
660  }
661 
662  // This was moved out of the try{} block so that any sheets definitionsthat
663  // the plugin fully parsed before the exception was raised will be loaded.
664  for( SCH_ITEM* aItem : aSheet->GetScreen()->Items().OfType( SCH_SHEET_T ) )
665  {
666  wxCHECK2( aItem->Type() == SCH_SHEET_T, /* do nothing */ );
667  SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
668 
669  // Recursion starts here.
670  loadHierarchy( sheet );
671  }
672  }
673 
674  m_currentPath.pop();
675  wxLogTrace( traceSchLegacyPlugin, "Restoring path \"%s\"", m_currentPath.top() );
676  }
677 }
678 
679 
680 void SCH_SEXPR_PLUGIN::loadFile( const wxString& aFileName, SCH_SHEET* aSheet )
681 {
682  FILE_LINE_READER reader( aFileName );
683 
684  size_t lineCount = 0;
685 
686  if( m_progressReporter )
687  {
688  m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) );
689 
691  THROW_IO_ERROR( ( "Open cancelled by user." ) );
692 
693  while( reader.ReadLine() )
694  lineCount++;
695 
696  reader.Rewind();
697  }
698 
699  SCH_SEXPR_PARSER parser( &reader, m_progressReporter, lineCount );
700 
701  parser.ParseSchematic( aSheet );
702 }
703 
704 
705 void SCH_SEXPR_PLUGIN::LoadContent( LINE_READER& aReader, SCH_SHEET* aSheet, int aFileVersion )
706 {
707  wxCHECK( aSheet, /* void */ );
708 
709  LOCALE_IO toggle;
710  SCH_SEXPR_PARSER parser( &aReader );
711 
712  parser.ParseSchematic( aSheet, true, aFileVersion );
713 }
714 
715 
716 void SCH_SEXPR_PLUGIN::Save( const wxString& aFileName, SCH_SHEET* aSheet, SCHEMATIC* aSchematic,
717  const PROPERTIES* aProperties )
718 {
719  wxCHECK_RET( aSheet != nullptr, "NULL SCH_SHEET object." );
720  wxCHECK_RET( !aFileName.IsEmpty(), "No schematic file name defined." );
721 
722  LOCALE_IO toggle; // toggles on, then off, the C locale, to write floating point values.
723 
724  init( aSchematic, aProperties );
725 
726  wxFileName fn = aFileName;
727 
728  // File names should be absolute. Don't assume everything relative to the project path
729  // works properly.
730  wxASSERT( fn.IsAbsolute() );
731 
732  FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
733 
734  m_out = &formatter; // no ownership
735 
736  Format( aSheet );
737 
738  aSheet->GetScreen()->SetFileExists( true );
739 }
740 
741 
743 {
744  wxCHECK_RET( aSheet != nullptr, "NULL SCH_SHEET* object." );
745  wxCHECK_RET( m_schematic != nullptr, "NULL SCHEMATIC* object." );
746 
747  SCH_SCREEN* screen = aSheet->GetScreen();
748 
749  wxCHECK( screen, /* void */ );
750 
751  m_out->Print( 0, "(kicad_sch (version %d) (generator eeschema)\n\n",
753 
754  m_out->Print( 1, "(uuid %s)\n\n", TO_UTF8( screen->m_uuid.AsString() ) );
755 
756  screen->GetPageSettings().Format( m_out, 1, 0 );
757  m_out->Print( 0, "\n" );
758  screen->GetTitleBlock().Format( m_out, 1, 0 );
759 
760  // Save cache library.
761  m_out->Print( 1, "(lib_symbols\n" );
762 
763  for( auto libSymbol : screen->GetLibSymbols() )
764  SCH_SEXPR_PLUGIN_CACHE::SaveSymbol( libSymbol.second, *m_out, 2, libSymbol.first );
765 
766  m_out->Print( 1, ")\n\n" );
767 
768  for( const auto& alias : screen->GetBusAliases() )
769  {
770  saveBusAlias( alias, 1 );
771  }
772 
773  // Enforce item ordering
774  auto cmp =
775  []( const SCH_ITEM* a, const SCH_ITEM* b )
776  {
777  if( a->Type() != b->Type() )
778  return a->Type() < b->Type();
779 
780  return a->m_Uuid < b->m_Uuid;
781  };
782 
783  std::multiset<SCH_ITEM*, decltype( cmp )> save_map( cmp );
784 
785  for( SCH_ITEM* item : screen->Items() )
786  save_map.insert( item );
787 
788  KICAD_T itemType = TYPE_NOT_INIT;
790 
791  for( SCH_ITEM* item : save_map )
792  {
793  if( itemType != item->Type() )
794  {
795  itemType = item->Type();
796 
797  if( itemType != SCH_SYMBOL_T
798  && itemType != SCH_JUNCTION_T
799  && itemType != SCH_SHEET_T )
800  {
801  m_out->Print( 0, "\n" );
802  }
803  }
804 
805  switch( item->Type() )
806  {
807  case SCH_SYMBOL_T:
808  m_out->Print( 0, "\n" );
809  saveSymbol( static_cast<SCH_SYMBOL*>( item ), nullptr, 1 );
810  break;
811 
812  case SCH_BITMAP_T:
813  saveBitmap( static_cast<SCH_BITMAP*>( item ), 1 );
814  break;
815 
816  case SCH_SHEET_T:
817  m_out->Print( 0, "\n" );
818  saveSheet( static_cast<SCH_SHEET*>( item ), 1 );
819  break;
820 
821  case SCH_JUNCTION_T:
822  saveJunction( static_cast<SCH_JUNCTION*>( item ), 1 );
823  break;
824 
825  case SCH_NO_CONNECT_T:
826  saveNoConnect( static_cast<SCH_NO_CONNECT*>( item ), 1 );
827  break;
828 
830  case SCH_BUS_BUS_ENTRY_T:
831  saveBusEntry( static_cast<SCH_BUS_ENTRY_BASE*>( item ), 1 );
832  break;
833 
834  case SCH_LINE_T:
835  if( layer != item->GetLayer() )
836  {
837  if( layer == SCH_LAYER_ID_START )
838  {
839  layer = item->GetLayer();
840  }
841  else
842  {
843  layer = item->GetLayer();
844  m_out->Print( 0, "\n" );
845  }
846  }
847 
848  saveLine( static_cast<SCH_LINE*>( item ), 1 );
849  break;
850 
851  case SCH_TEXT_T:
852  case SCH_LABEL_T:
853  case SCH_GLOBAL_LABEL_T:
854  case SCH_HIER_LABEL_T:
855  saveText( static_cast<SCH_TEXT*>( item ), 1 );
856  break;
857 
858  default:
859  wxASSERT( "Unexpected schematic object type in SCH_SEXPR_PLUGIN::Format()" );
860  }
861  }
862 
863  // If this is the root sheet, save all of the sheet paths.
864  if( aSheet->IsRootSheet() )
865  {
866  SCH_SHEET_LIST sheetPaths( aSheet, true );
867 
868  SCH_REFERENCE_LIST symbolInstances;
869 
870  for( const SCH_SHEET_PATH& sheetPath : sheetPaths )
871  sheetPath.GetSymbols( symbolInstances, true, true );
872 
873  symbolInstances.SortByReferenceOnly();
874 
875  saveInstances( sheetPaths.GetSheetInstances(), symbolInstances.GetSymbolInstances(), 1 );
876  }
877  else
878  {
879  // Schematic files (SCH_SCREEN objects) can be shared so we have to save and restore
880  // symbol and sheet instance data even if the file being saved is not the root sheet
881  // because it is possible that the file is the root sheet of another project.
882  saveInstances( screen->m_sheetInstances, screen->m_symbolInstances, 1 );
883  }
884 
885  m_out->Print( 0, ")\n" );
886 }
887 
888 
889 void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelectionPath,
890  SCH_SHEET_LIST* aFullSheetHierarchy,
891  OUTPUTFORMATTER* aFormatter )
892 {
893  wxCHECK( aSelection && aSelectionPath && aFullSheetHierarchy && aFormatter, /* void */ );
894 
895  LOCALE_IO toggle;
896 
897  m_out = aFormatter;
898 
899  size_t i;
900  SCH_ITEM* item;
901  std::map<wxString, LIB_SYMBOL*> libSymbols;
902  SCH_SCREEN* screen = aSelection->GetScreen();
903 
904  for( i = 0; i < aSelection->GetSize(); ++i )
905  {
906  item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( i ) );
907 
908  wxCHECK2( item, continue );
909 
910  if( item->Type() != SCH_SYMBOL_T )
911  continue;
912 
913  SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
914 
915  wxCHECK2( symbol, continue );
916 
917  wxString libSymbolLookup = symbol->GetLibId().Format().wx_str();
918 
919  if( !symbol->UseLibIdLookup() )
920  libSymbolLookup = symbol->GetSchSymbolLibraryName();
921 
922  auto it = screen->GetLibSymbols().find( libSymbolLookup );
923 
924  if( it != screen->GetLibSymbols().end() )
925  libSymbols[ libSymbolLookup ] = it->second;
926  }
927 
928  if( !libSymbols.empty() )
929  {
930  m_out->Print( 0, "(lib_symbols\n" );
931 
932  for( auto libSymbol : libSymbols )
933  SCH_SEXPR_PLUGIN_CACHE::SaveSymbol( libSymbol.second, *m_out, 1, libSymbol.first );
934 
935  m_out->Print( 0, ")\n\n" );
936  }
937 
938  // Store the selected sheets instance information
939  SCH_SHEET_LIST selectedSheets;
940  selectedSheets.push_back( *aSelectionPath ); // Include the "root" of the selection
941 
942  SCH_REFERENCE_LIST selectedSymbols;
943 
944  for( i = 0; i < aSelection->GetSize(); ++i )
945  {
946  item = (SCH_ITEM*) aSelection->GetItem( i );
947 
948  switch( item->Type() )
949  {
950  case SCH_SYMBOL_T:
951  saveSymbol( static_cast<SCH_SYMBOL*>( item ), aSelectionPath, 0 );
952 
953  aSelectionPath->AppendSymbol( selectedSymbols, static_cast<SCH_SYMBOL*>( item ),
954  true, true );
955  break;
956 
957  case SCH_BITMAP_T:
958  saveBitmap( static_cast< SCH_BITMAP* >( item ), 0 );
959  break;
960 
961  case SCH_SHEET_T:
962  saveSheet( static_cast< SCH_SHEET* >( item ), 0 );
963 
964  {
965  SCH_SHEET_PATH subSheetPath = *aSelectionPath;
966  subSheetPath.push_back( static_cast<SCH_SHEET*>( item ) );
967 
968  aFullSheetHierarchy->GetSheetsWithinPath( selectedSheets, subSheetPath );
969  aFullSheetHierarchy->GetSymbolsWithinPath( selectedSymbols, subSheetPath, true,
970  true );
971  }
972 
973  break;
974 
975  case SCH_JUNCTION_T:
976  saveJunction( static_cast< SCH_JUNCTION* >( item ), 0 );
977  break;
978 
979  case SCH_NO_CONNECT_T:
980  saveNoConnect( static_cast< SCH_NO_CONNECT* >( item ), 0 );
981  break;
982 
984  case SCH_BUS_BUS_ENTRY_T:
985  saveBusEntry( static_cast< SCH_BUS_ENTRY_BASE* >( item ), 0 );
986  break;
987 
988  case SCH_LINE_T:
989  saveLine( static_cast< SCH_LINE* >( item ), 0 );
990  break;
991 
992  case SCH_TEXT_T:
993  case SCH_LABEL_T:
994  case SCH_GLOBAL_LABEL_T:
995  case SCH_HIER_LABEL_T:
996  saveText( static_cast< SCH_TEXT* >( item ), 0 );
997  break;
998 
999  default:
1000  wxASSERT( "Unexpected schematic object type in SCH_SEXPR_PLUGIN::Format()" );
1001  }
1002  }
1003 
1004  // Make all instance information relative to the selection path
1005  KIID_PATH selectionPath = aSelectionPath->PathWithoutRootUuid();
1006 
1007  selectedSheets.SortByPageNumbers();
1008  std::vector<SCH_SHEET_INSTANCE> sheetinstances = selectedSheets.GetSheetInstances();
1009 
1010  for( SCH_SHEET_INSTANCE& sheetInstance : sheetinstances )
1011  {
1012  wxASSERT_MSG( sheetInstance.m_Path.MakeRelativeTo( selectionPath ),
1013  "Sheet is not inside the selection path?" );
1014  }
1015 
1016 
1017  selectedSymbols.SortByReferenceOnly();
1018  std::vector<SYMBOL_INSTANCE_REFERENCE> symbolInstances = selectedSymbols.GetSymbolInstances();
1019 
1020  for( SYMBOL_INSTANCE_REFERENCE& symbolInstance : symbolInstances )
1021  {
1022  wxASSERT_MSG( symbolInstance.m_Path.MakeRelativeTo( selectionPath ),
1023  "Symbol is not inside the selection path?" );
1024  }
1025 
1026  saveInstances( sheetinstances, symbolInstances, 0 );
1027 }
1028 
1029 
1031  int aNestLevel )
1032 {
1033  wxCHECK_RET( aSymbol != nullptr && m_out != nullptr, "" );
1034 
1035  std::string libName;
1036  wxArrayString reference_fields;
1037 
1038  static wxString delimiters( wxT( " " ) );
1039 
1040  wxString symbol_name = aSymbol->GetLibId().Format();
1041 
1042  if( symbol_name.size() )
1043  {
1044  libName = toUTFTildaText( symbol_name );
1045  }
1046  else
1047  {
1048  libName = "_NONAME_";
1049  }
1050 
1051  double angle;
1052  int orientation = aSymbol->GetOrientation() & ~( SYM_MIRROR_X | SYM_MIRROR_Y );
1053 
1054  if( orientation == SYM_ORIENT_90 )
1055  angle = 90.0;
1056  else if( orientation == SYM_ORIENT_180 )
1057  angle = 180.0;
1058  else if( orientation == SYM_ORIENT_270 )
1059  angle = 270.0;
1060  else
1061  angle = 0.0;
1062 
1063  m_out->Print( aNestLevel, "(symbol" );
1064 
1065  if( !aSymbol->UseLibIdLookup() )
1066  {
1067  m_out->Print( 0, " (lib_name %s)",
1068  m_out->Quotew( aSymbol->GetSchSymbolLibraryName() ).c_str() );
1069  }
1070 
1071  m_out->Print( 0, " (lib_id %s) (at %s %s %s)",
1072  m_out->Quotew( aSymbol->GetLibId().Format().wx_str() ).c_str(),
1073  FormatInternalUnits( aSymbol->GetPosition().x ).c_str(),
1074  FormatInternalUnits( aSymbol->GetPosition().y ).c_str(),
1075  FormatAngle( angle * 10.0 ).c_str() );
1076 
1077  bool mirrorX = aSymbol->GetOrientation() & SYM_MIRROR_X;
1078  bool mirrorY = aSymbol->GetOrientation() & SYM_MIRROR_Y;
1079 
1080  if( mirrorX || mirrorY )
1081  {
1082  m_out->Print( 0, " (mirror" );
1083 
1084  if( mirrorX )
1085  m_out->Print( 0, " x" );
1086 
1087  if( mirrorY )
1088  m_out->Print( 0, " y" );
1089 
1090  m_out->Print( 0, ")" );
1091  }
1092 
1093  int unit = ( aSymbol->GetInstanceReferences().size() == 0 ) ?
1094  aSymbol->GetUnit() :
1095  aSymbol->GetInstanceReferences()[0].m_Unit;
1096 
1097  m_out->Print( 0, " (unit %d)", unit );
1098 
1099  if( aSymbol->GetConvert() == LIB_ITEM::LIB_CONVERT::DEMORGAN )
1100  m_out->Print( 0, " (convert %d)", aSymbol->GetConvert() );
1101 
1102  m_out->Print( 0, "\n" );
1103 
1104  m_out->Print( aNestLevel + 1, "(in_bom %s)", ( aSymbol->GetIncludeInBom() ) ? "yes" : "no" );
1105  m_out->Print( 0, " (on_board %s)", ( aSymbol->GetIncludeOnBoard() ) ? "yes" : "no" );
1106 
1107  if( aSymbol->GetFieldsAutoplaced() != FIELDS_AUTOPLACED_NO )
1108  m_out->Print( 0, " (fields_autoplaced)" );
1109 
1110  m_out->Print( 0, "\n" );
1111 
1112  m_out->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aSymbol->m_Uuid.AsString() ) );
1113 
1115 
1116  for( SCH_FIELD& field : aSymbol->GetFields() )
1117  {
1118  int id = field.GetId();
1119  wxString value = field.GetText();
1120 
1121  // The instance fields are always set to the first sheet instance of the project to
1122  // schematic file changes when switching sheet instances with the current project
1123  // schematic. It does not solve the problem for schematics shared between projects.
1124  if( id == REFERENCE_FIELD )
1125  {
1126  field.SetText( ( aSymbol->GetInstanceReferences().size() == 0 ) ?
1127  value :
1128  aSymbol->GetInstanceReferences()[0].m_Reference );
1129  }
1130  else if( id == VALUE_FIELD )
1131  {
1132  field.SetText( ( aSymbol->GetInstanceReferences().size() == 0 ) ?
1133  value :
1134  aSymbol->GetInstanceReferences()[0].m_Value );
1135  }
1136  else if( id == FOOTPRINT_FIELD )
1137  {
1138  field.SetText( ( aSymbol->GetInstanceReferences().size() == 0 ) ?
1139  value :
1140  aSymbol->GetInstanceReferences()[0].m_Footprint );
1141  }
1142 
1143  try
1144  {
1145  saveField( &field, aNestLevel + 1 );
1146  }
1147  catch( ... )
1148  {
1149  // Restore the changed field text on write error.
1150  if( id == REFERENCE_FIELD || id == VALUE_FIELD || id == FOOTPRINT_FIELD )
1151  field.SetText( value );
1152 
1153  throw;
1154  }
1155 
1156  if( id == REFERENCE_FIELD || id == VALUE_FIELD || id == FOOTPRINT_FIELD )
1157  field.SetText( value );
1158  }
1159 
1160  for( const std::unique_ptr<SCH_PIN>& pin : aSymbol->GetRawPins() )
1161  {
1162  if( pin->GetAlt().IsEmpty() )
1163  {
1164  m_out->Print( aNestLevel + 1, "(pin %s (uuid %s))\n",
1165  m_out->Quotew( pin->GetNumber() ).c_str(),
1166  TO_UTF8( pin->m_Uuid.AsString() ) );
1167  }
1168  else
1169  {
1170  m_out->Print( aNestLevel + 1, "(pin %s (uuid %s) (alternate %s))\n",
1171  m_out->Quotew( pin->GetNumber() ).c_str(),
1172  TO_UTF8( pin->m_Uuid.AsString() ),
1173  m_out->Quotew( pin->GetAlt() ).c_str() );
1174  }
1175  }
1176 
1177  m_out->Print( aNestLevel, ")\n" );
1178 }
1179 
1180 
1181 void SCH_SEXPR_PLUGIN::saveField( SCH_FIELD* aField, int aNestLevel )
1182 {
1183  wxCHECK_RET( aField != nullptr && m_out != nullptr, "" );
1184 
1185  wxString fieldName = aField->GetName();
1186 
1187  // For some reason (bug in legacy parser?) the field ID for non-mandatory fields is -1 so
1188  // check for this in order to correctly use the field name.
1189  if( aField->GetParent()->Type() == SCH_SYMBOL_T )
1190  {
1191  if( aField->GetId() >= 0 && aField->GetId() < MANDATORY_FIELDS )
1192  fieldName = TEMPLATE_FIELDNAME::GetDefaultFieldName( aField->GetId(), false );
1193  }
1194  else if( aField->GetParent()->Type() == SCH_SHEET_T )
1195  {
1196  if( aField->GetId() >= 0 && aField->GetId() < SHEET_MANDATORY_FIELDS )
1197  fieldName = SCH_SHEET::GetDefaultFieldName( aField->GetId(), false );
1198  }
1199 
1200  if( aField->GetId() == -1 /* undefined ID */ )
1201  {
1202  aField->SetId( m_nextFreeFieldId );
1203  m_nextFreeFieldId += 1;
1204  }
1205  else if( aField->GetId() >= m_nextFreeFieldId )
1206  {
1207  m_nextFreeFieldId = aField->GetId() + 1;
1208  }
1209 
1210  m_out->Print( aNestLevel, "(property %s %s (id %d) (at %s %s %s)",
1211  m_out->Quotew( fieldName ).c_str(),
1212  m_out->Quotew( aField->GetText() ).c_str(),
1213  aField->GetId(),
1214  FormatInternalUnits( aField->GetPosition().x ).c_str(),
1215  FormatInternalUnits( aField->GetPosition().y ).c_str(),
1216  FormatAngle( aField->GetTextAngleDegrees() * 10.0 ).c_str() );
1217 
1218  if( !aField->IsDefaultFormatting()
1219  || ( aField->GetTextHeight() != Mils2iu( DEFAULT_SIZE_TEXT ) ) )
1220  {
1221  m_out->Print( 0, "\n" );
1222  aField->Format( m_out, aNestLevel, 0 );
1223  m_out->Print( aNestLevel, ")\n" ); // Closes property token with font effects.
1224  }
1225  else
1226  {
1227  m_out->Print( 0, ")\n" ); // Closes property token without font effects.
1228  }
1229 }
1230 
1231 
1232 void SCH_SEXPR_PLUGIN::saveBitmap( SCH_BITMAP* aBitmap, int aNestLevel )
1233 {
1234  wxCHECK_RET( aBitmap != nullptr && m_out != nullptr, "" );
1235 
1236  const wxImage* image = aBitmap->GetImage()->GetImageData();
1237 
1238  wxCHECK_RET( image != nullptr, "wxImage* is NULL" );
1239 
1240  m_out->Print( aNestLevel, "(image (at %s %s)",
1241  FormatInternalUnits( aBitmap->GetPosition().x ).c_str(),
1242  FormatInternalUnits( aBitmap->GetPosition().y ).c_str() );
1243 
1244  if( aBitmap->GetImage()->GetScale() != 1.0 )
1245  m_out->Print( 0, " (scale %g)", aBitmap->GetImage()->GetScale() );
1246 
1247  m_out->Print( 0, "\n" );
1248 
1249  m_out->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aBitmap->m_Uuid.AsString() ) );
1250 
1251  m_out->Print( aNestLevel + 1, "(data" );
1252 
1253  wxMemoryOutputStream stream;
1254 
1255  image->SaveFile( stream, wxBITMAP_TYPE_PNG );
1256 
1257  // Write binary data in hexadecimal form (ASCII)
1258  wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
1259  wxString out = wxBase64Encode( buffer->GetBufferStart(), buffer->GetBufferSize() );
1260 
1261  // Apparently the MIME standard character width for base64 encoding is 76 (unconfirmed)
1262  // so use it in a vein attempt to be standard like.
1263 #define MIME_BASE64_LENGTH 76
1264 
1265  size_t first = 0;
1266 
1267  while( first < out.Length() )
1268  {
1269  m_out->Print( 0, "\n" );
1270  m_out->Print( aNestLevel + 2, "%s", TO_UTF8( out( first, MIME_BASE64_LENGTH ) ) );
1271  first += MIME_BASE64_LENGTH;
1272  }
1273 
1274  m_out->Print( 0, "\n" );
1275  m_out->Print( aNestLevel + 1, ")\n" ); // Closes data token.
1276  m_out->Print( aNestLevel, ")\n" ); // Closes image token.
1277 }
1278 
1279 
1280 void SCH_SEXPR_PLUGIN::saveSheet( SCH_SHEET* aSheet, int aNestLevel )
1281 {
1282  wxCHECK_RET( aSheet != nullptr && m_out != nullptr, "" );
1283 
1284  m_out->Print( aNestLevel, "(sheet (at %s %s) (size %s %s)",
1285  FormatInternalUnits( aSheet->GetPosition().x ).c_str(),
1286  FormatInternalUnits( aSheet->GetPosition().y ).c_str(),
1287  FormatInternalUnits( aSheet->GetSize().GetWidth() ).c_str(),
1288  FormatInternalUnits( aSheet->GetSize().GetHeight() ).c_str() );
1289 
1290  if( aSheet->GetFieldsAutoplaced() != FIELDS_AUTOPLACED_NO )
1291  m_out->Print( 0, " (fields_autoplaced)" );
1292 
1293  m_out->Print( 0, "\n" );
1294 
1296  aSheet->GetBorderColor() );
1297 
1298  stroke.SetWidth( aSheet->GetBorderWidth() );
1299  formatStroke( m_out, aNestLevel + 1, stroke );
1300 
1301  m_out->Print( 0, "\n" );
1302 
1303  m_out->Print( aNestLevel + 1, "(fill (color %d %d %d %0.4f))\n",
1304  KiROUND( aSheet->GetBackgroundColor().r * 255.0 ),
1305  KiROUND( aSheet->GetBackgroundColor().g * 255.0 ),
1306  KiROUND( aSheet->GetBackgroundColor().b * 255.0 ),
1307  aSheet->GetBackgroundColor().a );
1308 
1309  m_out->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aSheet->m_Uuid.AsString() ) );
1310 
1312 
1313  for( SCH_FIELD& field : aSheet->GetFields() )
1314  {
1315  saveField( &field, aNestLevel + 1 );
1316  }
1317 
1318  for( const SCH_SHEET_PIN* pin : aSheet->GetPins() )
1319  {
1320  m_out->Print( aNestLevel + 1, "(pin %s %s (at %s %s %s)\n",
1321  EscapedUTF8( pin->GetText() ).c_str(),
1322  getSheetPinShapeToken( pin->GetShape() ),
1323  FormatInternalUnits( pin->GetPosition().x ).c_str(),
1324  FormatInternalUnits( pin->GetPosition().y ).c_str(),
1325  FormatAngle( getSheetPinAngle( pin->GetSide() ) * 10.0 ).c_str() );
1326 
1327  pin->Format( m_out, aNestLevel + 1, 0 );
1328 
1329  m_out->Print( aNestLevel + 2, "(uuid %s)\n", TO_UTF8( pin->m_Uuid.AsString() ) );
1330 
1331  m_out->Print( aNestLevel + 1, ")\n" ); // Closes pin token.
1332  }
1333 
1334  m_out->Print( aNestLevel, ")\n" ); // Closes sheet token.
1335 }
1336 
1337 
1338 void SCH_SEXPR_PLUGIN::saveJunction( SCH_JUNCTION* aJunction, int aNestLevel )
1339 {
1340  wxCHECK_RET( aJunction != nullptr && m_out != nullptr, "" );
1341 
1342  m_out->Print( aNestLevel, "(junction (at %s %s) (diameter %s) (color %d %d %d %s)\n",
1343  FormatInternalUnits( aJunction->GetPosition().x ).c_str(),
1344  FormatInternalUnits( aJunction->GetPosition().y ).c_str(),
1345  FormatInternalUnits( aJunction->GetDiameter() ).c_str(),
1346  KiROUND( aJunction->GetColor().r * 255.0 ),
1347  KiROUND( aJunction->GetColor().g * 255.0 ),
1348  KiROUND( aJunction->GetColor().b * 255.0 ),
1349  Double2Str( aJunction->GetColor().a ).c_str() );
1350 
1351  m_out->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aJunction->m_Uuid.AsString() ) );
1352 
1353  m_out->Print( aNestLevel, ")\n" );
1354 }
1355 
1356 
1357 void SCH_SEXPR_PLUGIN::saveNoConnect( SCH_NO_CONNECT* aNoConnect, int aNestLevel )
1358 {
1359  wxCHECK_RET( aNoConnect != nullptr && m_out != nullptr, "" );
1360 
1361  m_out->Print( aNestLevel, "(no_connect (at %s %s) (uuid %s))\n",
1362  FormatInternalUnits( aNoConnect->GetPosition().x ).c_str(),
1363  FormatInternalUnits( aNoConnect->GetPosition().y ).c_str(),
1364  TO_UTF8( aNoConnect->m_Uuid.AsString() ) );
1365 }
1366 
1367 
1368 void SCH_SEXPR_PLUGIN::saveBusEntry( SCH_BUS_ENTRY_BASE* aBusEntry, int aNestLevel )
1369 {
1370  wxCHECK_RET( aBusEntry != nullptr && m_out != nullptr, "" );
1371 
1372  // Bus to bus entries are converted to bus line segments.
1373  if( aBusEntry->GetClass() == "SCH_BUS_BUS_ENTRY" )
1374  {
1375  SCH_LINE busEntryLine( aBusEntry->GetPosition(), LAYER_BUS );
1376 
1377  busEntryLine.SetEndPoint( aBusEntry->GetEnd() );
1378  saveLine( &busEntryLine, aNestLevel );
1379  }
1380  else
1381  {
1382  m_out->Print( aNestLevel, "(bus_entry (at %s %s) (size %s %s)\n",
1383  FormatInternalUnits( aBusEntry->GetPosition().x ).c_str(),
1384  FormatInternalUnits( aBusEntry->GetPosition().y ).c_str(),
1385  FormatInternalUnits( aBusEntry->GetSize().GetWidth() ).c_str(),
1386  FormatInternalUnits( aBusEntry->GetSize().GetHeight() ).c_str() );
1387 
1388  formatStroke( m_out, aNestLevel + 1, aBusEntry->GetStroke() );
1389 
1390  m_out->Print( 0, "\n" );
1391 
1392  m_out->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aBusEntry->m_Uuid.AsString() ) );
1393 
1394  m_out->Print( aNestLevel, ")\n" );
1395  }
1396 }
1397 
1398 
1399 void SCH_SEXPR_PLUGIN::saveLine( SCH_LINE* aLine, int aNestLevel )
1400 {
1401  wxCHECK_RET( aLine != nullptr && m_out != nullptr, "" );
1402 
1403  wxString lineType;
1404 
1405  STROKE_PARAMS line_stroke = aLine->GetStroke();
1406 
1407  switch( aLine->GetLayer() )
1408  {
1409  case LAYER_BUS: lineType = "bus"; break;
1410  case LAYER_WIRE: lineType = "wire"; break;
1411  case LAYER_NOTES:
1412  default: lineType = "polyline"; break;
1413  }
1414 
1415  m_out->Print( aNestLevel, "(%s (pts (xy %s %s) (xy %s %s))\n",
1416  TO_UTF8( lineType ),
1417  FormatInternalUnits( aLine->GetStartPoint().x ).c_str(),
1418  FormatInternalUnits( aLine->GetStartPoint().y ).c_str(),
1419  FormatInternalUnits( aLine->GetEndPoint().x ).c_str(),
1420  FormatInternalUnits( aLine->GetEndPoint().y ).c_str() );
1421 
1422  formatStroke( m_out, aNestLevel + 1, line_stroke );
1423  m_out->Print( 0, "\n" );
1424 
1425  m_out->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aLine->m_Uuid.AsString() ) );
1426 
1427  m_out->Print( aNestLevel, ")\n" );
1428 }
1429 
1430 
1431 void SCH_SEXPR_PLUGIN::saveText( SCH_TEXT* aText, int aNestLevel )
1432 {
1433  wxCHECK_RET( aText != nullptr && m_out != nullptr, "" );
1434 
1435  double angle;
1436 
1437  switch( aText->GetLabelSpinStyle() )
1438  {
1439  case LABEL_SPIN_STYLE::RIGHT: angle = 0.0; break;
1440  case LABEL_SPIN_STYLE::UP: angle = 90.0; break;
1441  case LABEL_SPIN_STYLE::LEFT: angle = 180.0; break;
1442  case LABEL_SPIN_STYLE::BOTTOM: angle = 270.0; break;
1443  default: wxFAIL; angle = 0.0; break;
1444  }
1445 
1446  m_out->Print( aNestLevel, "(%s %s",
1447  getTextTypeToken( aText->Type() ),
1448  m_out->Quotew( aText->GetText() ).c_str() );
1449 
1450  if( ( aText->Type() == SCH_GLOBAL_LABEL_T ) || ( aText->Type() == SCH_HIER_LABEL_T ) )
1451  m_out->Print( 0, " (shape %s)", getSheetPinShapeToken( aText->GetShape() ) );
1452 
1453  if( aText->GetText().Length() < 50 )
1454  {
1455  m_out->Print( 0, " (at %s %s %s)",
1456  FormatInternalUnits( aText->GetPosition().x ).c_str(),
1457  FormatInternalUnits( aText->GetPosition().y ).c_str(),
1458  FormatAngle( angle * 10.0 ).c_str() );
1459  }
1460  else
1461  {
1462  m_out->Print( 0, "\n" );
1463  m_out->Print( aNestLevel + 1, "(at %s %s %s)",
1464  FormatInternalUnits( aText->GetPosition().x ).c_str(),
1465  FormatInternalUnits( aText->GetPosition().y ).c_str(),
1466  FormatAngle( aText->GetTextAngle() ).c_str() );
1467  }
1468 
1469  if( aText->GetFieldsAutoplaced() != FIELDS_AUTOPLACED_NO )
1470  m_out->Print( 0, " (fields_autoplaced)" );
1471 
1472  m_out->Print( 0, "\n" );
1473  aText->Format( m_out, aNestLevel, 0 );
1474 
1475  m_out->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aText->m_Uuid.AsString() ) );
1476 
1477  if( ( aText->Type() == SCH_GLOBAL_LABEL_T ) )
1478  {
1479  SCH_GLOBALLABEL* label = static_cast<SCH_GLOBALLABEL*>( aText );
1480  saveField( label->GetIntersheetRefs(), aNestLevel + 1 );
1481  }
1482 
1483  m_out->Print( aNestLevel, ")\n" ); // Closes text token.
1484 }
1485 
1486 
1487 void SCH_SEXPR_PLUGIN::saveBusAlias( std::shared_ptr<BUS_ALIAS> aAlias, int aNestLevel )
1488 {
1489  wxCHECK_RET( aAlias != nullptr, "BUS_ALIAS* is NULL" );
1490 
1491  wxString members;
1492 
1493  for( auto member : aAlias->Members() )
1494  {
1495  if( members.IsEmpty() )
1496  members = m_out->Quotew( member );
1497  else
1498  members += " " + m_out->Quotew( member );
1499  }
1500 
1501  m_out->Print( aNestLevel, "(bus_alias %s (members %s))\n",
1502  m_out->Quotew( aAlias->GetName() ).c_str(),
1503  TO_UTF8( members ) );
1504 }
1505 
1506 
1507 void SCH_SEXPR_PLUGIN::saveInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheets,
1508  const std::vector<SYMBOL_INSTANCE_REFERENCE>& aSymbols,
1509  int aNestLevel )
1510 {
1511  if( aSheets.size() )
1512  {
1513  m_out->Print( 0, "\n" );
1514  m_out->Print( aNestLevel, "(sheet_instances\n" );
1515 
1516  for( const SCH_SHEET_INSTANCE& instance : aSheets )
1517  {
1518  wxString path = instance.m_Path.AsString();
1519 
1520  if( path.IsEmpty() )
1521  path = wxT( "/" ); // Root path
1522 
1523  m_out->Print( aNestLevel + 1, "(path %s (page %s))\n",
1524  m_out->Quotew( path ).c_str(),
1525  m_out->Quotew( instance.m_PageNumber ).c_str() );
1526  }
1527 
1528  m_out->Print( aNestLevel, ")\n" ); // Close sheet instances token.
1529  }
1530 
1531  if( aSymbols.size() )
1532  {
1533  m_out->Print( 0, "\n" );
1534  m_out->Print( aNestLevel, "(symbol_instances\n" );
1535 
1536  for( const SYMBOL_INSTANCE_REFERENCE& instance : aSymbols )
1537  {
1538  m_out->Print( aNestLevel + 1, "(path %s\n",
1539  m_out->Quotew( instance.m_Path.AsString() ).c_str() );
1540  m_out->Print( aNestLevel + 2, "(reference %s) (unit %d) (value %s) (footprint %s)\n",
1541  m_out->Quotew( instance.m_Reference ).c_str(),
1542  instance.m_Unit,
1543  m_out->Quotew( instance.m_Value ).c_str(),
1544  m_out->Quotew( instance.m_Footprint ).c_str() );
1545  m_out->Print( aNestLevel + 1, ")\n" );
1546  }
1547 
1548  m_out->Print( aNestLevel, ")\n" ); // Close symbol instances token.
1549  }
1550 }
1551 
1552 
1553 int SCH_SEXPR_PLUGIN_CACHE::m_modHash = 1; // starts at 1 and goes up
1554 
1555 
1556 SCH_SEXPR_PLUGIN_CACHE::SCH_SEXPR_PLUGIN_CACHE( const wxString& aFullPathAndFileName ) :
1557  m_fileName( aFullPathAndFileName ),
1558  m_libFileName( aFullPathAndFileName ),
1559  m_isWritable( true ),
1560  m_isModified( false )
1561 {
1562  m_versionMajor = -1;
1564 }
1565 
1566 
1568 {
1569  // When the cache is destroyed, all of the alias objects on the heap should be deleted.
1570  for( LIB_SYMBOL_MAP::iterator it = m_symbols.begin(); it != m_symbols.end(); ++it )
1571  delete it->second;
1572 
1573  m_symbols.clear();
1574 }
1575 
1576 
1577 // If m_libFileName is a symlink follow it to the real source file
1579 {
1580  wxFileName fn( m_libFileName );
1582  return fn;
1583 }
1584 
1585 
1587 {
1588  wxFileName fn = GetRealFile();
1589 
1590  // update the writable flag while we have a wxFileName, in a network this
1591  // is possibly quite dynamic anyway.
1592  m_isWritable = fn.IsFileWritable();
1593 
1594  return fn.GetModificationTime();
1595 }
1596 
1597 
1598 bool SCH_SEXPR_PLUGIN_CACHE::IsFile( const wxString& aFullPathAndFileName ) const
1599 {
1600  return m_fileName == aFullPathAndFileName;
1601 }
1602 
1603 
1605 {
1606  wxFileName fn = GetRealFile();
1607 
1608  if( m_fileModTime.IsValid() && fn.IsOk() && fn.FileExists() )
1609  return fn.GetModificationTime() != m_fileModTime;
1610 
1611  return false;
1612 }
1613 
1614 
1616 {
1617  wxCHECK_MSG( aSymbol != nullptr, nullptr, "NULL pointer cannot be removed from library." );
1618 
1619  LIB_SYMBOL* firstChild = nullptr;
1620  LIB_SYMBOL_MAP::iterator it = m_symbols.find( aSymbol->GetName() );
1621 
1622  if( it == m_symbols.end() )
1623  return nullptr;
1624 
1625  // If the entry pointer doesn't match the name it is mapped to in the library, we
1626  // have done something terribly wrong.
1627  wxCHECK_MSG( *it->second == aSymbol, nullptr,
1628  "Pointer mismatch while attempting to remove alias entry <" + aSymbol->GetName() +
1629  "> from library cache <" + m_libFileName.GetName() + ">." );
1630 
1631  // If the symbol is a root symbol used by other symbols find the first alias that uses
1632  // the root symbol and make it the new root.
1633  if( aSymbol->IsRoot() )
1634  {
1635  for( auto entry : m_symbols )
1636  {
1637  if( entry.second->IsAlias()
1638  && entry.second->GetParent().lock() == aSymbol->SharedPtr() )
1639  {
1640  firstChild = entry.second;
1641  break;
1642  }
1643  }
1644 
1645  if( firstChild )
1646  {
1647  for( LIB_ITEM& drawItem : aSymbol->GetDrawItems() )
1648  {
1649  if( drawItem.Type() == LIB_FIELD_T )
1650  {
1651  LIB_FIELD& field = static_cast<LIB_FIELD&>( drawItem );
1652 
1653  if( firstChild->FindField( field.GetCanonicalName() ) )
1654  continue;
1655  }
1656 
1657  LIB_ITEM* newItem = (LIB_ITEM*) drawItem.Clone();
1658  drawItem.SetParent( firstChild );
1659  firstChild->AddDrawItem( newItem );
1660  }
1661 
1662  // Reparent the remaining aliases.
1663  for( auto entry : m_symbols )
1664  {
1665  if( entry.second->IsAlias()
1666  && entry.second->GetParent().lock() == aSymbol->SharedPtr() )
1667  entry.second->SetParent( firstChild );
1668  }
1669  }
1670  }
1671 
1672  m_symbols.erase( it );
1673  delete aSymbol;
1674  m_isModified = true;
1675  ++m_modHash;
1676  return firstChild;
1677 }
1678 
1679 
1681 {
1682  // aSymbol is cloned in SYMBOL_LIB::AddSymbol(). The cache takes ownership of aSymbol.
1683  wxString name = aSymbol->GetName();
1684  LIB_SYMBOL_MAP::iterator it = m_symbols.find( name );
1685 
1686  if( it != m_symbols.end() )
1687  {
1688  removeSymbol( it->second );
1689  }
1690 
1691  m_symbols[ name ] = const_cast< LIB_SYMBOL* >( aSymbol );
1692  m_isModified = true;
1693  ++m_modHash;
1694 }
1695 
1696 
1698 {
1699  if( !m_libFileName.FileExists() )
1700  {
1701  THROW_IO_ERROR( wxString::Format( _( "Library file '%s' not found." ),
1702  m_libFileName.GetFullPath() ) );
1703  }
1704 
1705  wxCHECK_RET( m_libFileName.IsAbsolute(),
1706  wxString::Format( "Cannot use relative file paths in sexpr plugin to "
1707  "open library '%s'.", m_libFileName.GetFullPath() ) );
1708 
1709  // The current locale must use period as the decimal point.
1710  wxCHECK2( wxLocale::GetInfo( wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER ) == ".",
1711  LOCALE_IO toggle );
1712 
1713  wxLogTrace( traceSchLegacyPlugin, "Loading sexpr symbol library file '%s'",
1714  m_libFileName.GetFullPath() );
1715 
1716  FILE_LINE_READER reader( m_libFileName.GetFullPath() );
1717 
1718  SCH_SEXPR_PARSER parser( &reader );
1719 
1720  parser.ParseLib( m_symbols );
1721  ++m_modHash;
1722 
1723  // Remember the file modification time of library file when the
1724  // cache snapshot was made, so that in a networked environment we will
1725  // reload the cache as needed.
1727 }
1728 
1729 
1731 {
1732  if( !m_isModified )
1733  return;
1734 
1735  LOCALE_IO toggle; // toggles on, then off, the C locale.
1736 
1737  // Write through symlinks, don't replace them.
1738  wxFileName fn = GetRealFile();
1739 
1740  auto formatter = std::make_unique<FILE_OUTPUTFORMATTER>( fn.GetFullPath() );
1741 
1742  formatter->Print( 0, "(kicad_symbol_lib (version %d) (generator kicad_symbol_editor)\n",
1744 
1745  for( auto parent : m_symbols )
1746  {
1747  // Save the root symbol first so alias can inherit from them.
1748  if( parent.second->IsRoot() )
1749  {
1750  SaveSymbol( parent.second, *formatter.get(), 1 );
1751 
1752  // Save all of the aliases associated with the current root symbol.
1753  for( auto alias : m_symbols )
1754  {
1755  if( !alias.second->IsAlias() )
1756  continue;
1757 
1758  std::shared_ptr<LIB_SYMBOL> aliasParent = alias.second->GetParent().lock();
1759 
1760  if( aliasParent.get() != parent.second )
1761  continue;
1762 
1763  SaveSymbol( alias.second, *formatter.get(), 1 );
1764  }
1765  }
1766  }
1767 
1768  formatter->Print( 0, ")\n" );
1769 
1770  formatter.reset();
1771 
1772  m_fileModTime = fn.GetModificationTime();
1773  m_isModified = false;
1774 }
1775 
1776 
1778  int aNestLevel, const wxString& aLibName )
1779 {
1780  wxCHECK_RET( aSymbol, "Invalid LIB_SYMBOL pointer." );
1781 
1782  // The current locale must use period as the decimal point.
1783  wxCHECK2( wxLocale::GetInfo( wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER ) == ".",
1784  LOCALE_IO toggle );
1785 
1786  int nextFreeFieldId = MANDATORY_FIELDS;
1787  std::vector<LIB_FIELD*> fields;
1788  std::string name = aFormatter.Quotew( aSymbol->GetLibId().GetLibItemName().wx_str() );
1789  std::string unitName = aSymbol->GetLibId().GetLibItemName();
1790 
1791  if( !aLibName.IsEmpty() )
1792  {
1793  name = aFormatter.Quotew( aLibName );
1794 
1795  LIB_ID unitId;
1796 
1797  wxCHECK2( unitId.Parse( aLibName ) < 0, /* do nothing */ );
1798 
1799  unitName = unitId.GetLibItemName();
1800  }
1801 
1802  if( aSymbol->IsRoot() )
1803  {
1804  aFormatter.Print( aNestLevel, "(symbol %s", name.c_str() );
1805 
1806  if( aSymbol->IsPower() )
1807  aFormatter.Print( 0, " (power)" );
1808 
1809  // TODO: add uuid token here.
1810 
1811  // TODO: add anchor position token here.
1812 
1813  if( !aSymbol->ShowPinNumbers() )
1814  aFormatter.Print( 0, " (pin_numbers hide)" );
1815 
1816  if( aSymbol->GetPinNameOffset() != Mils2iu( DEFAULT_PIN_NAME_OFFSET )
1817  || !aSymbol->ShowPinNames() )
1818  {
1819  aFormatter.Print( 0, " (pin_names" );
1820 
1821  if( aSymbol->GetPinNameOffset() != Mils2iu( DEFAULT_PIN_NAME_OFFSET ) )
1822  aFormatter.Print( 0, " (offset %s)",
1823  FormatInternalUnits( aSymbol->GetPinNameOffset() ).c_str() );
1824 
1825  if( !aSymbol->ShowPinNames() )
1826  aFormatter.Print( 0, " hide" );
1827 
1828  aFormatter.Print( 0, ")" );
1829  }
1830 
1831  aFormatter.Print( 0, " (in_bom %s)", ( aSymbol->GetIncludeInBom() ) ? "yes" : "no" );
1832  aFormatter.Print( 0, " (on_board %s)", ( aSymbol->GetIncludeOnBoard() ) ? "yes" : "no" );
1833 
1834  // TODO: add atomic token here.
1835 
1836  // TODO: add required token here."
1837 
1838  aFormatter.Print( 0, "\n" );
1839 
1840  aSymbol->GetFields( fields );
1841 
1842  for( LIB_FIELD* field : fields )
1843  saveField( field, aFormatter, aNestLevel + 1 );
1844 
1845  nextFreeFieldId = aSymbol->GetNextAvailableFieldId();
1846 
1847  // @todo At some point in the future the lock status (all units interchangeable) should
1848  // be set deterministically. For now a custom lock property is used to preserve the
1849  // locked flag state.
1850  if( aSymbol->UnitsLocked() )
1851  {
1852  LIB_FIELD locked( nextFreeFieldId, "ki_locked" );
1853  saveField( &locked, aFormatter, aNestLevel + 1 );
1854  nextFreeFieldId += 1;
1855  }
1856 
1857  saveDcmInfoAsFields( aSymbol, aFormatter, nextFreeFieldId, aNestLevel );
1858 
1859  // Save the draw items grouped by units.
1860  std::vector<LIB_SYMBOL_UNIT> units = aSymbol->GetUnitDrawItems();
1861  std::sort( units.begin(), units.end(),
1862  []( const LIB_SYMBOL_UNIT& a, const LIB_SYMBOL_UNIT& b )
1863  {
1864  if( a.m_unit == b.m_unit )
1865  return a.m_convert < b.m_convert;
1866 
1867  return a.m_unit < b.m_unit;
1868  } );
1869 
1870  for( auto unit : units )
1871  {
1872  // Add quotes and escape chars like ") to the UTF8 unitName string
1873  name = aFormatter.Quotes( unitName );
1874  name.pop_back(); // Remove last char: the quote ending the string.
1875 
1876  aFormatter.Print( aNestLevel + 1, "(symbol %s_%d_%d\"\n",
1877  name.c_str(), unit.m_unit, unit.m_convert );
1878 
1879  // Enforce item ordering
1880  auto cmp =
1881  []( const LIB_ITEM* a, const LIB_ITEM* b )
1882  {
1883  return *a < *b;
1884  };
1885 
1886  std::multiset<LIB_ITEM*, decltype( cmp )> save_map( cmp );
1887 
1888  for( LIB_ITEM* item : unit.m_items )
1889  save_map.insert( item );
1890 
1891  for( LIB_ITEM* item : save_map )
1892  saveSymbolDrawItem( item, aFormatter, aNestLevel + 2 );
1893 
1894  aFormatter.Print( aNestLevel + 1, ")\n" );
1895  }
1896  }
1897  else
1898  {
1899  std::shared_ptr<LIB_SYMBOL> parent = aSymbol->GetParent().lock();
1900 
1901  wxASSERT( parent );
1902 
1903  aFormatter.Print( aNestLevel, "(symbol %s (extends %s)\n",
1904  name.c_str(),
1905  aFormatter.Quotew( parent->GetName() ).c_str() );
1906 
1907  aSymbol->GetFields( fields );
1908 
1909  for( LIB_FIELD* field : fields )
1910  saveField( field, aFormatter, aNestLevel + 1 );
1911 
1912  nextFreeFieldId = aSymbol->GetNextAvailableFieldId();
1913 
1914  saveDcmInfoAsFields( aSymbol, aFormatter, nextFreeFieldId, aNestLevel );
1915  }
1916 
1917  aFormatter.Print( aNestLevel, ")\n" );
1918 }
1919 
1920 
1922  int& aNextFreeFieldId, int aNestLevel )
1923 {
1924  wxCHECK_RET( aSymbol, "Invalid LIB_SYMBOL pointer." );
1925 
1926  if( !aSymbol->GetKeyWords().IsEmpty() )
1927  {
1928  LIB_FIELD keywords( aNextFreeFieldId, wxString( "ki_keywords" ) );
1929  keywords.SetVisible( false );
1930  keywords.SetText( aSymbol->GetKeyWords() );
1931  saveField( &keywords, aFormatter, aNestLevel + 1 );
1932  aNextFreeFieldId += 1;
1933  }
1934 
1935  if( !aSymbol->GetDescription().IsEmpty() )
1936  {
1937  LIB_FIELD description( aNextFreeFieldId, wxString( "ki_description" ) );
1938  description.SetVisible( false );
1939  description.SetText( aSymbol->GetDescription() );
1940  saveField( &description, aFormatter, aNestLevel + 1 );
1941  aNextFreeFieldId += 1;
1942  }
1943 
1944  wxArrayString fpFilters = aSymbol->GetFPFilters();
1945 
1946  if( !fpFilters.IsEmpty() )
1947  {
1948  wxString tmp;
1949 
1950  for( auto filter : fpFilters )
1951  {
1952  // Spaces are not handled in fp filter names so escape spaces if any
1953  wxString curr_filter = EscapeString( filter, ESCAPE_CONTEXT::CTX_NO_SPACE );
1954 
1955  if( tmp.IsEmpty() )
1956  tmp = curr_filter;
1957  else
1958  tmp += " " + curr_filter;
1959  }
1960 
1961  LIB_FIELD description( aNextFreeFieldId, wxString( "ki_fp_filters" ) );
1962  description.SetVisible( false );
1963  description.SetText( tmp );
1964  saveField( &description, aFormatter, aNestLevel + 1 );
1965  aNextFreeFieldId += 1;
1966  }
1967 }
1968 
1969 
1971  int aNestLevel )
1972 {
1973  wxCHECK_RET( aItem, "Invalid LIB_ITEM pointer." );
1974 
1975  switch( aItem->Type() )
1976  {
1977  case LIB_SHAPE_T:
1978  {
1979  LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( aItem );
1980  STROKE_PARAMS stroke;
1981  FILL_T fillMode = shape->GetFillType();
1982 
1983  stroke.SetWidth( shape->GetWidth() );
1984 
1985  switch( shape->GetShape() )
1986  {
1987  case SHAPE_T::ARC:
1988  int x1;
1989  int x2;
1990 
1991  shape->CalcArcAngles( x1, x2 );
1992 
1993  formatArc( &aFormatter, aNestLevel, shape, x1, x2, stroke, fillMode, COLOR4D() );
1994  break;
1995 
1996  case SHAPE_T::CIRCLE:
1997  formatCircle( &aFormatter, aNestLevel, shape, stroke, fillMode, COLOR4D() );
1998  break;
1999 
2000  case SHAPE_T::RECT:
2001  formatRect( &aFormatter, aNestLevel, shape, stroke, fillMode, COLOR4D() );
2002  break;
2003 
2004  case SHAPE_T::BEZIER:
2005  formatBezier(&aFormatter, aNestLevel, shape, stroke, fillMode, COLOR4D() );
2006  break;
2007 
2008  case SHAPE_T::POLY:
2009  formatPoly( &aFormatter, aNestLevel, shape, stroke, fillMode, COLOR4D() );
2010  break;
2011 
2012  default:
2013  UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
2014  }
2015 
2016  break;
2017  }
2018 
2019  case LIB_PIN_T:
2020  savePin( (LIB_PIN* ) aItem, aFormatter, aNestLevel );
2021  break;
2022 
2023  case LIB_TEXT_T:
2024  saveText( ( LIB_TEXT* ) aItem, aFormatter, aNestLevel );
2025  break;
2026 
2027  default:
2028  UNIMPLEMENTED_FOR( aItem->GetClass() );
2029  }
2030 }
2031 
2032 
2034  int aNestLevel )
2035 {
2036  wxCHECK_RET( aField && aField->Type() == LIB_FIELD_T, "Invalid LIB_FIELD object." );
2037 
2038  wxString fieldName = aField->GetName();
2039 
2040  if( aField->GetId() >= 0 && aField->GetId() < MANDATORY_FIELDS )
2041  fieldName = TEMPLATE_FIELDNAME::GetDefaultFieldName( aField->GetId(), false );
2042 
2043  aFormatter.Print( aNestLevel, "(property %s %s (id %d) (at %s %s %g)\n",
2044  aFormatter.Quotew( fieldName ).c_str(),
2045  aFormatter.Quotew( aField->GetText() ).c_str(),
2046  aField->GetId(),
2047  FormatInternalUnits( aField->GetPosition().x ).c_str(),
2048  FormatInternalUnits( aField->GetPosition().y ).c_str(),
2049  static_cast<double>( aField->GetTextAngle() ) / 10.0 );
2050 
2051  aField->Format( &aFormatter, aNestLevel, 0 );
2052  aFormatter.Print( aNestLevel, ")\n" );
2053 }
2054 
2055 
2056 void SCH_SEXPR_PLUGIN_CACHE::savePin( LIB_PIN* aPin, OUTPUTFORMATTER& aFormatter, int aNestLevel )
2057 {
2058  wxCHECK_RET( aPin && aPin->Type() == LIB_PIN_T, "Invalid LIB_PIN object." );
2059 
2060  aPin->ClearFlags( IS_CHANGED );
2061 
2062  aFormatter.Print( aNestLevel, "(pin %s %s (at %s %s %s) (length %s)",
2064  getPinShapeToken( aPin->GetShape() ),
2065  FormatInternalUnits( aPin->GetPosition().x ).c_str(),
2066  FormatInternalUnits( aPin->GetPosition().y ).c_str(),
2067  FormatAngle( getPinAngle( aPin->GetOrientation() ) * 10.0 ).c_str(),
2068  FormatInternalUnits( aPin->GetLength() ).c_str() );
2069 
2070  if( !aPin->IsVisible() )
2071  aFormatter.Print( 0, " hide\n" );
2072  else
2073  aFormatter.Print( 0, "\n" );
2074 
2075  // This follows the EDA_TEXT effects formatting for future expansion.
2076  aFormatter.Print( aNestLevel + 1, "(name %s (effects (font (size %s %s))))\n",
2077  aFormatter.Quotew( aPin->GetName() ).c_str(),
2078  FormatInternalUnits( aPin->GetNameTextSize() ).c_str(),
2079  FormatInternalUnits( aPin->GetNameTextSize() ).c_str() );
2080 
2081  aFormatter.Print( aNestLevel + 1, "(number %s (effects (font (size %s %s))))\n",
2082  aFormatter.Quotew( aPin->GetNumber() ).c_str(),
2083  FormatInternalUnits( aPin->GetNumberTextSize() ).c_str(),
2084  FormatInternalUnits( aPin->GetNumberTextSize() ).c_str() );
2085 
2086 
2087  for( const std::pair<const wxString, LIB_PIN::ALT>& alt : aPin->GetAlternates() )
2088  {
2089  aFormatter.Print( aNestLevel + 1, "(alternate %s %s %s)\n",
2090  aFormatter.Quotew( alt.second.m_Name ).c_str(),
2091  getPinElectricalTypeToken( alt.second.m_Type ),
2092  getPinShapeToken( alt.second.m_Shape ) );
2093  }
2094 
2095  aFormatter.Print( aNestLevel, ")\n" );
2096 }
2097 
2098 
2100  int aNestLevel )
2101 {
2102  wxCHECK_RET( aText && aText->Type() == LIB_TEXT_T, "Invalid LIB_TEXT object." );
2103 
2104  aFormatter.Print( aNestLevel, "(text %s (at %s %s %g)\n",
2105  aFormatter.Quotew( aText->GetText() ).c_str(),
2106  FormatInternalUnits( aText->GetPosition().x ).c_str(),
2107  FormatInternalUnits( aText->GetPosition().y ).c_str(),
2108  aText->GetTextAngle() );
2109  aText->Format( &aFormatter, aNestLevel, 0 );
2110  aFormatter.Print( aNestLevel, ")\n" );
2111 }
2112 
2113 
2114 void SCH_SEXPR_PLUGIN_CACHE::DeleteSymbol( const wxString& aSymbolName )
2115 {
2116  LIB_SYMBOL_MAP::iterator it = m_symbols.find( aSymbolName );
2117 
2118  if( it == m_symbols.end() )
2119  THROW_IO_ERROR( wxString::Format( _( "library %s does not contain a symbol named %s" ),
2120  m_libFileName.GetFullName(), aSymbolName ) );
2121 
2122  LIB_SYMBOL* symbol = it->second;
2123 
2124  if( symbol->IsRoot() )
2125  {
2126  LIB_SYMBOL* rootSymbol = symbol;
2127 
2128  // Remove the root symbol and all its children.
2129  m_symbols.erase( it );
2130 
2131  LIB_SYMBOL_MAP::iterator it1 = m_symbols.begin();
2132 
2133  while( it1 != m_symbols.end() )
2134  {
2135  if( it1->second->IsAlias()
2136  && it1->second->GetParent().lock() == rootSymbol->SharedPtr() )
2137  {
2138  delete it1->second;
2139  it1 = m_symbols.erase( it1 );
2140  }
2141  else
2142  {
2143  it1++;
2144  }
2145  }
2146 
2147  delete rootSymbol;
2148  }
2149  else
2150  {
2151  // Just remove the alias.
2152  m_symbols.erase( it );
2153  delete symbol;
2154  }
2155 
2156  ++m_modHash;
2157  m_isModified = true;
2158 }
2159 
2160 
2161 void SCH_SEXPR_PLUGIN::cacheLib( const wxString& aLibraryFileName, const PROPERTIES* aProperties )
2162 {
2163  if( !m_cache || !m_cache->IsFile( aLibraryFileName ) || m_cache->IsFileChanged() )
2164  {
2165  // a spectacular episode in memory management:
2166  delete m_cache;
2167  m_cache = new SCH_SEXPR_PLUGIN_CACHE( aLibraryFileName );
2168 
2169  // Because m_cache is rebuilt, increment SYMBOL_LIBS::s_modify_generation
2170  // to modify the hash value that indicate symbol to symbol links
2171  // must be updated.
2173 
2174  if( !isBuffering( aProperties ) )
2175  m_cache->Load();
2176  }
2177 }
2178 
2179 
2180 bool SCH_SEXPR_PLUGIN::isBuffering( const PROPERTIES* aProperties )
2181 {
2182  return ( aProperties && aProperties->Exists( SCH_SEXPR_PLUGIN::PropBuffering ) );
2183 }
2184 
2185 
2187 {
2188  if( m_cache )
2189  return m_cache->GetModifyHash();
2190 
2191  // If the cache hasn't been loaded, it hasn't been modified.
2192  return 0;
2193 }
2194 
2195 
2196 void SCH_SEXPR_PLUGIN::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
2197  const wxString& aLibraryPath,
2198  const PROPERTIES* aProperties )
2199 {
2200  LOCALE_IO toggle; // toggles on, then off, the C locale.
2201 
2202  bool powerSymbolsOnly = ( aProperties &&
2203  aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
2204 
2205  cacheLib( aLibraryPath, aProperties );
2206 
2207  const LIB_SYMBOL_MAP& symbols = m_cache->m_symbols;
2208 
2209  for( LIB_SYMBOL_MAP::const_iterator it = symbols.begin(); it != symbols.end(); ++it )
2210  {
2211  if( !powerSymbolsOnly || it->second->IsPower() )
2212  aSymbolNameList.Add( it->first );
2213  }
2214 }
2215 
2216 
2217 void SCH_SEXPR_PLUGIN::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
2218  const wxString& aLibraryPath,
2219  const PROPERTIES* aProperties )
2220 {
2221  LOCALE_IO toggle; // toggles on, then off, the C locale.
2222 
2223  bool powerSymbolsOnly = ( aProperties &&
2224  aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
2225 
2226  cacheLib( aLibraryPath, aProperties );
2227 
2228  const LIB_SYMBOL_MAP& symbols = m_cache->m_symbols;
2229 
2230  for( LIB_SYMBOL_MAP::const_iterator it = symbols.begin(); it != symbols.end(); ++it )
2231  {
2232  if( !powerSymbolsOnly || it->second->IsPower() )
2233  aSymbolList.push_back( it->second );
2234  }
2235 }
2236 
2237 
2238 LIB_SYMBOL* SCH_SEXPR_PLUGIN::LoadSymbol( const wxString& aLibraryPath, const wxString& aSymbolName,
2239  const PROPERTIES* aProperties )
2240 {
2241  LOCALE_IO toggle; // toggles on, then off, the C locale.
2242 
2243  cacheLib( aLibraryPath, aProperties );
2244 
2245  LIB_SYMBOL_MAP::const_iterator it = m_cache->m_symbols.find( aSymbolName );
2246 
2247  if( it == m_cache->m_symbols.end() )
2248  return nullptr;
2249 
2250  return it->second;
2251 }
2252 
2253 
2254 void SCH_SEXPR_PLUGIN::SaveSymbol( const wxString& aLibraryPath, const LIB_SYMBOL* aSymbol,
2255  const PROPERTIES* aProperties )
2256 {
2257  LOCALE_IO toggle; // toggles on, then off, the C locale.
2258 
2259  cacheLib( aLibraryPath, aProperties );
2260 
2261  m_cache->AddSymbol( aSymbol );
2262 
2263  if( !isBuffering( aProperties ) )
2264  m_cache->Save();
2265 }
2266 
2267 
2268 void SCH_SEXPR_PLUGIN::DeleteSymbol( const wxString& aLibraryPath, const wxString& aSymbolName,
2269  const PROPERTIES* aProperties )
2270 {
2271  LOCALE_IO toggle; // toggles on, then off, the C locale.
2272 
2273  cacheLib( aLibraryPath, aProperties );
2274 
2275  m_cache->DeleteSymbol( aSymbolName );
2276 
2277  if( !isBuffering( aProperties ) )
2278  m_cache->Save();
2279 }
2280 
2281 
2282 void SCH_SEXPR_PLUGIN::CreateSymbolLib( const wxString& aLibraryPath,
2283  const PROPERTIES* aProperties )
2284 {
2285  if( wxFileExists( aLibraryPath ) )
2286  {
2287  THROW_IO_ERROR( wxString::Format( _( "Symbol library '%s' already exists." ),
2288  aLibraryPath.GetData() ) );
2289  }
2290 
2291  LOCALE_IO toggle;
2292 
2293  delete m_cache;
2294  m_cache = new SCH_SEXPR_PLUGIN_CACHE( aLibraryPath );
2295  m_cache->SetModified();
2296  m_cache->Save();
2297  m_cache->Load(); // update m_writable and m_mod_time
2298 }
2299 
2300 
2301 bool SCH_SEXPR_PLUGIN::DeleteSymbolLib( const wxString& aLibraryPath,
2302  const PROPERTIES* aProperties )
2303 {
2304  wxFileName fn = aLibraryPath;
2305 
2306  if( !fn.FileExists() )
2307  return false;
2308 
2309  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
2310  // we don't want that. we want bare metal portability with no UI here.
2311  if( wxRemove( aLibraryPath ) )
2312  {
2313  THROW_IO_ERROR( wxString::Format( _( "Symbol library '%s' cannot be deleted." ),
2314  aLibraryPath.GetData() ) );
2315  }
2316 
2317  if( m_cache && m_cache->IsFile( aLibraryPath ) )
2318  {
2319  delete m_cache;
2320  m_cache = nullptr;
2321  }
2322 
2323  return true;
2324 }
2325 
2326 
2327 void SCH_SEXPR_PLUGIN::SaveLibrary( const wxString& aLibraryPath, const PROPERTIES* aProperties )
2328 {
2329  if( !m_cache )
2330  m_cache = new SCH_SEXPR_PLUGIN_CACHE( aLibraryPath );
2331 
2332  wxString oldFileName = m_cache->GetFileName();
2333 
2334  if( !m_cache->IsFile( aLibraryPath ) )
2335  {
2336  m_cache->SetFileName( aLibraryPath );
2337  }
2338 
2339  // This is a forced save.
2340  m_cache->SetModified();
2341  m_cache->Save();
2342  m_cache->SetFileName( oldFileName );
2343 }
2344 
2345 
2346 bool SCH_SEXPR_PLUGIN::CheckHeader( const wxString& aFileName )
2347 {
2348  // Open file and check first line
2349  wxTextFile tempFile;
2350 
2351  tempFile.Open( aFileName );
2352  wxString firstline;
2353  // read the first line
2354  firstline = tempFile.GetFirstLine();
2355  tempFile.Close();
2356 
2357  return firstline.StartsWith( "EESchema" );
2358 }
2359 
2360 
2361 bool SCH_SEXPR_PLUGIN::IsSymbolLibWritable( const wxString& aLibraryPath )
2362 {
2363  wxFileName fn( aLibraryPath );
2364 
2365  return ( fn.FileExists() && fn.IsFileWritable() ) || fn.IsDirWritable();
2366 }
2367 
2368 
2370 {
2371  LOCALE_IO toggle; // toggles on, then off, the C locale.
2372  LIB_SYMBOL_MAP map;
2373  SCH_SEXPR_PARSER parser( &aReader );
2374 
2375  parser.NeedLEFT();
2376  parser.NextTok();
2377 
2378  return parser.ParseSymbol( map, aFileVersion );
2379 }
2380 
2381 
2383 {
2384 
2385  LOCALE_IO toggle; // toggles on, then off, the C locale.
2386  SCH_SEXPR_PLUGIN_CACHE::SaveSymbol( symbol, formatter );
2387 }
2388 
2389 
2390 const char* SCH_SEXPR_PLUGIN::PropBuffering = "buffering";
Field Reference of part, i.e. "IC21".
void CalcArcAngles(int &aStartAngle, int &aEndAngle) const
Definition: lib_shape.cpp:430
power input (GND, VCC for ICs). Must be connected to a power output.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
LIB_FIELD * FindField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName and returns it or NULL if not found.
SCH_LIB_TYPE
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:230
SCHEMATIC * m_schematic
#define IS_CHANGED
Item was edited, and modified.
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:49
LIB_SYMBOL_REF & GetParent()
Definition: lib_symbol.h:124
int GetPinNameOffset() const
Definition: lib_symbol.h:572
int m_version
Version of file being loaded.
std::map< wxString, LIB_SYMBOL *, LibSymbolMapSort > LIB_SYMBOL_MAP
Symbol map used by symbol library object.
LIB_SYMBOL_SPTR SharedPtr() const
Definition: lib_symbol.h:107
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition: richio.h:80
void SetWidth(int aWidth)
Definition: sch_item.h:153
const UTF8 & GetLibItemName() const
Definition: lib_id.h:104
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:214
int GetWidth() const
Definition: eda_shape.h:98
bool m_CompactSave
Save files in compact display mode When is is not specified, points are written one per line.
bool SearchHierarchy(const wxString &aFilename, SCH_SCREEN **aScreen)
Search the existing hierarchy for an instance of screen loaded from aFileName.
Definition: sch_sheet.cpp:693
#define DEFAULT_SIZE_TEXT
This is the "default-of-the-default" hardcoded text size; individual application define their own def...
Definition: eda_text.h:101
KIID niluuid(0)
void saveLine(SCH_LINE *aLine, int aNestLevel)
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
static void formatFill(OUTPUTFORMATTER *aFormatter, int aNestLevel, FILL_T aFillMode, const COLOR4D &aFillColor)
Fill token formatting helper.
void saveNoConnect(SCH_NO_CONNECT *aNoConnect, int aNestLevel)
Schematic and symbol library s-expression file format parser definitions.
static const char * getTextTypeToken(KICAD_T aType)
void Format(SCH_SHEET *aSheet)
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:40
SCH_SEXPR_PLUGIN_CACHE(const wxString &aLibraryPath)
SCH_SCREEN * GetScreen()
Definition: ee_selection.h:51
wxPoint GetStartPoint() const
Definition: sch_line.h:90
int GetNextAvailableFieldId() const
std::vector< SYMBOL_INSTANCE_REFERENCE > m_symbolInstances
The list of symbol instances loaded from the schematic file.
Definition: sch_screen.h:571
void Save()
Save the entire library to file m_libFileName;.
Holds all the data relating to one schematic.
Definition: schematic.h:59
wxString m_error
For throwing exceptions or errors on partial loads.
The first 2 are mandatory, and must be instantiated in SCH_SHEET.
Definition: sch_sheet.h:47
wxPoint GetPosition() const override
Definition: lib_field.h:157
static void saveText(LIB_TEXT *aText, OUTPUTFORMATTER &aFormatter, int aNestLevel=0)
wxPoint GetPosition() const override
const wxPoint & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:106
void saveJunction(SCH_JUNCTION *aJunction, int aNestLevel)
wxString GetName() const override
Definition: lib_symbol.h:133
Define a symbol library graphical text item.
Definition: lib_text.h:39
int GetOrientation() const
Definition: lib_pin.h:75
virtual STROKE_PARAMS GetStroke() const override
Definition: sch_bus_entry.h:81
GRAPHIC_PINSHAPE GetShape() const
Definition: lib_pin.h:78
wxString GetFileName() const
void DeleteSymbol(const wxString &aLibraryPath, const wxString &aSymbolName, const PROPERTIES *aProperties=nullptr) override
Delete the entire LIB_SYMBOL associated with aAliasName from the library aLibraryPath.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
static void formatPoly(OUTPUTFORMATTER *aFormatter, int aNestLevel, EDA_SHAPE *aPolyLine, const STROKE_PARAMS &aStroke, FILL_T aFillMode, const COLOR4D &aFillColor, KIID aUuid=niluuid)
wxPoint GetPosition() const override
Definition: sch_field.cpp:842
std::stack< wxString > m_currentPath
Stack to maintain nested sheet paths.
wxPoint GetPosition() const override
Definition: lib_text.h:91
SCH_SEXPR_PLUGIN_CACHE * m_cache
Field object used in symbol libraries.
Definition: lib_field.h:59
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:175
const wxChar *const traceSchLegacyPlugin
Flag to enable legacy schematic plugin debug output.
double GetScale() const
Definition: bitmap_base.h:79
pin for passive symbols: must be connected, and can be connected to any pin
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition: schematic.h:108
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
Definition: sch_symbol.cpp:741
wxImage * GetImageData()
Definition: bitmap_base.h:70
bool ShowPinNumbers() const
Definition: lib_symbol.h:588
void SetFileName(const wxString &aFileName)
SCH_SHEET * m_rootSheet
The root sheet of the schematic being loaded.
void Save(const wxString &aFileName, SCH_SHEET *aSheet, SCHEMATIC *aSchematic, const PROPERTIES *aProperties=nullptr) override
Write aSchematic to a storage file in a format that this SCH_PLUGIN implementation knows about,...
LIB_SYMBOL * ParseSymbol(LIB_SYMBOL_MAP &aSymbolLibMap, int aFileVersion=SEXPR_SYMBOL_LIB_FILE_VERSION)
bool GetIncludeInBom() const
Definition: sch_symbol.h:663
std::vector< SYMBOL_INSTANCE_REFERENCE > GetSymbolInstances() const
double GetTextAngle() const
Definition: eda_text.h:195
bool GetIncludeOnBoard() const
Definition: lib_symbol.h:604
int GetId() const
Definition: sch_field.h:113
static void formatCircle(OUTPUTFORMATTER *aFormatter, int aNestLevel, EDA_SHAPE *aCircle, const STROKE_PARAMS &aStroke, FILL_T aFillMode, const COLOR4D &aFillColor, KIID aUuid=niluuid)
unknown electrical properties: creates always a warning when connected
void saveText(SCH_TEXT *aText, int aNestLevel)
static const wxString GetDefaultFieldName(int aFieldNdx, bool aTranslated=true)
Definition: sch_sheet.cpp:53
void saveInstances(const std::vector< SCH_SHEET_INSTANCE > &aSheets, const std::vector< SYMBOL_INSTANCE_REFERENCE > &aSymbols, int aNestLevel)
wxString AsString() const
Definition: kiid.cpp:236
const TITLE_BLOCK & GetTitleBlock() const
Definition: sch_screen.h:156
An interface used to output 8 bit text in a convenient way.
Definition: richio.h:309
int GetDiameter() const
Definition: sch_junction.h:110
double g
Green component.
Definition: color4d.h:385
static const char * emptyString
KIGFX::COLOR4D GetBorderColor() const
Definition: sch_sheet.h:110
bool IsPower() const
Definition: lib_symbol.cpp:459
void DeleteSymbol(const wxString &aName)
virtual std::string Quotes(const std::string &aWrapee) const
Check aWrapee input string for a need to be quoted (e.g.
Definition: richio.cpp:455
void saveField(SCH_FIELD *aField, int aNestLevel)
void AddSymbol(const LIB_SYMBOL *aSymbol)
Definition: lib_pin.h:48
int GetId() const
Definition: lib_field.h:115
void SetFileExists(bool aFileExists)
Definition: sch_screen.h:150
#define SEXPR_SYMBOL_LIB_FILE_VERSION
This file contains the file format version information for the s-expression schematic and symbol libr...
static float getPinAngle(int aOrientation)
void SaveSymbol(const wxString &aLibraryPath, const LIB_SYMBOL *aSymbol, const PROPERTIES *aProperties=nullptr) override
Write aSymbol to an existing library located at aLibraryPath.
wxPoint GetPosition() const override
Definition: sch_bitmap.h:136
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
GRAPHIC_PINSHAPE
Definition: pin_type.h:55
void Format(OUTPUTFORMATTER *aFormatter, int aNestLevel, int aControlBits) const
Output the page class to aFormatter in s-expression form.
Definition: page_info.cpp:271
LIB_SYMBOL * removeSymbol(LIB_SYMBOL *aAlias)
A name/value tuple with unique names and optional values.
Definition: properties.h:33
std::string toUTFTildaText(const wxString &txt)
Convert a wxString to UTF8 and replace any control characters with a ~, where a control character is ...
Definition: sch_symbol.cpp:46
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:102
Define a library symbol object.
Definition: lib_symbol.h:96
const PAGE_INFO & GetPageSettings() const
Definition: sch_screen.h:132
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:122
int m_unit
The unit number.
Definition: lib_symbol.h:84
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:115
FIELDS_AUTOPLACED GetFieldsAutoplaced() const
Return whether the fields have been automatically placed.
Definition: sch_item.h:424
wxString GetName(bool aUseDefaultName=true) const
Return the field name.
Definition: lib_field.cpp:393
FILL_T
Definition: eda_shape.h:53
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition: eda_item.cpp:83
std::vector< struct LIB_SYMBOL_UNIT > GetUnitDrawItems()
Return a list of LIB_ITEM objects separated by unit and convert number.
The base class for drawable items used by schematic library symbols.
Definition: lib_item.h:61
double b
Blue component.
Definition: color4d.h:386
void GetFields(std::vector< LIB_FIELD * > &aList)
Return a list of fields within this symbol.
Definition: lib_symbol.cpp:982
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
void SetEndPoint(const wxPoint &aPosition)
Definition: sch_line.h:94
int GetTextHeight() const
Definition: eda_text.h:265
KIGFX::COLOR4D GetBackgroundColor() const
Definition: sch_sheet.h:113
Base class for a bus or wire entry.
Definition: sch_bus_entry.h:42
const std::vector< SYMBOL_INSTANCE_REFERENCE > & GetInstanceReferences()
Definition: sch_symbol.h:123
static const char * getPinShapeToken(GRAPHIC_PINSHAPE aShape)
void Rewind()
Rewind the file and resets the line number back to zero.
Definition: richio.h:222
std::vector< SCH_FIELD > & GetFields()
Definition: sch_sheet.h:90
A cache assistant for the symbol library portion of the SCH_PLUGIN API, and only for the SCH_SEXPR_PL...
const wxPoint & GetBezierC1() const
Definition: eda_shape.h:154
void SetFileReadOnly(bool aIsReadOnly)
Definition: sch_screen.h:147
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
COLOR4D GetColor() const
Definition: sch_junction.h:115
not internally connected (may be connected to anything)
virtual void SetVisible(bool aVisible)
Definition: eda_text.h:206
Definition: kiid.h:44
void saveBusEntry(SCH_BUS_ENTRY_BASE *aBusEntry, int aNestLevel)
void SetModified(bool aModified=true)
int m_convert
The alternate body style of the unit.
Definition: lib_symbol.h:85
std::string FormatAngle(double aAngle)
Function FormatAngle converts aAngle from board units to a string appropriate for writing to file.
Definition: base_units.cpp:520
int GetBorderWidth() const
Definition: sch_sheet.h:107
double a
Alpha component.
Definition: color4d.h:387
A LINE_READER that reads from an open file.
Definition: richio.h:172
static LIB_SYMBOL * ParseLibSymbol(LINE_READER &aReader, int aVersion=SEXPR_SCHEMATIC_FILE_VERSION)
const wxPoint & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:131
void saveBusAlias(std::shared_ptr< BUS_ALIAS > aAlias, int aNestLevel)
wxFileName GetRealFile() const
void CreateSymbolLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=nullptr) override
Create a new empty symbol library at aLibraryPath.
bool IsFile(const wxString &aFullPathAndFileName) const
wxString GetKeyWords() const
Definition: lib_symbol.h:155
Field Value of part, i.e. "3.3K".
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:124
static void FormatLibSymbol(LIB_SYMBOL *aPart, OUTPUTFORMATTER &aFormatter)
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
const std::vector< VECTOR2I > & CPoints() const
BITMAP_BASE * GetImage() const
Definition: sch_bitmap.h:54
SCH_LAYER_ID
Eeschema drawing layers.
Definition: layer_ids.h:335
wxString GetLogicalName() const
wxPoint GetPosition() const override
Definition: sch_junction.h:103
LIB_ID GetLibId() const override
Definition: lib_symbol.h:135
const wxString & GetName() const
Definition: lib_pin.h:106
std::vector< SCH_SHEET_INSTANCE > m_sheetInstances
Definition: sch_screen.h:572
SHAPE_LINE_CHAIN & Outline(int aIndex)
wxString GetSchSymbolLibraryName() const
Definition: sch_symbol.cpp:271
void cacheLib(const wxString &aLibraryFileName, const PROPERTIES *aProperties)
bool IsRootSheet() const
Definition: sch_sheet.cpp:207
static const char * getPinElectricalTypeToken(ELECTRICAL_PINTYPE aType)
void SaveLibrary(const wxString &aLibraryPath, const PROPERTIES *aProperties=nullptr) override
static void ResolvePossibleSymlinks(wxFileName &aFilename)
Definition: wx_filename.cpp:85
const wxPoint & GetBezierC2() const
Definition: eda_shape.h:157
static double getSheetPinAngle(SHEET_SIDE aSide)
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
Definition: lib_field.cpp:402
static void IncrementModifyGeneration()
#define MIME_BASE64_LENGTH
static wxString getLineStyleToken(PLOT_DASH_TYPE aStyle)
A simple container for schematic symbol instance information.
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const PROPERTIES *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:120
Definition for symbol library class.
PLOT_DASH_TYPE GetPlotStyle() const
Definition: sch_item.h:155
EDA_ITEM * GetParent() const
Definition: eda_item.h:114
bool ShowPinNames() const
Definition: lib_symbol.h:580
#define _(s)
std::vector< SCH_SHEET_INSTANCE > GetSheetInstances() const
Fetch the instance information for all of the sheets in the hiearchy.
static void savePin(LIB_PIN *aPin, OUTPUTFORMATTER &aFormatter, int aNestLevel=0)
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:153
wxLogTrace helper definitions.
bool isBuffering(const PROPERTIES *aProperties)
std::map< wxString, LIB_SYMBOL * > & GetLibSymbols()
Fetch a list of unique LIB_SYMBOL object pointers required to properly render each SCH_SYMBOL in this...
Definition: sch_screen.h:451
void AddDrawItem(LIB_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
Definition: lib_symbol.cpp:716
virtual void Format(OUTPUTFORMATTER *aFormatter, int aNestLevel, int aControlBits) const
Output the object to aFormatter in s-expression form.
Definition: title_block.cpp:29
static void formatBezier(OUTPUTFORMATTER *aFormatter, int aNestLevel, EDA_SHAPE *aBezier, const STROKE_PARAMS &aStroke, FILL_T aFillMode, const COLOR4D &aFillColor, KIID aUuid=niluuid)
LABEL_SPIN_STYLE GetLabelSpinStyle() const
Definition: sch_text.h:159
virtual void Format(OUTPUTFORMATTER *aFormatter, int aNestLevel, int aControlBits) const
Output the object to aFormatter in s-expression form.
Definition: eda_text.cpp:539
bool IsVisible() const
Definition: lib_pin.h:97
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
int GetWidth() const
Definition: sch_item.h:152
static void formatStroke(OUTPUTFORMATTER *aFormatter, int aNestLevel, const STROKE_PARAMS &aStroke)
Write stroke definition to aFormatter.
static const wxString GetDefaultFieldName(int aFieldNdx, bool aTranslate=true)
Return a default symbol field name for field aFieldNdx for all components.
Object to parser s-expression symbol library and schematic file formats.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
int GetNameTextSize() const
Definition: lib_pin.h:126
#define DEFAULT_PIN_NAME_OFFSET
The intersheets references prefix string.
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:314
bool IsDefaultFormatting() const
Definition: eda_text.cpp:525
wxString SHAPE_T_asString() const
Definition: eda_shape.cpp:71
void AppendSymbol(SCH_REFERENCE_LIST &aReferences, SCH_SYMBOL *aSymbol, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Append a SCH_REFERENCE object to aReferences based on aSymbol.
wxPoint GetPosition() const override
Definition: sch_text.h:241
wxPoint GetPosition() const override
Definition: sch_sheet.h:379
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:484
void loadFile(const wxString &aFileName, SCH_SHEET *aSheet)
Object to handle a bitmap image that can be inserted in a schematic.
Definition: sch_bitmap.h:40
KIID_PATH PathWithoutRootUuid() const
Get the sheet path as an KIID_PATH without the root sheet UUID prefix.
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:227
UTF8 Format() const
Definition: lib_id.cpp:116
std::vector< std::unique_ptr< SCH_PIN > > & GetRawPins()
Definition: sch_symbol.h:471
bool UnitsLocked() const
Check whether symbol units are interchangeable.
Definition: lib_symbol.h:241
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
PLOT_DASH_TYPE
Dashed line types.
Definition: plotter.h:104
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
Definition: schematic.h:75
const KIID m_Uuid
Definition: eda_item.h:474
wxPoint GetPosition() const override
Definition: lib_pin.h:212
PROGRESS_REPORTER * m_progressReporter
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:88
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:259
bool IsSymbolLibWritable(const wxString &aLibraryPath) override
Return true if the library at aLibraryPath is writable.
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:183
static void saveField(LIB_FIELD *aField, OUTPUTFORMATTER &aFormatter, int aNestLevel)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
SCH_SHEET * Load(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const PROPERTIES *aProperties=nullptr) override
Load information from some input file format that this SCH_PLUGIN implementation knows about,...
OUTPUTFORMATTER * m_out
The formatter for saving SCH_SCREEN objects.
SCH_FIELD * GetIntersheetRefs()
Definition: sch_text.h:415
const wxString & GetNumber() const
Definition: lib_pin.h:116
ELECTRICAL_PINTYPE GetType() const
Definition: lib_pin.h:84
void LoadContent(LINE_READER &aReader, SCH_SHEET *aSheet, int aVersion=SEXPR_SCHEMATIC_FILE_VERSION)
COLOR4D GetColor() const
Definition: sch_item.h:158
std::unordered_set< std::shared_ptr< BUS_ALIAS > > GetBusAliases() const
Return a list of bus aliases defined in this screen.
Definition: sch_screen.h:481
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:49
std::map< wxString, ALT > & GetAlternates()
Definition: lib_pin.h:132
wxSize GetSize() const
Definition: sch_bus_entry.h:75
PINSHEETLABEL_SHAPE
Definition: sch_text.h:95
double GetTextAngleDegrees() const
Definition: eda_text.h:197
SCH_SHEET & Root() const
Definition: schematic.h:92
A simple container for sheet instance information.
wxString m_path
Root project path for loading child sheets.
static void formatArc(OUTPUTFORMATTER *aFormatter, int aNestLevel, EDA_SHAPE *aArc, int x1, int x2, const STROKE_PARAMS &aStroke, FILL_T aFillMode, const COLOR4D &aFillColor, KIID aUuid=niluuid)
int GetNumberTextSize() const
Definition: lib_pin.h:129
bool Exists(const std::string &aProperty) const
Definition: properties.h:41
Schematic symbol object.
Definition: sch_symbol.h:78
const char * name
Definition: DXF_plotter.cpp:56
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
bool CheckHeader(const wxString &aFileName) override
Return true if the first line in aFileName begins with the expected header.
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
Definition: pin_type.h:35
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:53
void SortByReferenceOnly()
Sort the list of references by reference.
int GetLength() const
Definition: lib_pin.h:81
Simple container to manage line stroke parameters.
Definition: sch_item.h:140
usual pin input: must be connected
wxSize GetSize() const
Definition: sch_sheet.h:104
KIID m_uuid
A unique identifier for each schematic file.
Definition: sch_screen.h:580
static void saveDcmInfoAsFields(LIB_SYMBOL *aSymbol, OUTPUTFORMATTER &aFormatter, int &aNextFreeFieldId, int aNestLevel)
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
wxString GetName(bool aUseDefaultName=true) const
Return the field name.
Definition: sch_field.cpp:678
wxString GetClass() const override
Return the class name.
Definition: lib_text.h:48
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
wxPoint GetArcMid() const
Definition: eda_shape.cpp:437
void SortByPageNumbers(bool aUpdateVirtualPageNums=true)
Sort the list of sheets by page number.
wxString wx_str() const
Definition: utf8.cpp:46
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
wxPoint GetPosition() const override
Definition: sch_symbol.h:645
std::string Double2Str(double aValue)
Print a float number without using scientific notation and no trailing 0 We want to avoid scientific ...
bool GetIncludeOnBoard() const
Definition: sch_symbol.h:666
void saveSheet(SCH_SHEET *aSheet, int aNestLevel)
wxArrayString GetFPFilters() const
Definition: lib_symbol.h:183
virtual STROKE_PARAMS GetStroke() const override
Definition: sch_line.h:136
Used for text file output.
Definition: richio.h:456
virtual wxString GetClass() const override
Return the class name.
Definition: sch_item.h:193
void ParseSchematic(SCH_SHEET *aSheet, bool aIsCopyablyOnly=false, int aFileVersion=SEXPR_SCHEMATIC_FILE_VERSION)
Parse the internal LINE_READER object into aSheet.
void loadHierarchy(SCH_SHEET *aSheet)
int GetOrientation()
Get the display symbol orientation.
static void SaveSymbol(LIB_SYMBOL *aSymbol, OUTPUTFORMATTER &aFormatter, int aNestLevel=0, const wxString &aLibName=wxEmptyString)
KICAD_PLUGIN_EXPORT SCENEGRAPH * Load(char const *aFileName)
reads a model file and creates a generic display structure
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
input or output (like port for a microprocessor)
static void formatRect(OUTPUTFORMATTER *aFormatter, int aNestLevel, EDA_SHAPE *aRect, const STROKE_PARAMS &aStroke, FILL_T aFillMode, const COLOR4D &aFillColor, KIID aUuid=niluuid)
bool IsRoot() const override
For symbols derived from other symbols, IsRoot() indicates no derivation.
Definition: lib_symbol.h:171
std::string EscapedUTF8(const wxString &aString)
Return an 8 bit UTF8 string given aString in Unicode form.
SHEET_SIDE
Define the edge of the sheet that the sheet pin is positioned.
Definition: sch_sheet_pin.h:45
void saveSymbol(SCH_SYMBOL *aSymbol, SCH_SHEET_PATH *aSheetPath, int aNestLevel)
void GetSymbolsWithinPath(SCH_REFERENCE_LIST &aReferences, const SCH_SHEET_PATH &aSheetPath, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets that are contained wi...
SHAPE_T GetShape() const
Definition: eda_shape.h:101
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:110
double r
Red component.
Definition: color4d.h:384
void SetId(int aId)
Definition: sch_field.cpp:80
void init(SCHEMATIC *aSchematic, const PROPERTIES *aProperties=nullptr)
initialize PLUGIN like a constructor would.
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition: richio.cpp:426
int GetUnit() const
Definition: sch_symbol.h:196
#define SEXPR_SCHEMATIC_FILE_VERSION
Schematic file version.
int GetRadius() const
Definition: eda_shape.cpp:472
static void saveSymbolDrawItem(LIB_ITEM *aItem, OUTPUTFORMATTER &aFormatter, int aNestLevel)
not connected (must be left open)
wxString GetDescription() override
Definition: lib_symbol.h:142
int GetModifyHash() const override
Return the modification hash from the library cache.
int GetConvert() const
Definition: sch_symbol.h:224
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
output of a regulator: intended to be connected to power input pins
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:154
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
static const char * PropPowerSymsOnly
FILL_T GetFillType() const
Definition: eda_shape.h:88
std::string FormatInternalUnits(int aValue)
Function FormatInternalUnits converts aValue from internal units to a string appropriate for writing ...
Definition: base_units.cpp:485
void saveBitmap(SCH_BITMAP *aBitmap, int aNestLevel)
bool DeleteSymbolLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=nullptr) override
Delete an existing symbol library and returns true if successful, or if library does not exist return...
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const PROPERTIES *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
static const char * getSheetPinShapeToken(PINSHEETLABEL_SHAPE aShape)
PINSHEETLABEL_SHAPE GetShape() const
Definition: sch_text.h:161
bool UseLibIdLookup() const
Definition: sch_symbol.h:163
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
std::string Quotew(const wxString &aWrapee) const
Definition: richio.cpp:494
wxPoint GetEnd() const
bool GetIncludeInBom() const
Definition: lib_symbol.h:596
const LIB_ID & GetLibId() const
Definition: sch_symbol.h:148
void GetSheetsWithinPath(SCH_SHEET_PATHS &aSheets, const SCH_SHEET_PATH &aSheetPath) const
Add a SCH_SHEET_PATH object to aSheets for each sheet in the list that are contained within aSheetPat...
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
wxPoint GetPosition() const override
Field Name Module PCB, i.e. "16DIP300".
wxPoint GetEndPoint() const
Definition: sch_line.h:93