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