KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_io_kicad_sexpr.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 The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Wayne Stambaugh <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <algorithm>
24
25#include <fmt/format.h>
26
27#include <wx/log.h>
28#include <wx/mstream.h>
29
30#include <base_units.h>
31#include <bitmap_base.h>
32#include <build_version.h>
33#include <sch_selection.h>
34#include <font/fontconfig.h>
36#include <progress_reporter.h>
37#include <schematic.h>
38#include <schematic_lexer.h>
39#include <sch_bitmap.h>
40#include <sch_bus_entry.h>
41#include <sch_edit_frame.h> // SYMBOL_ORIENTATION_T
42#include <sch_group.h>
47#include <sch_junction.h>
48#include <sch_line.h>
49#include <sch_no_connect.h>
50#include <sch_pin.h>
51#include <sch_rule_area.h>
52#include <sch_screen.h>
53#include <sch_shape.h>
54#include <sch_sheet.h>
55#include <sch_sheet_pin.h>
56#include <sch_symbol.h>
57#include <sch_table.h>
58#include <sch_tablecell.h>
59#include <sch_text.h>
60#include <sch_textbox.h>
61#include <string_utils.h>
62#include <symbol_lib_table.h> // for PropPowerSymsOnly definition.
63#include <trace_helpers.h>
64
65using namespace TSCHEMATIC_T;
66
67
68#define SCH_PARSE_ERROR( text, reader, pos ) \
69 THROW_PARSE_ERROR( text, reader.GetSource(), reader.Line(), \
70 reader.LineNumber(), pos - reader.Line() )
71
72
73SCH_IO_KICAD_SEXPR::SCH_IO_KICAD_SEXPR() : SCH_IO( wxS( "Eeschema s-expression" ) )
74{
75 init( nullptr );
76}
77
78
83
84
86 const std::map<std::string, UTF8>* aProperties )
87{
88 m_version = 0;
89 m_appending = false;
90 m_rootSheet = nullptr;
91 m_schematic = aSchematic;
92 m_cache = nullptr;
93 m_out = nullptr;
94}
95
96
97SCH_SHEET* SCH_IO_KICAD_SEXPR::LoadSchematicFile( const wxString& aFileName, SCHEMATIC* aSchematic,
98 SCH_SHEET* aAppendToMe,
99 const std::map<std::string, UTF8>* aProperties )
100{
101 wxASSERT( !aFileName || aSchematic != nullptr );
102
103 SCH_SHEET* sheet;
104
105 wxFileName fn = aFileName;
106
107 // Show the font substitution warnings
109
110 // Unfortunately child sheet file names the legacy schematic file format are not fully
111 // qualified and are always appended to the project path. The aFileName attribute must
112 // always be an absolute path so the project path can be used for load child sheet files.
113 wxASSERT( fn.IsAbsolute() );
114
115 if( aAppendToMe )
116 {
117 m_appending = true;
118 wxLogTrace( traceSchPlugin, "Append \"%s\" to sheet \"%s\".",
119 aFileName, aAppendToMe->GetFileName() );
120
121 wxFileName normedFn = aAppendToMe->GetFileName();
122
123 if( !normedFn.IsAbsolute() )
124 {
125 if( aFileName.Right( normedFn.GetFullPath().Length() ) == normedFn.GetFullPath() )
126 m_path = aFileName.Left( aFileName.Length() - normedFn.GetFullPath().Length() );
127 }
128
129 if( m_path.IsEmpty() )
130 m_path = aSchematic->Project().GetProjectPath();
131
132 wxLogTrace( traceSchPlugin, "Normalized append path \"%s\".", m_path );
133 }
134 else
135 {
136 m_path = aSchematic->Project().GetProjectPath();
137 }
138
139 m_currentPath.push( m_path );
140 init( aSchematic, aProperties );
141
142 if( aAppendToMe == nullptr )
143 {
144 // Clean up any allocated memory if an exception occurs loading the schematic.
145 std::unique_ptr<SCH_SHEET> newSheet = std::make_unique<SCH_SHEET>( aSchematic );
146
147 wxFileName relPath( aFileName );
148
149 // Do not use wxPATH_UNIX as option in MakeRelativeTo(). It can create incorrect
150 // relative paths on Windows, because paths have a disk identifier (C:, D: ...)
151 relPath.MakeRelativeTo( aSchematic->Project().GetProjectPath() );
152
153 newSheet->SetFileName( relPath.GetFullPath() );
154 m_rootSheet = newSheet.get();
155 loadHierarchy( SCH_SHEET_PATH(), newSheet.get() );
156
157 // If we got here, the schematic loaded successfully.
158 sheet = newSheet.release();
159 m_rootSheet = nullptr; // Quiet Coverity warning.
160 }
161 else
162 {
163 wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
164 m_rootSheet = &aSchematic->Root();
165 sheet = aAppendToMe;
166 loadHierarchy( SCH_SHEET_PATH(), sheet );
167 }
168
169 wxASSERT( m_currentPath.size() == 1 ); // only the project path should remain
170
171 m_currentPath.pop(); // Clear the path stack for next call to Load
172
173 return sheet;
174}
175
176
177// Everything below this comment is recursive. Modify with care.
178
179void SCH_IO_KICAD_SEXPR::loadHierarchy( const SCH_SHEET_PATH& aParentSheetPath, SCH_SHEET* aSheet )
180{
181 m_currentSheetPath.push_back( aSheet );
182
183 SCH_SCREEN* screen = nullptr;
184
185 if( !aSheet->GetScreen() )
186 {
187 // SCH_SCREEN objects store the full path and file name where the SCH_SHEET object only
188 // stores the file name and extension. Add the project path to the file name and
189 // extension to compare when calling SCH_SHEET::SearchHierarchy().
190 wxFileName fileName = aSheet->GetFileName();
191
192 if( !fileName.IsAbsolute() )
193 fileName.MakeAbsolute( m_currentPath.top() );
194
195 // Save the current path so that it gets restored when descending and ascending the
196 // sheet hierarchy which allows for sheet schematic files to be nested in folders
197 // relative to the last path a schematic was loaded from.
198 wxLogTrace( traceSchPlugin, "Saving path '%s'", m_currentPath.top() );
199 m_currentPath.push( fileName.GetPath() );
200 wxLogTrace( traceSchPlugin, "Current path '%s'", m_currentPath.top() );
201 wxLogTrace( traceSchPlugin, "Loading '%s'", fileName.GetFullPath() );
202
203 SCH_SHEET_PATH ancestorSheetPath = aParentSheetPath;
204
205 while( !ancestorSheetPath.empty() )
206 {
207 if( ancestorSheetPath.LastScreen()->GetFileName() == fileName.GetFullPath() )
208 {
209 if( !m_error.IsEmpty() )
210 m_error += "\n";
211
212 m_error += wxString::Format( _( "Could not load sheet '%s' because it already "
213 "appears as a direct ancestor in the schematic "
214 "hierarchy." ),
215 fileName.GetFullPath() );
216
217 fileName = wxEmptyString;
218
219 break;
220 }
221
222 ancestorSheetPath.pop_back();
223 }
224
225 if( ancestorSheetPath.empty() )
226 {
227 // Existing schematics could be either in the root sheet path or the current sheet
228 // load path so we have to check both.
229 if( !m_rootSheet->SearchHierarchy( fileName.GetFullPath(), &screen ) )
230 m_currentSheetPath.at( 0 )->SearchHierarchy( fileName.GetFullPath(), &screen );
231 }
232
233 if( screen )
234 {
235 aSheet->SetScreen( screen );
236 aSheet->GetScreen()->SetParent( m_schematic );
237 // Do not need to load the sub-sheets - this has already been done.
238 }
239 else
240 {
241 aSheet->SetScreen( new SCH_SCREEN( m_schematic ) );
242 aSheet->GetScreen()->SetFileName( fileName.GetFullPath() );
243
244 try
245 {
246 loadFile( fileName.GetFullPath(), aSheet );
247 }
248 catch( const IO_ERROR& ioe )
249 {
250 // If there is a problem loading the root sheet, there is no recovery.
251 if( aSheet == m_rootSheet )
252 throw;
253
254 // For all subsheets, queue up the error message for the caller.
255 if( !m_error.IsEmpty() )
256 m_error += "\n";
257
258 m_error += ioe.What();
259 }
260
261 if( fileName.FileExists() )
262 {
263 aSheet->GetScreen()->SetFileReadOnly( !fileName.IsFileWritable() );
264 aSheet->GetScreen()->SetFileExists( true );
265 }
266 else
267 {
268 aSheet->GetScreen()->SetFileReadOnly( !fileName.IsDirWritable() );
269 aSheet->GetScreen()->SetFileExists( false );
270 }
271
272 SCH_SHEET_PATH currentSheetPath = aParentSheetPath;
273 currentSheetPath.push_back( aSheet );
274
275 // This was moved out of the try{} block so that any sheet definitions that
276 // the plugin fully parsed before the exception was raised will be loaded.
277 for( SCH_ITEM* aItem : aSheet->GetScreen()->Items().OfType( SCH_SHEET_T ) )
278 {
279 wxCHECK2( aItem->Type() == SCH_SHEET_T, /* do nothing */ );
280 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
281
282 // Recursion starts here.
283 loadHierarchy( currentSheetPath, sheet );
284 }
285 }
286
287 m_currentPath.pop();
288 wxLogTrace( traceSchPlugin, "Restoring path \"%s\"", m_currentPath.top() );
289 }
290
291 m_currentSheetPath.pop_back();
292}
293
294
295void SCH_IO_KICAD_SEXPR::loadFile( const wxString& aFileName, SCH_SHEET* aSheet )
296{
297 FILE_LINE_READER reader( aFileName );
298
299 size_t lineCount = 0;
300
302 {
303 m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) );
304
305 if( !m_progressReporter->KeepRefreshing() )
306 THROW_IO_ERROR( _( "Open canceled by user." ) );
307
308 while( reader.ReadLine() )
309 lineCount++;
310
311 reader.Rewind();
312 }
313
314 SCH_IO_KICAD_SEXPR_PARSER parser( &reader, m_progressReporter, lineCount, m_rootSheet,
315 m_appending );
316
317 parser.ParseSchematic( aSheet );
318}
319
320
321void SCH_IO_KICAD_SEXPR::LoadContent( LINE_READER& aReader, SCH_SHEET* aSheet, int aFileVersion )
322{
323 wxCHECK( aSheet, /* void */ );
324
325 SCH_IO_KICAD_SEXPR_PARSER parser( &aReader );
326
327 parser.ParseSchematic( aSheet, true, aFileVersion );
328}
329
330
331void SCH_IO_KICAD_SEXPR::SaveSchematicFile( const wxString& aFileName, SCH_SHEET* aSheet,
332 SCHEMATIC* aSchematic,
333 const std::map<std::string, UTF8>* aProperties )
334{
335 wxCHECK_RET( aSheet != nullptr, "NULL SCH_SHEET object." );
336 wxCHECK_RET( !aFileName.IsEmpty(), "No schematic file name defined." );
337
338 wxString sanityResult = aSheet->GetScreen()->GroupsSanityCheck();
339
340 if( sanityResult != wxEmptyString && m_queryUserCallback )
341 {
342 if( !m_queryUserCallback( _( "Internal Group Data Error" ), wxICON_ERROR,
343 wxString::Format( _( "Please report this bug. Error validating group "
344 "structure: %s\n\nSave anyway?" ),
345 sanityResult ),
346 _( "Save Anyway" ) ) )
347 {
348 return;
349 }
350 }
351
352 init( aSchematic, aProperties );
353
354 wxFileName fn = aFileName;
355
356 // File names should be absolute. Don't assume everything relative to the project path
357 // works properly.
358 wxASSERT( fn.IsAbsolute() );
359
360 PRETTIFIED_FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
361
362 m_out = &formatter; // no ownership
363
364 Format( aSheet );
365
366 if( aSheet->GetScreen() )
367 aSheet->GetScreen()->SetFileExists( true );
368}
369
370
372{
373 wxCHECK_RET( aSheet != nullptr, "NULL SCH_SHEET* object." );
374 wxCHECK_RET( m_schematic != nullptr, "NULL SCHEMATIC* object." );
375
376 SCH_SHEET_LIST sheets = m_schematic->Hierarchy();
377 SCH_SCREEN* screen = aSheet->GetScreen();
378
379 wxCHECK( screen, /* void */ );
380
381 // If we've requested to embed the fonts in the schematic, do so.
382 // Otherwise, clear the embedded fonts from the schematic. Embedded
383 // fonts will be used if available
384 if( m_schematic->GetAreFontsEmbedded() )
385 m_schematic->EmbedFonts();
386 else
387 m_schematic->GetEmbeddedFiles()->ClearEmbeddedFonts();
388
389 m_out->Print( "(kicad_sch (version %d) (generator \"eeschema\") (generator_version %s)",
391 m_out->Quotew( GetMajorMinorVersion() ).c_str() );
392
394
395 screen->GetPageSettings().Format( m_out );
396 screen->GetTitleBlock().Format( m_out );
397
398 // Save cache library.
399 m_out->Print( "(lib_symbols" );
400
401 for( const auto& [ libItemName, libSymbol ] : screen->GetLibSymbols() )
402 SCH_IO_KICAD_SEXPR_LIB_CACHE::SaveSymbol( libSymbol, *m_out, libItemName );
403
404 m_out->Print( ")" );
405
406 for( const std::shared_ptr<BUS_ALIAS>& alias : screen->GetBusAliases() )
407 saveBusAlias( alias );
408
409 // Enforce item ordering
410 auto cmp =
411 []( const SCH_ITEM* a, const SCH_ITEM* b )
412 {
413 if( a->Type() != b->Type() )
414 return a->Type() < b->Type();
415
416 return a->m_Uuid < b->m_Uuid;
417 };
418
419 std::multiset<SCH_ITEM*, decltype( cmp )> save_map( cmp );
420
421 for( SCH_ITEM* item : screen->Items() )
422 {
423 // Markers are not saved, so keep them from being considered below
424 if( item->Type() != SCH_MARKER_T )
425 save_map.insert( item );
426 }
427
428 for( SCH_ITEM* item : save_map )
429 {
430 switch( item->Type() )
431 {
432 case SCH_SYMBOL_T:
433 saveSymbol( static_cast<SCH_SYMBOL*>( item ), *m_schematic, sheets, false );
434 break;
435
436 case SCH_BITMAP_T:
437 saveBitmap( static_cast<SCH_BITMAP&>( *item ) );
438 break;
439
440 case SCH_SHEET_T:
441 saveSheet( static_cast<SCH_SHEET*>( item ), sheets );
442 break;
443
444 case SCH_JUNCTION_T:
445 saveJunction( static_cast<SCH_JUNCTION*>( item ) );
446 break;
447
448 case SCH_NO_CONNECT_T:
449 saveNoConnect( static_cast<SCH_NO_CONNECT*>( item ) );
450 break;
451
454 saveBusEntry( static_cast<SCH_BUS_ENTRY_BASE*>( item ) );
455 break;
456
457 case SCH_LINE_T:
458 saveLine( static_cast<SCH_LINE*>( item ) );
459 break;
460
461 case SCH_SHAPE_T:
462 saveShape( static_cast<SCH_SHAPE*>( item ) );
463 break;
464
465 case SCH_RULE_AREA_T:
466 saveRuleArea( static_cast<SCH_RULE_AREA*>( item ) );
467 break;
468
469 case SCH_TEXT_T:
470 case SCH_LABEL_T:
472 case SCH_HIER_LABEL_T:
474 saveText( static_cast<SCH_TEXT*>( item ) );
475 break;
476
477 case SCH_TEXTBOX_T:
478 saveTextBox( static_cast<SCH_TEXTBOX*>( item ) );
479 break;
480
481 case SCH_TABLE_T:
482 saveTable( static_cast<SCH_TABLE*>( item ) );
483 break;
484
485 case SCH_GROUP_T:
486 saveGroup( static_cast<SCH_GROUP*>( item ) );
487 break;
488
489 default:
490 wxASSERT( "Unexpected schematic object type in SCH_IO_KICAD_SEXPR::Format()" );
491 }
492 }
493
494 if( aSheet->HasRootInstance() )
495 {
496 std::vector< SCH_SHEET_INSTANCE> instances;
497
498 instances.emplace_back( aSheet->GetRootInstance() );
499 saveInstances( instances );
500
501 KICAD_FORMAT::FormatBool( m_out, "embedded_fonts", m_schematic->GetAreFontsEmbedded() );
502
503 // Save any embedded files
504 if( !m_schematic->GetEmbeddedFiles()->IsEmpty() )
505 m_schematic->WriteEmbeddedFiles( *m_out, true );
506 }
507
508 m_out->Print( ")" );
509}
510
511
512void SCH_IO_KICAD_SEXPR::Format( SCH_SELECTION* aSelection, SCH_SHEET_PATH* aSelectionPath,
513 SCHEMATIC& aSchematic, OUTPUTFORMATTER* aFormatter,
514 bool aForClipboard )
515{
516 wxCHECK( aSelection && aSelectionPath && aFormatter, /* void */ );
517
518 SCH_SHEET_LIST sheets = aSchematic.Hierarchy();
519
520 m_schematic = &aSchematic;
521 m_out = aFormatter;
522
523 std::map<wxString, LIB_SYMBOL*> libSymbols;
524 SCH_SCREEN* screen = aSelection->GetScreen();
525 std::set<SCH_TABLE*> promotedTables;
526
527 for( EDA_ITEM* item : *aSelection )
528 {
529 if( item->Type() != SCH_SYMBOL_T )
530 continue;
531
532 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
533
534 wxString libSymbolLookup = symbol->GetLibId().Format().wx_str();
535
536 if( !symbol->UseLibIdLookup() )
537 libSymbolLookup = symbol->GetSchSymbolLibraryName();
538
539 auto it = screen->GetLibSymbols().find( libSymbolLookup );
540
541 if( it != screen->GetLibSymbols().end() )
542 libSymbols[ libSymbolLookup ] = it->second;
543 }
544
545 if( !libSymbols.empty() )
546 {
547 m_out->Print( "(lib_symbols" );
548
549 for( const auto& [name, libSymbol] : libSymbols )
551
552 m_out->Print( ")" );
553 }
554
555 for( EDA_ITEM* edaItem : *aSelection )
556 {
557 if( !edaItem->IsSCH_ITEM() )
558 continue;
559
560 SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
561
562 switch( item->Type() )
563 {
564 case SCH_SYMBOL_T:
565 saveSymbol( static_cast<SCH_SYMBOL*>( item ), aSchematic, sheets, aForClipboard, aSelectionPath );
566 break;
567
568 case SCH_BITMAP_T:
569 saveBitmap( static_cast<SCH_BITMAP&>( *item ) );
570 break;
571
572 case SCH_SHEET_T:
573 saveSheet( static_cast<SCH_SHEET*>( item ), sheets );
574 break;
575
576 case SCH_JUNCTION_T:
577 saveJunction( static_cast<SCH_JUNCTION*>( item ) );
578 break;
579
580 case SCH_NO_CONNECT_T:
581 saveNoConnect( static_cast<SCH_NO_CONNECT*>( item ) );
582 break;
583
586 saveBusEntry( static_cast<SCH_BUS_ENTRY_BASE*>( item ) );
587 break;
588
589 case SCH_LINE_T:
590 saveLine( static_cast<SCH_LINE*>( item ) );
591 break;
592
593 case SCH_SHAPE_T:
594 saveShape( static_cast<SCH_SHAPE*>( item ) );
595 break;
596
597 case SCH_RULE_AREA_T:
598 saveRuleArea( static_cast<SCH_RULE_AREA*>( item ) );
599 break;
600
601 case SCH_TEXT_T:
602 case SCH_LABEL_T:
604 case SCH_HIER_LABEL_T:
606 saveText( static_cast<SCH_TEXT*>( item ) );
607 break;
608
609 case SCH_TEXTBOX_T:
610 saveTextBox( static_cast<SCH_TEXTBOX*>( item ) );
611 break;
612
613 case SCH_TABLECELL_T:
614 {
615 SCH_TABLE* table = static_cast<SCH_TABLE*>( item->GetParent() );
616
617 if( promotedTables.count( table ) )
618 break;
619
620 table->SetFlags( SKIP_STRUCT );
621 saveTable( table );
622 table->ClearFlags( SKIP_STRUCT );
623 promotedTables.insert( table );
624 break;
625 }
626
627 case SCH_TABLE_T:
628 item->ClearFlags( SKIP_STRUCT );
629 saveTable( static_cast<SCH_TABLE*>( item ) );
630 break;
631
632 case SCH_GROUP_T:
633 saveGroup( static_cast<SCH_GROUP*>( item ) );
634 break;
635
636 default:
637 wxASSERT( "Unexpected schematic object type in SCH_IO_KICAD_SEXPR::Format()" );
638 }
639 }
640}
641
642
643void SCH_IO_KICAD_SEXPR::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchematic,
644 const SCH_SHEET_LIST& aSheetList, bool aForClipboard,
645 const SCH_SHEET_PATH* aRelativePath )
646{
647 wxCHECK_RET( aSymbol != nullptr && m_out != nullptr, "" );
648
649 std::string libName;
650
651 wxString symbol_name = aSymbol->GetLibId().Format();
652
653 if( symbol_name.size() )
654 {
655 libName = toUTFTildaText( symbol_name );
656 }
657 else
658 {
659 libName = "_NONAME_";
660 }
661
662 EDA_ANGLE angle;
663 int orientation = aSymbol->GetOrientation() & ~( SYM_MIRROR_X | SYM_MIRROR_Y );
664
665 if( orientation == SYM_ORIENT_90 )
666 angle = ANGLE_90;
667 else if( orientation == SYM_ORIENT_180 )
668 angle = ANGLE_180;
669 else if( orientation == SYM_ORIENT_270 )
670 angle = ANGLE_270;
671 else
672 angle = ANGLE_0;
673
674 m_out->Print( "(symbol" );
675
676 if( !aSymbol->UseLibIdLookup() )
677 {
678 m_out->Print( "(lib_name %s)",
679 m_out->Quotew( aSymbol->GetSchSymbolLibraryName() ).c_str() );
680 }
681
682 m_out->Print( "(lib_id %s) (at %s %s %s)",
683 m_out->Quotew( aSymbol->GetLibId().Format().wx_str() ).c_str(),
685 aSymbol->GetPosition().x ).c_str(),
687 aSymbol->GetPosition().y ).c_str(),
688 EDA_UNIT_UTILS::FormatAngle( angle ).c_str() );
689
690 bool mirrorX = aSymbol->GetOrientation() & SYM_MIRROR_X;
691 bool mirrorY = aSymbol->GetOrientation() & SYM_MIRROR_Y;
692
693 if( mirrorX || mirrorY )
694 {
695 m_out->Print( "(mirror %s %s)",
696 mirrorX ? "x" : "",
697 mirrorY ? "y" : "" );
698 }
699
700 // The symbol unit is always set to the ordianal instance regardless of the current sheet
701 // instance to prevent file churn.
702 SCH_SYMBOL_INSTANCE ordinalInstance;
703
704 ordinalInstance.m_Reference = aSymbol->GetPrefix();
705
706 const SCH_SCREEN* parentScreen = static_cast<const SCH_SCREEN*>( aSymbol->GetParent() );
707
708 wxASSERT( parentScreen );
709
710 if( parentScreen && m_schematic )
711 {
712 std::optional<SCH_SHEET_PATH> ordinalPath =
713 m_schematic->Hierarchy().GetOrdinalPath( parentScreen );
714
715 // Design blocks are saved from a temporary sheet & screen which will not be found in
716 // the schematic, and will therefore have no ordinal path.
717 // wxASSERT( ordinalPath );
718
719 if( ordinalPath )
720 aSymbol->GetInstance( ordinalInstance, ordinalPath->Path() );
721 else if( aSymbol->GetInstances().size() )
722 ordinalInstance = aSymbol->GetInstances()[0];
723 }
724
725 int unit = ordinalInstance.m_Unit;
726
727 if( aForClipboard && aRelativePath )
728 {
729 SCH_SYMBOL_INSTANCE unitInstance;
730
731 if( aSymbol->GetInstance( unitInstance, aRelativePath->Path() ) )
732 unit = unitInstance.m_Unit;
733 }
734
735 m_out->Print( "(unit %d)", unit );
736 m_out->Print( "(body_style %d)", aSymbol->GetBodyStyle() );
737
738 KICAD_FORMAT::FormatBool( m_out, "exclude_from_sim", aSymbol->GetExcludedFromSim() );
739 KICAD_FORMAT::FormatBool( m_out, "in_bom", !aSymbol->GetExcludedFromBOM() );
740 KICAD_FORMAT::FormatBool( m_out, "on_board", !aSymbol->GetExcludedFromBoard() );
741 KICAD_FORMAT::FormatBool( m_out, "dnp", aSymbol->GetDNP() );
742
743 AUTOPLACE_ALGO fieldsAutoplaced = aSymbol->GetFieldsAutoplaced();
744
745 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
746 KICAD_FORMAT::FormatBool( m_out, "fields_autoplaced", true );
747
749
750 std::vector<SCH_FIELD*> orderedFields;
751 aSymbol->GetFields( orderedFields, false );
752
753 for( SCH_FIELD* field : orderedFields )
754 {
755 FIELD_T id = field->GetId();
756 wxString value = field->GetText();
757
758 if( !aForClipboard && aSymbol->GetInstances().size() )
759 {
760 // The instance fields are always set to the default instance regardless of the
761 // sheet instance to prevent file churn.
762 if( id == FIELD_T::REFERENCE )
763 field->SetText( ordinalInstance.m_Reference );
764 }
765 else if( aForClipboard && aSymbol->GetInstances().size() && aRelativePath
766 && ( id == FIELD_T::REFERENCE ) )
767 {
768 SCH_SYMBOL_INSTANCE instance;
769
770 if( aSymbol->GetInstance( instance, aRelativePath->Path() ) )
771 field->SetText( instance.m_Reference );
772 }
773
774 try
775 {
776 saveField( field );
777 }
778 catch( ... )
779 {
780 // Restore the changed field text on write error.
781 if( id == FIELD_T::REFERENCE )
782 field->SetText( value );
783
784 throw;
785 }
786
787 if( id == FIELD_T::REFERENCE )
788 field->SetText( value );
789 }
790
791 for( const std::unique_ptr<SCH_PIN>& pin : aSymbol->GetRawPins() )
792 {
793 // There was a bug introduced somewhere in the original alternated pin code that would
794 // set the alternate pin to the default pin name which caused a number of library symbol
795 // comparison issues. Clearing the alternate pin resolves this issue.
796 if( pin->GetAlt().IsEmpty() || ( pin->GetAlt() == pin->GetBaseName() ) )
797 {
798 m_out->Print( "(pin %s", m_out->Quotew( pin->GetNumber() ).c_str() );
800 m_out->Print( ")" );
801 }
802 else
803 {
804 m_out->Print( "(pin %s", m_out->Quotew( pin->GetNumber() ).c_str() );
806 m_out->Print( "(alternate %s))", m_out->Quotew( pin->GetAlt() ).c_str() );
807 }
808 }
809
810 if( !aSymbol->GetInstances().empty() )
811 {
812 std::map<KIID, std::vector<SCH_SYMBOL_INSTANCE>> projectInstances;
813
814 m_out->Print( "(instances" );
815
816 wxString projectName;
817 KIID rootSheetUuid = aSchematic.Root().m_Uuid;
818
819 for( const SCH_SYMBOL_INSTANCE& inst : aSymbol->GetInstances() )
820 {
821 // Zero length KIID_PATH objects are not valid and will cause a crash below.
822 wxCHECK2( inst.m_Path.size(), continue );
823
824 // If the instance data is part of this design but no longer has an associated sheet
825 // path, don't save it. This prevents large amounts of orphaned instance data for the
826 // current project from accumulating in the schematic files.
827 bool isOrphaned = ( inst.m_Path[0] == rootSheetUuid )
828 && !aSheetList.GetSheetPathByKIIDPath( inst.m_Path );
829
830 // Keep all instance data when copying to the clipboard. They may be needed on paste.
831 if( !aForClipboard && isOrphaned )
832 continue;
833
834 auto it = projectInstances.find( inst.m_Path[0] );
835
836 if( it == projectInstances.end() )
837 projectInstances[ inst.m_Path[0] ] = { inst };
838 else
839 it->second.emplace_back( inst );
840 }
841
842 for( auto& [uuid, instances] : projectInstances )
843 {
844 wxCHECK2( instances.size(), continue );
845
846 // Sort project instances by KIID_PATH.
847 std::sort( instances.begin(), instances.end(),
849 {
850 return aLhs.m_Path < aRhs.m_Path;
851 } );
852
853 projectName = instances[0].m_ProjectName;
854
855 m_out->Print( "(project %s", m_out->Quotew( projectName ).c_str() );
856
857 for( const SCH_SYMBOL_INSTANCE& instance : instances )
858 {
859 wxString path;
860 KIID_PATH tmp = instance.m_Path;
861
862 if( aForClipboard && aRelativePath )
863 tmp.MakeRelativeTo( aRelativePath->Path() );
864
865 path = tmp.AsString();
866
867 m_out->Print( "(path %s (reference %s) (unit %d))",
868 m_out->Quotew( path ).c_str(),
869 m_out->Quotew( instance.m_Reference ).c_str(),
870 instance.m_Unit );
871 }
872
873 m_out->Print( ")" ); // Closes `project`.
874 }
875
876 m_out->Print( ")" ); // Closes `instances`.
877 }
878
879 m_out->Print( ")" ); // Closes `symbol`.
880}
881
882
884{
885 wxCHECK_RET( aField != nullptr && m_out != nullptr, "" );
886
887 wxString fieldName;
888
889 if( aField->IsMandatory() )
890 fieldName = aField->GetCanonicalName();
891 else
892 fieldName = aField->GetName();
893
894 m_out->Print( "(property %s %s %s (at %s %s %s)",
895 aField->IsPrivate() ? "private" : "",
896 m_out->Quotew( fieldName ).c_str(),
897 m_out->Quotew( aField->GetText() ).c_str(),
899 aField->GetPosition().x ).c_str(),
901 aField->GetPosition().y ).c_str(),
902 EDA_UNIT_UTILS::FormatAngle( aField->GetTextAngle() ).c_str() );
903
904 if( !aField->IsVisible() )
905 KICAD_FORMAT::FormatBool( m_out, "hide", true );
906
907 if( aField->IsNameShown() )
908 KICAD_FORMAT::FormatBool( m_out, "show_name", true );
909
910 if( !aField->CanAutoplace() )
911 KICAD_FORMAT::FormatBool( m_out, "do_not_autoplace", true );
912
913 if( !aField->IsDefaultFormatting()
914 || ( aField->GetTextHeight() != schIUScale.MilsToIU( DEFAULT_SIZE_TEXT ) ) )
915 {
916 aField->Format( m_out, 0 );
917 }
918
919 m_out->Print( ")" ); // Closes `property` token
920}
921
922
924{
925 wxCHECK_RET( m_out != nullptr, "" );
926
927 const REFERENCE_IMAGE& refImage = aBitmap.GetReferenceImage();
928 const BITMAP_BASE& bitmapBase = refImage.GetImage();
929
930 const wxImage* image = bitmapBase.GetImageData();
931
932 wxCHECK_RET( image != nullptr, "wxImage* is NULL" );
933
934 m_out->Print( "(image (at %s %s)",
936 refImage.GetPosition().x ).c_str(),
938 refImage.GetPosition().y ).c_str() );
939
940 double scale = refImage.GetImageScale();
941
942 // 20230121 or older file format versions assumed 300 image PPI at load/save.
943 // Let's keep compatibility by changing image scale.
944 if( SEXPR_SCHEMATIC_FILE_VERSION <= 20230121 )
945 scale = scale * 300.0 / bitmapBase.GetPPI();
946
947 if( scale != 1.0 )
948 m_out->Print( "%s", fmt::format("(scale {:g})", refImage.GetImageScale()).c_str() );
949
951
952 wxMemoryOutputStream stream;
953 bitmapBase.SaveImageData( stream );
954
955 KICAD_FORMAT::FormatStreamData( *m_out, *stream.GetOutputStreamBuffer() );
956
957 m_out->Print( ")" ); // Closes image token.
958}
959
960
962{
963 wxCHECK_RET( aSheet != nullptr && m_out != nullptr, "" );
964
965 m_out->Print( "(sheet (at %s %s) (size %s %s)",
967 aSheet->GetPosition().x ).c_str(),
969 aSheet->GetPosition().y ).c_str(),
971 aSheet->GetSize().x ).c_str(),
973 aSheet->GetSize().y ).c_str() );
974
975 KICAD_FORMAT::FormatBool( m_out, "exclude_from_sim", aSheet->GetExcludedFromSim() );
976 KICAD_FORMAT::FormatBool( m_out, "in_bom", !aSheet->GetExcludedFromBOM() );
977 KICAD_FORMAT::FormatBool( m_out, "on_board", !aSheet->GetExcludedFromBoard() );
978 KICAD_FORMAT::FormatBool( m_out, "dnp", aSheet->GetDNP() );
979
980 AUTOPLACE_ALGO fieldsAutoplaced = aSheet->GetFieldsAutoplaced();
981
982 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
983 KICAD_FORMAT::FormatBool( m_out, "fields_autoplaced", true );
984
985 STROKE_PARAMS stroke( aSheet->GetBorderWidth(), LINE_STYLE::SOLID, aSheet->GetBorderColor() );
986
987 stroke.SetWidth( aSheet->GetBorderWidth() );
988 stroke.Format( m_out, schIUScale );
989
990 m_out->Print( "(fill (color %d %d %d %s))",
991 KiROUND( aSheet->GetBackgroundColor().r * 255.0 ),
992 KiROUND( aSheet->GetBackgroundColor().g * 255.0 ),
993 KiROUND( aSheet->GetBackgroundColor().b * 255.0 ),
994 FormatDouble2Str( aSheet->GetBackgroundColor().a ).c_str() );
995
997
998 for( SCH_FIELD& field : aSheet->GetFields() )
999 saveField( &field );
1000
1001 for( const SCH_SHEET_PIN* pin : aSheet->GetPins() )
1002 {
1003 m_out->Print( "(pin %s %s (at %s %s %s)",
1004 EscapedUTF8( pin->GetText() ).c_str(),
1005 getSheetPinShapeToken( pin->GetShape() ),
1007 pin->GetPosition().x ).c_str(),
1009 pin->GetPosition().y ).c_str(),
1010 EDA_UNIT_UTILS::FormatAngle( getSheetPinAngle( pin->GetSide() ) ).c_str() );
1011
1013
1014 pin->Format( m_out, 0 );
1015
1016 m_out->Print( ")" ); // Closes pin token.
1017 }
1018
1019 // Save all sheet instances here except the root sheet instance.
1020 std::vector< SCH_SHEET_INSTANCE > sheetInstances = aSheet->GetInstances();
1021
1022 auto it = sheetInstances.begin();
1023
1024 while( it != sheetInstances.end() )
1025 {
1026 if( it->m_Path.size() == 0 )
1027 it = sheetInstances.erase( it );
1028 else
1029 it++;
1030 }
1031
1032 if( !sheetInstances.empty() )
1033 {
1034 m_out->Print( "(instances" );
1035
1036 KIID lastProjectUuid;
1037 KIID rootSheetUuid = m_schematic->Root().m_Uuid;
1038 bool inProjectClause = false;
1039
1040 for( size_t i = 0; i < sheetInstances.size(); i++ )
1041 {
1042 // If the instance data is part of this design but no longer has an associated sheet
1043 // path, don't save it. This prevents large amounts of orphaned instance data for the
1044 // current project from accumulating in the schematic files.
1045 //
1046 // Keep all instance data when copying to the clipboard. It may be needed on paste.
1047 if( ( sheetInstances[i].m_Path[0] == rootSheetUuid )
1048 && !aSheetList.GetSheetPathByKIIDPath( sheetInstances[i].m_Path, false ) )
1049 {
1050 if( inProjectClause && ( ( i + 1 == sheetInstances.size() )
1051 || lastProjectUuid != sheetInstances[i+1].m_Path[0] ) )
1052 {
1053 m_out->Print( ")" ); // Closes `project` token.
1054 inProjectClause = false;
1055 }
1056
1057 continue;
1058 }
1059
1060 if( lastProjectUuid != sheetInstances[i].m_Path[0] )
1061 {
1062 wxString projectName;
1063
1064 if( sheetInstances[i].m_Path[0] == rootSheetUuid )
1065 projectName = m_schematic->Project().GetProjectName();
1066 else
1067 projectName = sheetInstances[i].m_ProjectName;
1068
1069 lastProjectUuid = sheetInstances[i].m_Path[0];
1070 m_out->Print( "(project %s", m_out->Quotew( projectName ).c_str() );
1071 inProjectClause = true;
1072 }
1073
1074 wxString path = sheetInstances[i].m_Path.AsString();
1075
1076 m_out->Print( "(path %s (page %s))",
1077 m_out->Quotew( path ).c_str(),
1078 m_out->Quotew( sheetInstances[i].m_PageNumber ).c_str() );
1079
1080 if( inProjectClause && ( ( i + 1 == sheetInstances.size() )
1081 || lastProjectUuid != sheetInstances[i+1].m_Path[0] ) )
1082 {
1083 m_out->Print( ")" ); // Closes `project` token.
1084 inProjectClause = false;
1085 }
1086 }
1087
1088 m_out->Print( ")" ); // Closes `instances` token.
1089 }
1090
1091 m_out->Print( ")" ); // Closes sheet token.
1092}
1093
1094
1096{
1097 wxCHECK_RET( aJunction != nullptr && m_out != nullptr, "" );
1098
1099 m_out->Print( "(junction (at %s %s) (diameter %s) (color %d %d %d %s)",
1101 aJunction->GetPosition().x ).c_str(),
1103 aJunction->GetPosition().y ).c_str(),
1105 aJunction->GetDiameter() ).c_str(),
1106 KiROUND( aJunction->GetColor().r * 255.0 ),
1107 KiROUND( aJunction->GetColor().g * 255.0 ),
1108 KiROUND( aJunction->GetColor().b * 255.0 ),
1109 FormatDouble2Str( aJunction->GetColor().a ).c_str() );
1110
1111 KICAD_FORMAT::FormatUuid( m_out, aJunction->m_Uuid );
1112 m_out->Print( ")" );
1113}
1114
1115
1117{
1118 wxCHECK_RET( aNoConnect != nullptr && m_out != nullptr, "" );
1119
1120 m_out->Print( "(no_connect (at %s %s)",
1122 aNoConnect->GetPosition().x ).c_str(),
1124 aNoConnect->GetPosition().y ).c_str() );
1125
1126 KICAD_FORMAT::FormatUuid( m_out, aNoConnect->m_Uuid );
1127 m_out->Print( ")" );
1128}
1129
1130
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->GetEnd() );
1141 saveLine( &busEntryLine );
1142 return;
1143 }
1144
1145 m_out->Print( "(bus_entry (at %s %s) (size %s %s)",
1147 aBusEntry->GetPosition().x ).c_str(),
1149 aBusEntry->GetPosition().y ).c_str(),
1151 aBusEntry->GetSize().x ).c_str(),
1153 aBusEntry->GetSize().y ).c_str() );
1154
1155 aBusEntry->GetStroke().Format( m_out, schIUScale );
1156 KICAD_FORMAT::FormatUuid( m_out, aBusEntry->m_Uuid );
1157 m_out->Print( ")" );
1158}
1159
1160
1162{
1163 wxCHECK_RET( aShape != nullptr && m_out != nullptr, "" );
1164
1165 switch( aShape->GetShape() )
1166 {
1167 case SHAPE_T::ARC:
1168 formatArc( m_out, aShape, false, aShape->GetStroke(), aShape->GetFillMode(),
1169 aShape->GetFillColor(), false, aShape->m_Uuid );
1170 break;
1171
1172 case SHAPE_T::CIRCLE:
1173 formatCircle( m_out, aShape, false, aShape->GetStroke(), aShape->GetFillMode(),
1174 aShape->GetFillColor(), false, aShape->m_Uuid );
1175 break;
1176
1177 case SHAPE_T::RECTANGLE:
1178 formatRect( m_out, aShape, false, aShape->GetStroke(), aShape->GetFillMode(),
1179 aShape->GetFillColor(), false, aShape->m_Uuid );
1180 break;
1181
1182 case SHAPE_T::BEZIER:
1183 formatBezier( m_out, aShape, false, aShape->GetStroke(), aShape->GetFillMode(),
1184 aShape->GetFillColor(), false, aShape->m_Uuid );
1185 break;
1186
1187 case SHAPE_T::POLY:
1188 formatPoly( m_out, aShape, false, aShape->GetStroke(), aShape->GetFillMode(),
1189 aShape->GetFillColor(), false, aShape->m_Uuid );
1190 break;
1191
1192 default:
1194 }
1195}
1196
1197
1199{
1200 wxCHECK_RET( aRuleArea != nullptr && m_out != nullptr, "" );
1201
1202 m_out->Print( "(rule_area " );
1203
1204 KICAD_FORMAT::FormatBool( m_out, "exclude_from_sim", aRuleArea->GetExcludedFromSim() );
1205 KICAD_FORMAT::FormatBool( m_out, "in_bom", !aRuleArea->GetExcludedFromBOM() );
1206 KICAD_FORMAT::FormatBool( m_out, "on_board", !aRuleArea->GetExcludedFromBoard() );
1207 KICAD_FORMAT::FormatBool( m_out, "dnp", aRuleArea->GetDNP() );
1208
1209 saveShape( aRuleArea );
1210
1211 m_out->Print( ")" );
1212}
1213
1214
1216{
1217 wxCHECK_RET( aLine != nullptr && m_out != nullptr, "" );
1218
1219 wxString lineType;
1220
1221 STROKE_PARAMS line_stroke = aLine->GetStroke();
1222
1223 switch( aLine->GetLayer() )
1224 {
1225 case LAYER_BUS: lineType = "bus"; break;
1226 case LAYER_WIRE: lineType = "wire"; break;
1227 case LAYER_NOTES: lineType = "polyline"; break;
1228 default:
1229 UNIMPLEMENTED_FOR( LayerName( aLine->GetLayer() ) );
1230 }
1231
1232 m_out->Print( "(%s (pts (xy %s %s) (xy %s %s))",
1233 TO_UTF8( lineType ),
1235 aLine->GetStartPoint().x ).c_str(),
1237 aLine->GetStartPoint().y ).c_str(),
1239 aLine->GetEndPoint().x ).c_str(),
1241 aLine->GetEndPoint().y ).c_str() );
1242
1243 line_stroke.Format( m_out, schIUScale );
1245 m_out->Print( ")" );
1246}
1247
1248
1250{
1251 wxCHECK_RET( aText != nullptr && m_out != nullptr, "" );
1252
1253 // Note: label is nullptr SCH_TEXT, but not for SCH_LABEL_XXX,
1254 SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( aText );
1255
1256 m_out->Print( "(%s %s",
1257 getTextTypeToken( aText->Type() ),
1258 m_out->Quotew( aText->GetText() ).c_str() );
1259
1260 if( aText->Type() == SCH_TEXT_T )
1261 KICAD_FORMAT::FormatBool( m_out, "exclude_from_sim", aText->GetExcludedFromSim() );
1262
1263 if( aText->Type() == SCH_DIRECTIVE_LABEL_T )
1264 {
1265 SCH_DIRECTIVE_LABEL* flag = static_cast<SCH_DIRECTIVE_LABEL*>( aText );
1266
1267 m_out->Print( "(length %s)",
1269 flag->GetPinLength() ).c_str() );
1270 }
1271
1272 EDA_ANGLE angle = aText->GetTextAngle();
1273
1274 if( label )
1275 {
1276 if( label->Type() == SCH_GLOBAL_LABEL_T
1277 || label->Type() == SCH_HIER_LABEL_T
1278 || label->Type() == SCH_DIRECTIVE_LABEL_T )
1279 {
1280 m_out->Print( "(shape %s)", getSheetPinShapeToken( label->GetShape() ) );
1281 }
1282
1283 // The angle of the text is always 0 or 90 degrees for readibility reasons,
1284 // but the item itself can have more rotation (-90 and 180 deg)
1285 switch( label->GetSpinStyle() )
1286 {
1287 default:
1288 case SPIN_STYLE::LEFT: angle += ANGLE_180; break;
1289 case SPIN_STYLE::UP: break;
1290 case SPIN_STYLE::RIGHT: break;
1291 case SPIN_STYLE::BOTTOM: angle += ANGLE_180; break;
1292 }
1293 }
1294
1295 m_out->Print( "(at %s %s %s)",
1297 aText->GetPosition().x ).c_str(),
1299 aText->GetPosition().y ).c_str(),
1300 EDA_UNIT_UTILS::FormatAngle( angle ).c_str() );
1301
1302 if( label && !label->GetFields().empty() )
1303 {
1304 AUTOPLACE_ALGO fieldsAutoplaced = label->GetFieldsAutoplaced();
1305
1306 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
1307 KICAD_FORMAT::FormatBool( m_out, "fields_autoplaced", true );
1308 }
1309
1310 aText->EDA_TEXT::Format( m_out, 0 );
1312
1313 if( label )
1314 {
1315 for( SCH_FIELD& field : label->GetFields() )
1316 saveField( &field );
1317 }
1318
1319 m_out->Print( ")" ); // Closes text token.
1320}
1321
1322
1324{
1325 wxCHECK_RET( aTextBox != nullptr && m_out != nullptr, "" );
1326
1327 m_out->Print( "(%s %s",
1328 aTextBox->Type() == SCH_TABLECELL_T ? "table_cell" : "text_box",
1329 m_out->Quotew( aTextBox->GetText() ).c_str() );
1330
1331 KICAD_FORMAT::FormatBool( m_out, "exclude_from_sim", aTextBox->GetExcludedFromSim() );
1332
1333 VECTOR2I pos = aTextBox->GetStart();
1334 VECTOR2I size = aTextBox->GetEnd() - pos;
1335
1336 m_out->Print( "(at %s %s %s) (size %s %s) (margins %s %s %s %s)",
1339 EDA_UNIT_UTILS::FormatAngle( aTextBox->GetTextAngle() ).c_str(),
1346
1347 if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( aTextBox ) )
1348 m_out->Print( "(span %d %d)", cell->GetColSpan(), cell->GetRowSpan() );
1349
1350 if( aTextBox->Type() != SCH_TABLECELL_T )
1351 aTextBox->GetStroke().Format( m_out, schIUScale );
1352
1353 formatFill( m_out, aTextBox->GetFillMode(), aTextBox->GetFillColor() );
1354 aTextBox->EDA_TEXT::Format( m_out, 0 );
1356 m_out->Print( ")" );
1357}
1358
1359
1361{
1362 if( aTable->GetFlags() & SKIP_STRUCT )
1363 {
1364 aTable = static_cast<SCH_TABLE*>( aTable->Clone() );
1365
1366 int minCol = aTable->GetColCount();
1367 int maxCol = -1;
1368 int minRow = aTable->GetRowCount();
1369 int maxRow = -1;
1370
1371 for( int row = 0; row < aTable->GetRowCount(); ++row )
1372 {
1373 for( int col = 0; col < aTable->GetColCount(); ++col )
1374 {
1375 SCH_TABLECELL* cell = aTable->GetCell( row, col );
1376
1377 if( cell->IsSelected() )
1378 {
1379 minRow = std::min( minRow, row );
1380 maxRow = std::max( maxRow, row );
1381 minCol = std::min( minCol, col );
1382 maxCol = std::max( maxCol, col );
1383 }
1384 else
1385 {
1386 cell->SetFlags( STRUCT_DELETED );
1387 }
1388 }
1389 }
1390
1391 wxCHECK_MSG( maxCol >= minCol && maxRow >= minRow, /*void*/, wxT( "No selected cells!" ) );
1392
1393 int destRow = 0;
1394
1395 for( int row = minRow; row <= maxRow; row++ )
1396 aTable->SetRowHeight( destRow++, aTable->GetRowHeight( row ) );
1397
1398 int destCol = 0;
1399
1400 for( int col = minCol; col <= maxCol; col++ )
1401 aTable->SetColWidth( destCol++, aTable->GetColWidth( col ) );
1402
1403 aTable->DeleteMarkedCells();
1404 aTable->SetColCount( ( maxCol - minCol ) + 1 );
1405 }
1406
1407 wxCHECK_RET( aTable != nullptr && m_out != nullptr, "" );
1408
1409 m_out->Print( "(table (column_count %d)", aTable->GetColCount() );
1410
1411 m_out->Print( "(border" );
1412 KICAD_FORMAT::FormatBool( m_out, "external", aTable->StrokeExternal() );
1414
1415 if( aTable->StrokeExternal() || aTable->StrokeHeaderSeparator() )
1416 aTable->GetBorderStroke().Format( m_out, schIUScale );
1417
1418 m_out->Print( ")" ); // Close `border` token.
1419
1420 m_out->Print( "(separators" );
1421 KICAD_FORMAT::FormatBool( m_out, "rows", aTable->StrokeRows() );
1422 KICAD_FORMAT::FormatBool( m_out, "cols", aTable->StrokeColumns() );
1423
1424 if( aTable->StrokeRows() || aTable->StrokeColumns() )
1426
1427 m_out->Print( ")" ); // Close `separators` token.
1428
1429 m_out->Print( "(column_widths" );
1430
1431 for( int col = 0; col < aTable->GetColCount(); ++col )
1432 {
1433 m_out->Print( " %s",
1434 EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aTable->GetColWidth( col ) ).c_str() );
1435 }
1436
1437 m_out->Print( ")" );
1438
1439 m_out->Print( "(row_heights" );
1440
1441 for( int row = 0; row < aTable->GetRowCount(); ++row )
1442 {
1443 m_out->Print( " %s",
1444 EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aTable->GetRowHeight( row ) ).c_str() );
1445 }
1446
1447 m_out->Print( ")" );
1448
1450
1451 m_out->Print( "(cells" );
1452
1453 for( SCH_TABLECELL* cell : aTable->GetCells() )
1454 saveTextBox( cell );
1455
1456 m_out->Print( ")" ); // Close `cells` token.
1457 m_out->Print( ")" ); // Close `table` token.
1458
1459 if( aTable->GetFlags() & SKIP_STRUCT )
1460 delete aTable;
1461}
1462
1463
1465{
1466 // Don't write empty groups
1467 if( aGroup->GetItems().empty() )
1468 return;
1469
1470 m_out->Print( "(group %s", m_out->Quotew( aGroup->GetName() ).c_str() );
1471
1473
1474 if( aGroup->IsLocked() )
1475 KICAD_FORMAT::FormatBool( m_out, "locked", true );
1476
1477 if( aGroup->HasDesignBlockLink() )
1478 m_out->Print( "(lib_id \"%s\")", aGroup->GetDesignBlockLibId().Format().c_str() );
1479
1480 wxArrayString memberIds;
1481
1482 for( EDA_ITEM* member : aGroup->GetItems() )
1483 memberIds.Add( member->m_Uuid.AsString() );
1484
1485 memberIds.Sort();
1486
1487 m_out->Print( "(members" );
1488
1489 for( const wxString& memberId : memberIds )
1490 m_out->Print( " %s", m_out->Quotew( memberId ).c_str() );
1491
1492 m_out->Print( ")" ); // Close `members` token.
1493 m_out->Print( ")" ); // Close `group` token.
1494}
1495
1496
1497void SCH_IO_KICAD_SEXPR::saveBusAlias( std::shared_ptr<BUS_ALIAS> aAlias )
1498{
1499 wxCHECK_RET( aAlias != nullptr, "BUS_ALIAS* is NULL" );
1500
1501 wxString members;
1502
1503 for( const wxString& member : aAlias->Members() )
1504 {
1505 if( !members.IsEmpty() )
1506 members += wxS( " " );
1507
1508 members += m_out->Quotew( member );
1509 }
1510
1511 m_out->Print( "(bus_alias %s (members %s))",
1512 m_out->Quotew( aAlias->GetName() ).c_str(),
1513 TO_UTF8( members ) );
1514}
1515
1516
1517void SCH_IO_KICAD_SEXPR::saveInstances( const std::vector<SCH_SHEET_INSTANCE>& aInstances )
1518{
1519 if( aInstances.size() )
1520 {
1521 m_out->Print( "(sheet_instances" );
1522
1523 for( const SCH_SHEET_INSTANCE& instance : aInstances )
1524 {
1525 wxString path = instance.m_Path.AsString();
1526
1527 if( path.IsEmpty() )
1528 path = wxT( "/" ); // Root path
1529
1530 m_out->Print( "(path %s (page %s))",
1531 m_out->Quotew( path ).c_str(),
1532 m_out->Quotew( instance.m_PageNumber ).c_str() );
1533 }
1534
1535 m_out->Print( ")" ); // Close sheet instances token.
1536 }
1537}
1538
1539
1540void SCH_IO_KICAD_SEXPR::cacheLib( const wxString& aLibraryFileName,
1541 const std::map<std::string, UTF8>* aProperties )
1542{
1543 // Suppress font substitution warnings
1545
1546 if( !m_cache || !m_cache->IsFile( aLibraryFileName ) || m_cache->IsFileChanged() )
1547 {
1548 // a spectacular episode in memory management:
1549 delete m_cache;
1550 m_cache = new SCH_IO_KICAD_SEXPR_LIB_CACHE( aLibraryFileName );
1551
1552 if( !isBuffering( aProperties ) )
1553 m_cache->Load();
1554 }
1555}
1556
1557
1558bool SCH_IO_KICAD_SEXPR::isBuffering( const std::map<std::string, UTF8>* aProperties )
1559{
1560 return ( aProperties && aProperties->contains( SCH_IO_KICAD_SEXPR::PropBuffering ) );
1561}
1562
1563
1565{
1566 if( m_cache )
1567 return m_cache->GetModifyHash();
1568
1569 // If the cache hasn't been loaded, it hasn't been modified.
1570 return 0;
1571}
1572
1573
1574void SCH_IO_KICAD_SEXPR::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
1575 const wxString& aLibraryPath,
1576 const std::map<std::string, UTF8>* aProperties )
1577{
1578 bool powerSymbolsOnly = ( aProperties && aProperties->contains( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) );
1579
1580 cacheLib( aLibraryPath, aProperties );
1581
1582 const LIB_SYMBOL_MAP& symbols = m_cache->m_symbols;
1583
1584 for( LIB_SYMBOL_MAP::const_iterator it = symbols.begin(); it != symbols.end(); ++it )
1585 {
1586 if( !powerSymbolsOnly || it->second->IsPower() )
1587 aSymbolNameList.Add( it->first );
1588 }
1589}
1590
1591
1592void SCH_IO_KICAD_SEXPR::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
1593 const wxString& aLibraryPath,
1594 const std::map<std::string, UTF8>* aProperties )
1595{
1596 bool powerSymbolsOnly = ( aProperties && aProperties->contains( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) );
1597
1598 cacheLib( aLibraryPath, aProperties );
1599
1600 const LIB_SYMBOL_MAP& symbols = m_cache->m_symbols;
1601
1602 for( LIB_SYMBOL_MAP::const_iterator it = symbols.begin(); it != symbols.end(); ++it )
1603 {
1604 if( !powerSymbolsOnly || it->second->IsPower() )
1605 aSymbolList.push_back( it->second );
1606 }
1607}
1608
1609
1610LIB_SYMBOL* SCH_IO_KICAD_SEXPR::LoadSymbol( const wxString& aLibraryPath,
1611 const wxString& aSymbolName,
1612 const std::map<std::string, UTF8>* aProperties )
1613{
1614 cacheLib( aLibraryPath, aProperties );
1615
1616 LIB_SYMBOL_MAP::const_iterator it = m_cache->m_symbols.find( aSymbolName );
1617
1618 // We no longer escape '/' in symbol names, but we used to.
1619 if( it == m_cache->m_symbols.end() && aSymbolName.Contains( '/' ) )
1620 it = m_cache->m_symbols.find( EscapeString( aSymbolName, CTX_LEGACY_LIBID ) );
1621
1622 if( it == m_cache->m_symbols.end() && aSymbolName.Contains( wxT( "{slash}" ) ) )
1623 {
1624 wxString unescaped = aSymbolName;
1625 unescaped.Replace( wxT( "{slash}" ), wxT( "/" ) );
1626 it = m_cache->m_symbols.find( unescaped );
1627 }
1628
1629 if( it == m_cache->m_symbols.end() )
1630 return nullptr;
1631
1632 return it->second;
1633}
1634
1635
1636void SCH_IO_KICAD_SEXPR::SaveSymbol( const wxString& aLibraryPath, const LIB_SYMBOL* aSymbol,
1637 const std::map<std::string, UTF8>* aProperties )
1638{
1639 cacheLib( aLibraryPath, aProperties );
1640
1641 m_cache->AddSymbol( aSymbol );
1642
1643 if( !isBuffering( aProperties ) )
1644 m_cache->Save();
1645}
1646
1647
1648void SCH_IO_KICAD_SEXPR::DeleteSymbol( const wxString& aLibraryPath, const wxString& aSymbolName,
1649 const std::map<std::string, UTF8>* aProperties )
1650{
1651 cacheLib( aLibraryPath, aProperties );
1652
1653 m_cache->DeleteSymbol( aSymbolName );
1654
1655 if( !isBuffering( aProperties ) )
1656 m_cache->Save();
1657}
1658
1659
1660void SCH_IO_KICAD_SEXPR::CreateLibrary( const wxString& aLibraryPath,
1661 const std::map<std::string, UTF8>* aProperties )
1662{
1663 if( wxFileExists( aLibraryPath ) )
1664 {
1665 THROW_IO_ERROR( wxString::Format( _( "Symbol library '%s' already exists." ),
1666 aLibraryPath.GetData() ) );
1667 }
1668
1669 delete m_cache;
1670 m_cache = new SCH_IO_KICAD_SEXPR_LIB_CACHE( aLibraryPath );
1671 m_cache->SetModified();
1672 m_cache->Save();
1673 m_cache->Load(); // update m_writable and m_timestamp
1674}
1675
1676
1677bool SCH_IO_KICAD_SEXPR::DeleteLibrary( const wxString& aLibraryPath,
1678 const std::map<std::string, UTF8>* aProperties )
1679{
1680 wxFileName fn = aLibraryPath;
1681
1682 if( !fn.FileExists() )
1683 return false;
1684
1685 // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
1686 // we don't want that. we want bare metal portability with no UI here.
1687 if( wxRemove( aLibraryPath ) )
1688 {
1689 THROW_IO_ERROR( wxString::Format( _( "Symbol library '%s' cannot be deleted." ),
1690 aLibraryPath.GetData() ) );
1691 }
1692
1693 if( m_cache && m_cache->IsFile( aLibraryPath ) )
1694 {
1695 delete m_cache;
1696 m_cache = nullptr;
1697 }
1698
1699 return true;
1700}
1701
1702
1703void SCH_IO_KICAD_SEXPR::SaveLibrary( const wxString& aLibraryPath,
1704 const std::map<std::string, UTF8>* aProperties )
1705{
1706 if( !m_cache )
1707 m_cache = new SCH_IO_KICAD_SEXPR_LIB_CACHE( aLibraryPath );
1708
1709 wxString oldFileName = m_cache->GetFileName();
1710
1711 if( !m_cache->IsFile( aLibraryPath ) )
1712 m_cache->SetFileName( aLibraryPath );
1713
1714 // This is a forced save.
1715 m_cache->SetModified();
1716 m_cache->Save();
1717 m_cache->SetFileName( oldFileName );
1718}
1719
1720
1721bool SCH_IO_KICAD_SEXPR::CanReadLibrary( const wxString& aLibraryPath ) const
1722{
1723 if( !SCH_IO::CanReadLibrary( aLibraryPath ) )
1724 return false;
1725
1726 // Above just checks for proper extension; now check that it actually exists
1727
1728 wxFileName fn( aLibraryPath );
1729 return fn.IsOk() && fn.FileExists();
1730}
1731
1732
1733bool SCH_IO_KICAD_SEXPR::IsLibraryWritable( const wxString& aLibraryPath )
1734{
1735 wxFileName fn( aLibraryPath );
1736
1737 if( fn.FileExists() )
1738 return fn.IsFileWritable();
1739
1740 return fn.IsDirWritable();
1741}
1742
1743
1744void SCH_IO_KICAD_SEXPR::GetAvailableSymbolFields( std::vector<wxString>& aNames )
1745{
1746 if( !m_cache )
1747 return;
1748
1749 const LIB_SYMBOL_MAP& symbols = m_cache->m_symbols;
1750
1751 std::set<wxString> fieldNames;
1752
1753 for( LIB_SYMBOL_MAP::const_iterator it = symbols.begin(); it != symbols.end(); ++it )
1754 {
1755 std::vector<SCH_FIELD*> fields;
1756 it->second->GetFields( fields );
1757
1758 for( SCH_FIELD* field : fields )
1759 {
1760 if( field->IsMandatory() )
1761 continue;
1762
1763 // TODO(JE): enable configurability of this outside database libraries?
1764 // if( field->ShowInChooser() )
1765 fieldNames.insert( field->GetName() );
1766 }
1767 }
1768
1769 std::copy( fieldNames.begin(), fieldNames.end(), std::back_inserter( aNames ) );
1770}
1771
1772
1773void SCH_IO_KICAD_SEXPR::GetDefaultSymbolFields( std::vector<wxString>& aNames )
1774{
1775 GetAvailableSymbolFields( aNames );
1776}
1777
1778
1779std::vector<LIB_SYMBOL*> SCH_IO_KICAD_SEXPR::ParseLibSymbols( std::string& aSymbolText,
1780 std::string aSource,
1781 int aFileVersion )
1782{
1783 LIB_SYMBOL* newSymbol = nullptr;
1784 LIB_SYMBOL_MAP map;
1785
1786 std::vector<LIB_SYMBOL*> newSymbols;
1787 std::unique_ptr<STRING_LINE_READER> reader = std::make_unique<STRING_LINE_READER>( aSymbolText,
1788 aSource );
1789
1790 do
1791 {
1792 SCH_IO_KICAD_SEXPR_PARSER parser( reader.get() );
1793
1794 newSymbol = parser.ParseSymbol( map, aFileVersion );
1795
1796 if( newSymbol )
1797 newSymbols.emplace_back( newSymbol );
1798
1799 reader.reset( new STRING_LINE_READER( *reader ) );
1800 }
1801 while( newSymbol );
1802
1803 return newSymbols;
1804}
1805
1806
1808{
1809 SCH_IO_KICAD_SEXPR_LIB_CACHE::SaveSymbol( symbol, formatter );
1810}
1811
1812
1813const char* SCH_IO_KICAD_SEXPR::PropBuffering = "buffering";
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
This class handle bitmap images in KiCad.
Definition bitmap_base.h:49
bool SaveImageData(wxOutputStream &aOutStream) const
Write the bitmap data to aOutStream.
int GetPPI() const
wxImage * GetImageData()
Definition bitmap_base.h:68
const LIB_ID & GetDesignBlockLibId() const
Definition eda_group.h:73
std::unordered_set< EDA_ITEM * > & GetItems()
Definition eda_group.h:54
wxString GetName() const
Definition eda_group.h:51
bool HasDesignBlockLink() const
Definition eda_group.h:70
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:142
const KIID m_Uuid
Definition eda_item.h:516
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:144
bool IsSelected() const
Definition eda_item.h:127
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
EDA_ITEM * GetParent() const
Definition eda_item.h:112
virtual bool IsLocked() const
Definition eda_item.h:120
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:145
FILL_T GetFillMode() const
Definition eda_shape.h:142
SHAPE_T GetShape() const
Definition eda_shape.h:168
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:215
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:173
COLOR4D GetFillColor() const
Definition eda_shape.h:152
wxString SHAPE_T_asString() const
int GetTextHeight() const
Definition eda_text.h:266
bool IsDefaultFormatting() const
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:146
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:97
virtual bool IsVisible() const
Definition eda_text.h:186
virtual void Format(OUTPUTFORMATTER *aFormatter, int aControlBits) const
Output the object to aFormatter in s-expression form.
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
A LINE_READER that reads from an open file.
Definition richio.h:185
void Rewind()
Rewind the file and resets the line number back to zero.
Definition richio.h:234
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition richio.cpp:249
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition io_base.h:223
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
Definition io_base.cpp:71
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
double r
Red component.
Definition color4d.h:392
double g
Green component.
Definition color4d.h:393
double a
Alpha component.
Definition color4d.h:395
double b
Blue component.
Definition color4d.h:394
bool MakeRelativeTo(const KIID_PATH &aPath)
Definition kiid.cpp:311
wxString AsString() const
Definition kiid.cpp:356
Definition kiid.h:49
UTF8 Format() const
Definition lib_id.cpp:119
Define a library symbol object.
Definition lib_symbol.h:85
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition richio.h:93
An interface used to output 8 bit text in a convenient way.
Definition richio.h:322
void Format(OUTPUTFORMATTER *aFormatter) const
Output the page class to aFormatter in s-expression form.
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:162
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
VECTOR2I GetPosition() const
const BITMAP_BASE & GetImage() const
Get the underlying image.
double GetImageScale() const
Holds all the data relating to one schematic.
Definition schematic.h:88
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition schematic.h:103
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition schematic.h:156
SCH_SHEET & Root() const
Definition schematic.h:140
Object to handle a bitmap image that can be inserted in a schematic.
Definition sch_bitmap.h:40
REFERENCE_IMAGE & GetReferenceImage()
Definition sch_bitmap.h:51
Base class for a bus or wire entry.
VECTOR2I GetSize() const
VECTOR2I GetPosition() const override
virtual STROKE_PARAMS GetStroke() const override
VECTOR2I GetEnd() const
bool IsMandatory() const
VECTOR2I GetPosition() const override
bool IsNameShown() const
Definition sch_field.h:202
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
bool CanAutoplace() const
Definition sch_field.h:213
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:52
A cache assistant for the KiCad s-expression symbol libraries.
static void SaveSymbol(LIB_SYMBOL *aSymbol, OUTPUTFORMATTER &aFormatter, const wxString &aLibName=wxEmptyString, bool aIncludeData=true)
Object to parser s-expression symbol library and schematic file formats.
void ParseSchematic(SCH_SHEET *aSheet, bool aIsCopyablyOnly=false, int aFileVersion=SEXPR_SCHEMATIC_FILE_VERSION)
Parse the internal LINE_READER object into aSheet.
LIB_SYMBOL * ParseSymbol(LIB_SYMBOL_MAP &aSymbolLibMap, int aFileVersion=SEXPR_SYMBOL_LIB_FILE_VERSION)
Parse internal LINE_READER object into symbols and return all found.
wxString m_path
Root project path for loading child sheets.
void GetDefaultSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that should be shown by default for this library in the symb...
void saveShape(SCH_SHAPE *aShape)
void SaveSchematicFile(const wxString &aFileName, SCH_SHEET *aSheet, SCHEMATIC *aSchematic, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aSchematic to a storage file in a format that this SCH_IO implementation knows about,...
void SaveLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
SCH_SHEET_PATH m_currentSheetPath
void saveGroup(SCH_GROUP *aGroup)
void LoadContent(LINE_READER &aReader, SCH_SHEET *aSheet, int aVersion=SEXPR_SCHEMATIC_FILE_VERSION)
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
bool m_appending
Schematic load append status.
int m_version
Version of file being loaded.
void loadFile(const wxString &aFileName, SCH_SHEET *aSheet)
static void FormatLibSymbol(LIB_SYMBOL *aPart, OUTPUTFORMATTER &aFormatter)
void DeleteSymbol(const wxString &aLibraryPath, const wxString &aSymbolName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Delete the entire LIB_SYMBOL associated with aAliasName from the library aLibraryPath.
void loadHierarchy(const SCH_SHEET_PATH &aParentSheetPath, SCH_SHEET *aSheet)
void SaveSymbol(const wxString &aLibraryPath, const LIB_SYMBOL *aSymbol, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aSymbol to an existing library located at aLibraryPath.
static std::vector< LIB_SYMBOL * > ParseLibSymbols(std::string &aSymbolText, std::string aSource, int aFileVersion=SEXPR_SCHEMATIC_FILE_VERSION)
void saveBusAlias(std::shared_ptr< BUS_ALIAS > aAlias)
OUTPUTFORMATTER * m_out
The formatter for saving SCH_SCREEN objects.
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load information from some input file format that this SCH_IO implementation knows about,...
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
wxString m_error
For throwing exceptions or errors on partial loads.
void saveInstances(const std::vector< SCH_SHEET_INSTANCE > &aSheets)
bool isBuffering(const std::map< std::string, UTF8 > *aProperties)
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
SCH_SHEET * m_rootSheet
The root sheet of the schematic being loaded.
void cacheLib(const wxString &aLibraryFileName, const std::map< std::string, UTF8 > *aProperties)
void saveRuleArea(SCH_RULE_AREA *aRuleArea)
void saveField(SCH_FIELD *aField)
SCH_IO_KICAD_SEXPR_LIB_CACHE * m_cache
void Format(SCH_SHEET *aSheet)
bool IsLibraryWritable(const wxString &aLibraryPath) override
Return true if the library at aLibraryPath is writable.
void init(SCHEMATIC *aSchematic, const std::map< std::string, UTF8 > *aProperties=nullptr)
initialize PLUGIN like a constructor would.
bool DeleteLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Delete an existing library and returns true, or if library does not exist returns false,...
void saveBitmap(const SCH_BITMAP &aBitmap)
void saveText(SCH_TEXT *aText)
void saveSheet(SCH_SHEET *aSheet, const SCH_SHEET_LIST &aSheetList)
int GetModifyHash() const override
Return the modification hash from the library cache.
bool CanReadLibrary(const wxString &aLibraryPath) const override
Checks if this IO object can read the specified library file/directory.
void saveLine(SCH_LINE *aLine)
void saveNoConnect(SCH_NO_CONNECT *aNoConnect)
void saveTable(SCH_TABLE *aTable)
std::stack< wxString > m_currentPath
Stack to maintain nested sheet paths.
void CreateLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Create a new empty library at aLibraryPath empty.
void saveJunction(SCH_JUNCTION *aJunction)
std::function< bool(wxString aTitle, int aIcon, wxString aMsg, wxString aAction)> m_queryUserCallback
void saveTextBox(SCH_TEXTBOX *aText)
void saveSymbol(SCH_SYMBOL *aSymbol, const SCHEMATIC &aSchematic, const SCH_SHEET_LIST &aSheetList, bool aForClipboard, const SCH_SHEET_PATH *aRelativePath=nullptr)
void saveBusEntry(SCH_BUS_ENTRY_BASE *aBusEntry)
void GetAvailableSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that are present on symbols in this library.
SCH_IO(const wxString &aName)
Definition sch_io.h:373
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
int GetBodyStyle() const
Definition sch_item.h:244
bool IsPrivate() const
Definition sch_item.h:250
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition sch_item.h:309
AUTOPLACE_ALGO GetFieldsAutoplaced() const
Return whether the fields have been automatically placed.
Definition sch_item.h:592
wxString GetClass() const override
Return the class name.
Definition sch_item.h:177
COLOR4D GetColor() const
int GetDiameter() const
VECTOR2I GetPosition() const override
SPIN_STYLE GetSpinStyle() const
LABEL_FLAG_SHAPE GetShape() const
Definition sch_label.h:180
std::vector< SCH_FIELD > & GetFields()
Definition sch_label.h:212
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:42
virtual STROKE_PARAMS GetStroke() const override
Definition sch_line.h:193
VECTOR2I GetEndPoint() const
Definition sch_line.h:144
VECTOR2I GetStartPoint() const
Definition sch_line.h:139
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:145
VECTOR2I GetPosition() const override
bool GetExcludedFromSim() const override
bool GetExcludedFromBoard() const override
bool GetDNP() const override
Set or clear the 'Do Not Populate' flag.
bool GetExcludedFromBOM() const override
const PAGE_INFO & GetPageSettings() const
Definition sch_screen.h:139
auto & GetBusAliases() const
Return a set of bus aliases defined in this screen.
Definition sch_screen.h:524
const std::map< wxString, LIB_SYMBOL * > & GetLibSymbols() const
Fetch a list of unique LIB_SYMBOL object pointers required to properly render each SCH_SYMBOL in this...
Definition sch_screen.h:488
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:117
const wxString & GetFileName() const
Definition sch_screen.h:152
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
wxString GroupsSanityCheck(bool repair=false)
Consistency check of internal m_groups structure.
const TITLE_BLOCK & GetTitleBlock() const
Definition sch_screen.h:163
KIID m_uuid
A unique identifier for each schematic file.
Definition sch_screen.h:744
void SetFileReadOnly(bool aIsReadOnly)
Definition sch_screen.h:154
void SetFileExists(bool aFileExists)
Definition sch_screen.h:157
SCH_SCREEN * GetScreen()
STROKE_PARAMS GetStroke() const override
Definition sch_shape.h:58
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
std::optional< SCH_SHEET_PATH > GetSheetPathByKIIDPath(const KIID_PATH &aPath, bool aIncludeLastSheet=true) const
Finds a SCH_SHEET_PATH that matches the provided KIID_PATH.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool empty() const
Forwarded method from std::vector.
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
SCH_SCREEN * LastScreen()
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
void pop_back()
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:47
bool GetExcludedFromBoard() const override
Definition sch_sheet.h:397
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:321
bool HasRootInstance() const
Check to see if this sheet has a root sheet instance.
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the sheet's fields.
Definition sch_sheet.h:87
bool GetExcludedFromBOM() const override
Definition sch_sheet.h:391
VECTOR2I GetSize() const
Definition sch_sheet.h:118
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:116
VECTOR2I GetPosition() const override
Definition sch_sheet.h:415
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
const SCH_SHEET_INSTANCE & GetRootInstance() const
Return the root sheet instance data.
KIGFX::COLOR4D GetBorderColor() const
Definition sch_sheet.h:124
bool GetExcludedFromSim() const override
Definition sch_sheet.h:385
int GetBorderWidth() const
Definition sch_sheet.h:121
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition sch_sheet.h:187
bool GetDNP() const override
Set or clear the 'Do Not Populate' flags.
Definition sch_sheet.h:402
const std::vector< SCH_SHEET_INSTANCE > & GetInstances() const
Definition sch_sheet.h:430
KIGFX::COLOR4D GetBackgroundColor() const
Definition sch_sheet.h:127
Schematic symbol object.
Definition sch_symbol.h:75
std::vector< std::unique_ptr< SCH_PIN > > & GetRawPins()
Definition sch_symbol.h:626
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:134
bool UseLibIdLookup() const
Definition sch_symbol.h:181
wxString GetSchSymbolLibraryName() const
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
VECTOR2I GetPosition() const override
Definition sch_symbol.h:760
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:164
bool GetInstance(SCH_SYMBOL_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
int GetOrientation() const override
Get the display symbol orientation.
wxString GetPrefix() const
Definition sch_symbol.h:235
void SetRowHeight(int aRow, int aHeight)
Definition sch_table.h:137
const STROKE_PARAMS & GetSeparatorsStroke() const
Definition sch_table.h:77
void SetColCount(int aCount)
Definition sch_table.h:119
bool StrokeExternal() const
Definition sch_table.h:53
int GetRowHeight(int aRow) const
Definition sch_table.h:139
void SetColWidth(int aCol, int aWidth)
Definition sch_table.h:127
std::vector< SCH_TABLECELL * > GetCells() const
Definition sch_table.h:157
int GetColWidth(int aCol) const
Definition sch_table.h:129
const STROKE_PARAMS & GetBorderStroke() const
Definition sch_table.h:59
int GetColCount() const
Definition sch_table.h:120
bool StrokeHeaderSeparator() const
Definition sch_table.h:56
void DeleteMarkedCells()
Definition sch_table.h:182
SCH_TABLECELL * GetCell(int aRow, int aCol) const
Definition sch_table.h:147
bool StrokeColumns() const
Definition sch_table.h:99
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition sch_table.h:226
bool StrokeRows() const
Definition sch_table.h:102
int GetRowCount() const
Definition sch_table.h:122
int GetMarginBottom() const
Definition sch_textbox.h:66
int GetMarginLeft() const
Definition sch_textbox.h:63
bool GetExcludedFromSim() const override
Definition sch_textbox.h:92
int GetMarginRight() const
Definition sch_textbox.h:65
int GetMarginTop() const
Definition sch_textbox.h:64
VECTOR2I GetPosition() const override
Definition sch_text.h:141
bool GetExcludedFromSim() const override
Definition sch_text.h:88
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition richio.h:253
Simple container to manage line stroke parameters.
void SetWidth(int aWidth)
void Format(OUTPUTFORMATTER *out, const EDA_IU_SCALE &aIuScale) const
static const char * PropPowerSymsOnly
bool GetExcludedFromBoard() const override
Definition symbol.h:192
bool GetDNP() const override
Set or clear the 'Do Not Populate' flag.
Definition symbol.h:197
bool GetExcludedFromBOM() const override
Definition symbol.h:186
bool GetExcludedFromSim() const override
Definition symbol.h:180
virtual void Format(OUTPUTFORMATTER *aFormatter) const
Output the object to aFormatter in s-expression form.
const char * c_str() const
Definition utf8.h:109
wxString wx_str() const
Definition utf8.cpp:45
static REPORTER & GetInstance()
Definition reporter.cpp:190
static void SetReporter(REPORTER *aReporter)
Set the reporter to use for reporting font substitution warnings.
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:416
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
#define STRUCT_DELETED
flag indication structures to be erased
#define SKIP_STRUCT
flag indicating that the structure should be ignored
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
#define DEFAULT_SIZE_TEXT
This is the "default-of-the-default" hardcoded text size; individual application define their own def...
Definition eda_text.h:69
const wxChar *const traceSchPlugin
Flag to enable legacy schematic plugin debug output.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
Definition layer_id.cpp:31
@ LAYER_WIRE
Definition layer_ids.h:451
@ LAYER_NOTES
Definition layer_ids.h:466
@ LAYER_BUS
Definition layer_ids.h:452
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:96
KICOMMON_API std::string FormatInternalUnits(const EDA_IU_SCALE &aIuScale, int aValue)
Converts aValue from internal units to a string appropriate for writing to file.
KICOMMON_API std::string FormatAngle(const EDA_ANGLE &aAngle)
Convert aAngle from board units to a string appropriate for writing to file.
void FormatUuid(OUTPUTFORMATTER *aOut, const KIID &aUuid)
void FormatStreamData(OUTPUTFORMATTER &aOut, const wxStreamBuffer &aStream)
Write binary data to the formatter as base 64 encoded string.
void FormatBool(OUTPUTFORMATTER *aOut, const wxString &aKey, bool aValue)
Writes a boolean to the formatter, in the style (aKey [yes|no])
#define SEXPR_SCHEMATIC_FILE_VERSION
Schematic file version.
Class to handle a set of SCH_ITEMs.
void formatArc(OUTPUTFORMATTER *aFormatter, EDA_SHAPE *aArc, bool aIsPrivate, const STROKE_PARAMS &aStroke, FILL_T aFillMode, const COLOR4D &aFillColor, bool aInvertY, const KIID &aUuid)
const char * getSheetPinShapeToken(LABEL_FLAG_SHAPE aShape)
void formatCircle(OUTPUTFORMATTER *aFormatter, EDA_SHAPE *aCircle, bool aIsPrivate, const STROKE_PARAMS &aStroke, FILL_T aFillMode, const COLOR4D &aFillColor, bool aInvertY, const KIID &aUuid)
const char * getTextTypeToken(KICAD_T aType)
void formatBezier(OUTPUTFORMATTER *aFormatter, EDA_SHAPE *aBezier, bool aIsPrivate, const STROKE_PARAMS &aStroke, FILL_T aFillMode, const COLOR4D &aFillColor, bool aInvertY, const KIID &aUuid)
void formatRect(OUTPUTFORMATTER *aFormatter, EDA_SHAPE *aRect, bool aIsPrivate, const STROKE_PARAMS &aStroke, FILL_T aFillMode, const COLOR4D &aFillColor, bool aInvertY, const KIID &aUuid)
void formatPoly(OUTPUTFORMATTER *aFormatter, EDA_SHAPE *aPolyLine, bool aIsPrivate, const STROKE_PARAMS &aStroke, FILL_T aFillMode, const COLOR4D &aFillColor, bool aInvertY, const KIID &aUuid)
EDA_ANGLE getSheetPinAngle(SHEET_SIDE aSide)
void formatFill(OUTPUTFORMATTER *aFormatter, FILL_T aFillMode, const COLOR4D &aFillColor)
Fill token formatting helper.
AUTOPLACE_ALGO
Definition sch_item.h:68
@ AUTOPLACE_MANUAL
Definition sch_item.h:71
@ AUTOPLACE_AUTO
Definition sch_item.h:70
std::string toUTFTildaText(const wxString &txt)
Convert a wxString to UTF8 and replace any control characters with a ~, where a control character is ...
const int scale
std::string FormatDouble2Str(double aValue)
Print a float number without using scientific notation and no trailing 0 This function is intended in...
std::string EscapedUTF8(const wxString &aString)
Return an 8 bit UTF8 string given aString in Unicode form.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
@ CTX_LEGACY_LIBID
A simple container for sheet instance information.
A simple container for schematic symbol instance information.
@ SYM_ORIENT_270
Definition symbol.h:42
@ SYM_MIRROR_Y
Definition symbol.h:44
@ SYM_ORIENT_180
Definition symbol.h:41
@ SYM_MIRROR_X
Definition symbol.h:43
@ SYM_ORIENT_90
Definition symbol.h:40
std::map< wxString, LIB_SYMBOL *, LibSymbolMapSort > LIB_SYMBOL_MAP
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ REFERENCE
Field Reference of part, i.e. "IC21".
wxLogTrace helper definitions.
@ SCH_GROUP_T
Definition typeinfo.h:175
@ SCH_TABLE_T
Definition typeinfo.h:167
@ SCH_LINE_T
Definition typeinfo.h:165
@ SCH_NO_CONNECT_T
Definition typeinfo.h:162
@ SCH_SYMBOL_T
Definition typeinfo.h:174
@ SCH_TABLECELL_T
Definition typeinfo.h:168
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:173
@ SCH_LABEL_T
Definition typeinfo.h:169
@ SCH_SHEET_T
Definition typeinfo.h:177
@ SCH_MARKER_T
Definition typeinfo.h:160
@ SCH_SHAPE_T
Definition typeinfo.h:151
@ SCH_RULE_AREA_T
Definition typeinfo.h:172
@ SCH_HIER_LABEL_T
Definition typeinfo.h:171
@ SCH_BUS_BUS_ENTRY_T
Definition typeinfo.h:164
@ SCH_TEXT_T
Definition typeinfo.h:153
@ SCH_BUS_WIRE_ENTRY_T
Definition typeinfo.h:163
@ SCH_BITMAP_T
Definition typeinfo.h:166
@ SCH_TEXTBOX_T
Definition typeinfo.h:154
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:170
@ SCH_JUNCTION_T
Definition typeinfo.h:161
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695