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