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