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