KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_sheet_path.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) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
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
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <refdes_utils.h>
27#include <hash.h>
28#include <sch_screen.h>
29#include <sch_marker.h>
30#include <sch_label.h>
31#include <sch_shape.h>
32#include <sch_sheet_path.h>
33#include <sch_symbol.h>
34#include <sch_sheet.h>
35#include <schematic.h>
36#include <string_utils.h>
37#include <template_fieldnames.h>
38#include <trace_helpers.h>
39
40#include <wx/filename.h>
41#include <wx/log.h>
42
43
50{
51public:
53 SCH_ITEM( nullptr, NOT_USED )
54 {}
55
56 wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const override
57 {
58 return _( "(Deleted Item)" );
59 }
60
61 wxString GetClass() const override
62 {
63 return wxT( "DELETED_SHEET_ITEM" );
64 }
65
67 {
68 static DELETED_SHEET_ITEM* item = nullptr;
69
70 if( !item )
71 item = new DELETED_SHEET_ITEM();
72
73 return item;
74 }
75
76 // pure virtuals:
77 void SetPosition( const VECTOR2I& ) override {}
78 void Move( const VECTOR2I& aMoveVector ) override {}
79 void MirrorHorizontally( int aCenter ) override {}
80 void MirrorVertically( int aCenter ) override {}
81 void Rotate( const VECTOR2I& aCenter, bool aRotateCCW ) override {}
82
83 double Similarity( const SCH_ITEM& aOther ) const override
84 {
85 return 0.0;
86 }
87
88 bool operator==( const SCH_ITEM& aOther ) const override
89 {
90 return false;
91 }
92
93#if defined(DEBUG)
94 void Show( int , std::ostream& ) const override {}
95#endif
96};
97
98
107
108
110{
111 m_DNP = aSheet.GetDNP();
115 m_ExcludedFromPosFiles = false; // Sheets don't have position files exclusion
116}
117
118
119namespace std
120{
122 {
123 return path.GetCurrentHash();
124 }
125}
126
127
133
134
136{
137 initFromOther( aOther );
138}
139
140
142{
143 initFromOther( aOther );
144 return *this;
145}
146
147
148// Move assignment operator
150{
151 m_sheets = std::move( aOther.m_sheets );
152
153 m_virtualPageNumber = aOther.m_virtualPageNumber;
154 m_current_hash = aOther.m_current_hash;
155 m_cached_page_number = aOther.m_cached_page_number;
156
157 m_recursion_test_cache = std::move( aOther.m_recursion_test_cache );
158
159 return *this;
160}
161
162
164{
165 SCH_SHEET_PATH retv = *this;
166
167 size_t size = aOther.size();
168
169 for( size_t i = 0; i < size; i++ )
170 retv.push_back( aOther.at( i ) );
171
172 return retv;
173}
174
175
177{
178 m_sheets = aOther.m_sheets;
182
183 // Note: don't copy m_recursion_test_cache as it is slow and we want std::vector<SCH_SHEET_PATH>
184 // to be very fast to construct for use in the connectivity algorithm.
186}
187
189{
190 m_current_hash = 0;
191
192 for( SCH_SHEET* sheet : m_sheets )
193 hash_combine( m_current_hash, sheet->m_Uuid.Hash() );
194}
195
196
197int SCH_SHEET_PATH::Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const
198{
199 if( size() > aSheetPathToTest.size() )
200 return 1;
201
202 if( size() < aSheetPathToTest.size() )
203 return -1;
204
205 // otherwise, same number of sheets.
206 for( unsigned i = 0; i < size(); i++ )
207 {
208 if( at( i )->m_Uuid < aSheetPathToTest.at( i )->m_Uuid )
209 return -1;
210
211 if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
212 return 1;
213 }
214
215 return 0;
216}
217
218
219int SCH_SHEET_PATH::ComparePageNum( const SCH_SHEET_PATH& aSheetPathToTest ) const
220{
221 wxString pageA = this->GetPageNumber();
222 wxString pageB = aSheetPathToTest.GetPageNumber();
223
224 int pageNumComp = SCH_SHEET::ComparePageNum( pageA, pageB );
225
226 if( pageNumComp == 0 )
227 {
228 int virtualPageA = GetVirtualPageNumber();
229 int virtualPageB = aSheetPathToTest.GetVirtualPageNumber();
230
231 if( virtualPageA > virtualPageB )
232 pageNumComp = 1;
233 else if( virtualPageA < virtualPageB )
234 pageNumComp = -1;
235 }
236
237 return pageNumComp;
238}
239
240
241bool SCH_SHEET_PATH::IsContainedWithin( const SCH_SHEET_PATH& aSheetPathToTest ) const
242{
243 if( aSheetPathToTest.size() > size() )
244 return false;
245
246 for( size_t i = 0; i < aSheetPathToTest.size(); ++i )
247 {
248 if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
249 {
250 wxLogTrace( traceSchSheetPaths, "Sheet path '%s' is not within path '%s'.",
251 aSheetPathToTest.Path().AsString(), Path().AsString() );
252
253 return false;
254 }
255 }
256
257 wxLogTrace( traceSchSheetPaths, "Sheet path '%s' is within path '%s'.",
258 aSheetPathToTest.Path().AsString(), Path().AsString() );
259
260 return true;
261}
262
263
265{
266 if( !empty() )
267 return m_sheets.back();
268
269 return nullptr;
270}
271
272
274{
275 SCH_SHEET* lastSheet = Last();
276
277 if( lastSheet )
278 return lastSheet->GetScreen();
279
280 return nullptr;
281}
282
283
285{
286 SCH_SHEET* lastSheet = Last();
287
288 if( lastSheet )
289 return lastSheet->GetScreen();
290
291 return nullptr;
292}
293
294
296{
297 for( SCH_SHEET* sheet : m_sheets )
298 {
299 if( sheet->GetExcludedFromSim() )
300 return true;
301 }
302
303 return false;
304}
305
306
307bool SCH_SHEET_PATH::GetExcludedFromSim( const wxString& aVariantName ) const
308{
309 if( aVariantName.IsEmpty() )
310 return GetExcludedFromSim();
311
312 for( SCH_SHEET* sheet : m_sheets )
313 {
314 if( sheet->GetExcludedFromSim( this, aVariantName ) )
315 return true;
316 }
317
318 return false;
319}
320
321
323{
324 for( SCH_SHEET* sheet : m_sheets )
325 {
326 if( sheet->GetExcludedFromBOM() )
327 return true;
328 }
329
330 return false;
331}
332
333
334bool SCH_SHEET_PATH::GetExcludedFromBOM( const wxString& aVariantName ) const
335{
336 if( aVariantName.IsEmpty() )
337 return GetExcludedFromBOM();
338
339 for( SCH_SHEET* sheet : m_sheets )
340 {
341 if( sheet->GetExcludedFromBOM( this, aVariantName ) )
342 return true;
343 }
344
345 return false;
346}
347
348
350{
351 for( SCH_SHEET* sheet : m_sheets )
352 {
353 if( sheet->GetExcludedFromBoard() )
354 return true;
355 }
356
357 return false;
358}
359
360
361bool SCH_SHEET_PATH::GetExcludedFromBoard( const wxString& aVariantName ) const
362{
363 if( aVariantName.IsEmpty() )
364 return GetExcludedFromBoard();
365
366 for( SCH_SHEET* sheet : m_sheets )
367 {
368 if( sheet->GetExcludedFromBoard( this, aVariantName ) )
369 return true;
370 }
371
372 return false;
373}
374
375
377{
378 for( SCH_SHEET* sheet : m_sheets )
379 {
380 if( sheet->GetDNP() )
381 return true;
382 }
383
384 return false;
385}
386
387
388bool SCH_SHEET_PATH::GetDNP( const wxString& aVariantName ) const
389{
390 if( aVariantName.IsEmpty() )
391 return GetDNP();
392
393 for( SCH_SHEET* sheet : m_sheets )
394 {
395 if( sheet->GetDNP( this, aVariantName ) )
396 return true;
397 }
398
399 return false;
400}
401
402
404{
405 wxString s;
406
407 s = wxT( "/" ); // This is the root path
408
409 // Start at 1 to avoid the root sheet, which does not need to be added to the path.
410 // Its timestamp changes anyway.
411 for( unsigned i = 1; i < size(); i++ )
412 s += at( i )->m_Uuid.AsString() + "/";
413
414 return s;
415}
416
417
419{
421 size_t size = m_sheets.size();
422
423 if( m_sheets.empty() )
424 return path;
425
426 if( m_sheets[0]->m_Uuid != niluuid )
427 {
428 path.reserve( size );
429 path.push_back( m_sheets[0]->m_Uuid );
430 }
431 else
432 {
433 // Skip the virtual root
434 path.reserve( size - 1 );
435 }
436
437 for( size_t i = 1; i < size; i++ )
438 path.push_back( m_sheets[i]->m_Uuid );
439
440 return path;
441}
442
443
444wxString SCH_SHEET_PATH::PathHumanReadable( bool aUseShortRootName,
445 bool aStripTrailingSeparator,
446 bool aEscapeSheetNames ) const
447{
448 wxString s;
449
450 // Determine the starting index - skip virtual root if present
451 size_t startIdx = 0;
452
453 if( !empty() && at( 0 )->IsVirtualRootSheet() )
454 startIdx = 1;
455
456 if( aUseShortRootName )
457 {
458 s = wxS( "/" ); // Use only the short name in netlists
459 }
460 else
461 {
462 wxString fileName;
463
464 if( size() > startIdx && at( startIdx )->GetScreen() )
465 fileName = at( startIdx )->GetScreen()->GetFileName();
466
467 wxFileName fn = fileName;
468
469 s = fn.GetName() + wxS( "/" );
470 }
471
472 // Start at startIdx + 1 since we've already processed the root sheet.
473 for( unsigned i = startIdx + 1; i < size(); i++ )
474 {
475 wxString sheetName = at( i )->GetField( FIELD_T::SHEET_NAME )->GetShownText( false );
476
477 if( aEscapeSheetNames )
478 sheetName = EscapeString( sheetName, CTX_NETNAME );
479
480 s << sheetName << wxS( "/" );
481 }
482
483 if( aStripTrailingSeparator && s.EndsWith( "/" ) )
484 s = s.Left( s.length() - 1 );
485
486 return s;
487}
488
489
491{
492 std::vector<SCH_ITEM*> items;
493
494 std::copy_if( LastScreen()->Items().begin(), LastScreen()->Items().end(),
495 std::back_inserter( items ),
496 []( SCH_ITEM* aItem )
497 {
498 return ( aItem->Type() == SCH_SYMBOL_T
499 || aItem->Type() == SCH_GLOBAL_LABEL_T
500 || aItem->Type() == SCH_SHAPE_T );
501 } );
502
503 std::optional<wxString> variantName;
504 const SCHEMATIC* schematic = LastScreen()->Schematic();
505
506 if( schematic )
507 variantName = schematic->GetCurrentVariant();
508
509 for( SCH_ITEM* item : items )
510 {
511 if( item->Type() == SCH_SYMBOL_T )
512 {
513 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
514
515 symbol->GetField( FIELD_T::REFERENCE )->SetText( symbol->GetRef( this ) );
516 symbol->SetUnit( symbol->GetUnitSelection( this ) );
517 LastScreen()->Update( item, false );
518 }
519 else if( item->Type() == SCH_GLOBAL_LABEL_T )
520 {
521 SCH_GLOBALLABEL* label = static_cast<SCH_GLOBALLABEL*>( item );
522
523 if( label->GetFields().size() > 0 ) // Possible when reading a legacy .sch schematic
524 {
525 SCH_FIELD* intersheetRefs = label->GetField( FIELD_T::INTERSHEET_REFS );
526
527 // Fixup for legacy files which didn't store a position for the intersheet refs
528 // unless they were shown.
529 if( intersheetRefs->GetPosition() == VECTOR2I() && !intersheetRefs->IsVisible() )
531
532 intersheetRefs->SetVisible( label->Schematic()->Settings().m_IntersheetRefsShow );
533 LastScreen()->Update( intersheetRefs );
534 }
535 }
536 else if( item->Type() == SCH_SHAPE_T )
537 {
538 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
539 shape->UpdateHatching();
540 }
541 }
542}
543
544
545void SCH_SHEET_PATH::GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols,
546 bool aForceIncludeOrphanSymbols ) const
547{
548 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
549 {
550 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
551 AppendSymbol( aReferences, symbol, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
552 }
553}
554
555
557 bool aIncludePowerSymbols,
558 bool aForceIncludeOrphanSymbols ) const
559{
560 // Skip pseudo-symbols, which have a reference starting with #. This mainly
561 // affects power symbols.
562 if( aIncludePowerSymbols || aSymbol->GetRef( this )[0] != wxT( '#' ) )
563 {
564 if( aSymbol->GetLibSymbolRef() || aForceIncludeOrphanSymbols )
565 {
566 SCH_REFERENCE schReference( aSymbol, *this );
567
568 schReference.SetSheetNumber( GetPageNumberAsInt() );
569 aReferences.AddItem( schReference );
570 }
571 }
572}
573
574
576 bool aIncludePowerSymbols ) const
577{
578 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
579 {
580 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
581 AppendMultiUnitSymbol( aRefList, symbol, aIncludePowerSymbols );
582 }
583}
584
585
587 SCH_SYMBOL* aSymbol,
588 bool aIncludePowerSymbols ) const
589{
590 // Skip pseudo-symbols, which have a reference starting with #. This mainly
591 // affects power symbols.
592 if( !aIncludePowerSymbols && aSymbol->GetRef( this )[0] == wxT( '#' ) )
593 return;
594
595 LIB_SYMBOL* symbol = aSymbol->GetLibSymbolRef().get();
596
597 if( symbol && symbol->GetUnitCount() > 1 )
598 {
599 SCH_REFERENCE schReference = SCH_REFERENCE( aSymbol, *this );
600 schReference.SetSheetNumber( GetPageNumberAsInt() );
601 wxString reference_str = schReference.GetRef();
602
603 // Never lock unassigned references
604 if( reference_str[reference_str.Len() - 1] == '?' )
605 return;
606
607 aRefList[reference_str].AddItem( schReference );
608 }
609}
610
611
613{
614 return m_current_hash == d1.GetCurrentHash();
615}
616
617
618bool SCH_SHEET_PATH::TestForRecursion( const wxString& aSrcFileName, const wxString& aDestFileName )
619{
620 auto pair = std::make_pair( aSrcFileName, aDestFileName );
621
622 if( m_recursion_test_cache.count( pair ) )
623 return m_recursion_test_cache.at( pair );
624
625 SCHEMATIC* sch = LastScreen()->Schematic();
626
627 wxCHECK_MSG( sch, false, "No SCHEMATIC found in SCH_SHEET_PATH::TestForRecursion!" );
628
629 wxFileName rootFn = sch->GetFileName();
630 wxFileName srcFn = aSrcFileName;
631 wxFileName destFn = aDestFileName;
632
633 if( srcFn.IsRelative() )
634 srcFn.MakeAbsolute( rootFn.GetPath() );
635
636 if( destFn.IsRelative() )
637 destFn.MakeAbsolute( rootFn.GetPath() );
638
639 // The source and destination sheet file names cannot be the same.
640 if( srcFn == destFn )
641 {
642 m_recursion_test_cache[pair] = true;
643 return true;
644 }
645
649 unsigned i = 0;
650
651 while( i < size() )
652 {
653 wxFileName cmpFn = at( i )->GetFileName();
654
655 if( cmpFn.IsRelative() )
656 cmpFn.MakeAbsolute( rootFn.GetPath() );
657
658 // Test if the file name of the destination sheet is in anywhere in this sheet path.
659 if( cmpFn == destFn )
660 break;
661
662 i++;
663 }
664
665 // The destination sheet file name was not found in the sheet path or the destination
666 // sheet file name is the root sheet so no recursion is possible.
667 if( i >= size() || i == 0 )
668 {
669 m_recursion_test_cache[pair] = false;
670 return false;
671 }
672
673 // Walk back up to the root sheet to see if the source file name is already a parent in
674 // the sheet path. If so, recursion will occur.
675 do
676 {
677 i -= 1;
678
679 wxFileName cmpFn = at( i )->GetFileName();
680
681 if( cmpFn.IsRelative() )
682 cmpFn.MakeAbsolute( rootFn.GetPath() );
683
684 if( cmpFn == srcFn )
685 {
686 m_recursion_test_cache[pair] = true;
687 return true;
688 }
689
690 } while( i != 0 );
691
692 // The source sheet file name is not a parent of the destination sheet file name.
693 m_recursion_test_cache[pair] = false;
694 return false;
695}
696
697
699{
700 SCH_SHEET* sheet = Last();
701
702 wxCHECK( sheet, wxEmptyString );
703
704 KIID_PATH tmpPath = Path();
705
706 if( !tmpPath.empty() )
707 tmpPath.pop_back();
708 else
709 wxFAIL_MSG( wxS( "Sheet paths must have a least one valid sheet." ) );
710
711 return sheet->getPageNumber( tmpPath );
712}
713
715{
716 long page;
717 wxString pageStr = GetPageNumber();
718
719 if( pageStr.ToLong( &page ) )
720 return (int) page;
721
722 return GetVirtualPageNumber();
723}
724
725
726void SCH_SHEET_PATH::SetPageNumber( const wxString& aPageNumber )
727{
728 SCH_SHEET* sheet = Last();
729
730 wxCHECK( sheet, /* void */ );
731
732 KIID_PATH tmpPath = Path();
733
734 if( !tmpPath.empty() )
735 {
736 tmpPath.pop_back();
737 }
738 else
739 {
740 wxCHECK_MSG( false, /* void */, wxS( "Sheet paths must have a least one valid sheet." ) );
741 }
742
743 sheet->addInstance( tmpPath );
744 sheet->setPageNumber( tmpPath, aPageNumber );
745}
746
747
749 const wxString& aProjectName )
750{
751 wxCHECK( !aProjectName.IsEmpty(), /* void */ );
752
753 SCH_SHEET_PATH newSheetPath( aPrefixSheetPath );
754 SCH_SHEET_PATH currentSheetPath( *this );
755
756 // Prefix the new hierarchical path.
757 newSheetPath = newSheetPath + currentSheetPath;
758
759 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
760 {
761 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
762
763 wxCHECK2( symbol, continue );
764
765 SCH_SYMBOL_INSTANCE newSymbolInstance;
766
767 if( symbol->GetInstance( newSymbolInstance, Path(), true ) )
768 {
769 newSymbolInstance.m_ProjectName = aProjectName;
770
771 // Use an existing symbol instance for this path if it exists.
772 newSymbolInstance.m_Path = newSheetPath.Path();
773 symbol->AddHierarchicalReference( newSymbolInstance );
774 }
775 else if( !symbol->GetInstances().empty() )
776 {
777 newSymbolInstance.m_ProjectName = aProjectName;
778
779 // Use the first symbol instance if any symbol instance data exists.
780 newSymbolInstance = symbol->GetInstances()[0];
781 newSymbolInstance.m_Path = newSheetPath.Path();
782 symbol->AddHierarchicalReference( newSymbolInstance );
783 }
784 else
785 {
786 newSymbolInstance.m_ProjectName = aProjectName;
787
788 // Fall back to the last saved symbol field and unit settings if there is no
789 // instance data.
790 newSymbolInstance.m_Path = newSheetPath.Path();
791 newSymbolInstance.m_Reference = symbol->GetField( FIELD_T::REFERENCE )->GetText();
792 newSymbolInstance.m_Unit = symbol->GetUnit();
793 symbol->AddHierarchicalReference( newSymbolInstance );
794 }
795 }
796}
797
798
800{
801 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
802 {
803 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
804
805 wxCHECK2( symbol, continue );
806
807 SCH_SHEET_PATH fullSheetPath( aPrefixSheetPath );
808 SCH_SHEET_PATH currentSheetPath( *this );
809
810 // Prefix the hierarchical path of the symbol instance to be removed.
811 fullSheetPath = fullSheetPath + currentSheetPath;
812 symbol->RemoveInstance( fullSheetPath );
813 }
814}
815
816
817void SCH_SHEET_PATH::CheckForMissingSymbolInstances( const wxString& aProjectName )
818{
819 // Skip sheet paths without screens (e.g., sheets that haven't been loaded yet or virtual root)
820 if( aProjectName.IsEmpty() || !LastScreen() )
821 return;
822
823 wxLogTrace( traceSchSheetPaths, "CheckForMissingSymbolInstances for path: %s (project: %s)",
824 PathHumanReadable( false ), aProjectName );
825 wxLogTrace( traceSchSheetPaths, " Sheet path size=%zu, Path().AsString()='%s'",
826 size(), Path().AsString() );
827
828 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
829 {
830 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
831
832 wxCHECK2( symbol, continue );
833
834 SCH_SYMBOL_INSTANCE symbolInstance;
835
836 if( !symbol->GetInstance( symbolInstance, Path() ) )
837 {
838 wxLogTrace( traceSchSheetPaths, "Adding missing symbol \"%s\" instance data for "
839 "sheet path '%s'.",
840 symbol->m_Uuid.AsString(), PathHumanReadable( false ) );
841
842 // Legacy schematics that are not shared do not contain separate instance data.
843 // The symbol reference and unit are saved in the reference field and unit entries.
844 if( ( LastScreen()->GetRefCount() <= 1 ) &&
845 ( LastScreen()->GetFileFormatVersionAtLoad() <= 20200310 ) )
846 {
847 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
848 symbolInstance.m_Reference = refField->GetShownText( this, true );
849 symbolInstance.m_Unit = symbol->GetUnit();
850
851 wxLogTrace( traceSchSheetPaths,
852 " Legacy format: Using reference '%s' from field, unit %d",
853 symbolInstance.m_Reference, symbolInstance.m_Unit );
854 }
855 else if( !symbol->GetInstances().empty() )
856 {
857 // When a schematic is opened as a different project (e.g., a subsheet opened
858 // directly from File Browser), use the first available instance data.
859 // This provides better UX than showing unannotated references.
860 const SCH_SYMBOL_INSTANCE& firstInstance = symbol->GetInstances()[0];
861 symbolInstance.m_Reference = firstInstance.m_Reference;
862 symbolInstance.m_Unit = firstInstance.m_Unit;
863
864 wxLogTrace( traceSchSheetPaths,
865 " Using first available instance: ref=%s, unit=%d",
866 symbolInstance.m_Reference, symbolInstance.m_Unit );
867 }
868 else
869 {
870 // Fall back to the symbol's reference field and unit if no instance data exists.
871 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
872 symbolInstance.m_Reference = refField->GetText();
873 symbolInstance.m_Unit = symbol->GetUnit();
874
875 wxLogTrace( traceSchSheetPaths,
876 " No instance data: Using reference '%s' from field, unit %d",
877 symbolInstance.m_Reference, symbolInstance.m_Unit );
878 }
879
880 symbolInstance.m_ProjectName = aProjectName;
881 symbolInstance.m_Path = Path();
882 symbol->AddHierarchicalReference( symbolInstance );
883
884 wxLogTrace( traceSchSheetPaths,
885 " Created instance: ref=%s, path=%s",
886 symbolInstance.m_Reference, symbolInstance.m_Path.AsString() );
887 }
888 else
889 {
890 wxLogTrace( traceSchSheetPaths,
891 " Symbol %s already has instance: ref=%s, path=%s",
892 symbol->m_Uuid.AsString(),
893 symbolInstance.m_Reference,
894 symbolInstance.m_Path.AsString() );
895 }
896 }
897}
898
899
901{
902 wxCHECK( m_sheets.size() > 1, /* void */ );
903
904 wxFileName sheetFileName = Last()->GetFileName();
905
906 // If the sheet file name is absolute, then the user requested is so don't make it relative.
907 if( sheetFileName.IsAbsolute() )
908 return;
909
910 SCH_SCREEN* screen = LastScreen();
911 SCH_SCREEN* parentScreen = m_sheets[ m_sheets.size() - 2 ]->GetScreen();
912
913 wxCHECK( screen && parentScreen, /* void */ );
914
915 wxFileName fileName = screen->GetFileName();
916 wxFileName parentFileName = parentScreen->GetFileName();
917
918 // SCH_SCREEN file names must be absolute. If they are not, someone set them incorrectly
919 // on load or on creation.
920 wxCHECK( fileName.IsAbsolute() && parentFileName.IsAbsolute(), /* void */ );
921
922 if( fileName.GetPath() == parentFileName.GetPath() )
923 {
924 Last()->SetFileName( fileName.GetFullName() );
925 }
926 else if( fileName.MakeRelativeTo( parentFileName.GetPath() ) )
927 {
928 Last()->SetFileName( fileName.GetFullPath() );
929 }
930 else
931 {
932 Last()->SetFileName( screen->GetFileName() );
933 }
934
935 wxLogTrace( tracePathsAndFiles,
936 wxT( "\n File name: '%s'"
937 "\n parent file name '%s',"
938 "\n sheet '%s' file name '%s'." ),
939 screen->GetFileName(), parentScreen->GetFileName(), PathHumanReadable(),
940 Last()->GetFileName() );
941}
942
943
945{
946 if( aSheet != nullptr )
947 BuildSheetList( aSheet, false );
948}
949
950
951void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity )
952{
953 if( !aSheet )
954 return;
955
956 wxLogTrace( traceSchSheetPaths,
957 "BuildSheetList called with sheet '%s' (UUID=%s, isVirtualRoot=%d)",
958 aSheet->GetName(),
959 aSheet->m_Uuid.AsString(),
960 aSheet->m_Uuid == niluuid ? 1 : 0 );
961
962 // Special handling for virtual root: process its children without adding the root itself
963 if( aSheet->IsVirtualRootSheet() )
964 {
965 wxLogTrace( traceSchSheetPaths, " Skipping virtual root, processing children only" );
966
967 if( aSheet->GetScreen() )
968 {
969 std::vector<SCH_ITEM*> childSheets;
970 aSheet->GetScreen()->GetSheets( &childSheets );
971
972 for( SCH_ITEM* item : childSheets )
973 {
974 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
975 BuildSheetList( sheet, aCheckIntegrity );
976 }
977 }
978
979 return;
980 }
981
982 std::vector<SCH_SHEET*> badSheets;
983
984 m_currentSheetPath.push_back( aSheet );
985 m_currentSheetPath.SetVirtualPageNumber( static_cast<int>( size() ) + 1 );
986 push_back( m_currentSheetPath );
987
988 if( m_currentSheetPath.LastScreen() )
989 {
990 wxString parentFileName = aSheet->GetFileName();
991 std::vector<SCH_ITEM*> childSheets;
992 m_currentSheetPath.LastScreen()->GetSheets( &childSheets );
993
994 for( SCH_ITEM* item : childSheets )
995 {
996 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
997
998 if( aCheckIntegrity )
999 {
1000 if( !m_currentSheetPath.TestForRecursion( sheet->GetFileName(), parentFileName ) )
1001 BuildSheetList( sheet, true );
1002 else
1003 badSheets.push_back( sheet );
1004 }
1005 else
1006 {
1007 // If we are not performing a full recursion test, at least check if we are in
1008 // a simple recursion scenario to prevent stack overflow crashes
1009 wxCHECK2_MSG( sheet->GetFileName() != aSheet->GetFileName(), continue,
1010 wxT( "Recursion prevented in SCH_SHEET_LIST::BuildSheetList" ) );
1011
1012 BuildSheetList( sheet, false );
1013 }
1014 }
1015 }
1016
1017 if( aCheckIntegrity )
1018 {
1019 for( SCH_SHEET* sheet : badSheets )
1020 {
1021 m_currentSheetPath.LastScreen()->Remove( sheet );
1022 m_currentSheetPath.LastScreen()->SetContentModified();
1023 }
1024 }
1025
1026 m_currentSheetPath.pop_back();
1027}
1028
1029
1030void SCH_SHEET_LIST::SortByHierarchicalPageNumbers( bool aUpdateVirtualPageNums )
1031{
1032 for( const SCH_SHEET_PATH& path : *this )
1033 path.CachePageNumber();
1034
1035 std::sort( begin(), end(),
1036 []( const SCH_SHEET_PATH& a, const SCH_SHEET_PATH& b ) -> bool
1037 {
1038 // Find the divergence point in the paths
1039 size_t common_len = 0;
1040 size_t min_len = std::min( a.size(), b.size() );
1041
1042 while( common_len < min_len && a.at( common_len )->m_Uuid == b.at( common_len )->m_Uuid )
1043 common_len++;
1044
1045 // If one path is a prefix of the other, the shorter one comes first
1046 // This ensures parents come before children
1047 if( common_len == a.size() )
1048 return true; // a is a prefix of b - a is the parent
1049 if( common_len == b.size() )
1050 return false; // b is a prefix of a - b is the parent
1051
1052 // Paths diverge at common_len
1053 // If they share the same parent, sort by page number
1054 // This ensures siblings are sorted by page number
1055 SCH_SHEET* sheet_a = a.at( common_len );
1056 SCH_SHEET* sheet_b = b.at( common_len );
1057
1058 // Create partial paths to get to these sheets for page number comparison
1059 KIID_PATH ancestor;
1060 for( size_t i = 0; i < common_len; i++ )
1061 ancestor.push_back( a.at( i )->m_Uuid );
1062
1063 // Compare page numbers - use the last sheet's page number
1064 wxString page_a = sheet_a->getPageNumber( ancestor );
1065 wxString page_b = sheet_b->getPageNumber( ancestor );
1066
1067 int retval = SCH_SHEET::ComparePageNum( page_a, page_b );
1068
1069 if( retval != 0 )
1070 return retval < 0;
1071
1072 // If page numbers are the same, use virtual page numbers as a tie-breaker
1074 return true;
1075 else if( a.GetVirtualPageNumber() > b.GetVirtualPageNumber() )
1076 return false;
1077
1078 // Finally, use UUIDs for stable ordering when everything else is equal
1079 return a.GetCurrentHash() < b.GetCurrentHash();
1080 } );
1081
1082 if( aUpdateVirtualPageNums )
1083 {
1084 int virtualPageNum = 1;
1085
1086 for( SCH_SHEET_PATH& sheet : *this )
1087 sheet.SetVirtualPageNumber( virtualPageNum++ );
1088 }
1089}
1090
1091
1092void SCH_SHEET_LIST::SortByPageNumbers( bool aUpdateVirtualPageNums )
1093{
1094 for( const SCH_SHEET_PATH& path : *this )
1095 path.CachePageNumber();
1096
1097 std::sort( begin(), end(),
1098 []( const SCH_SHEET_PATH& a, const SCH_SHEET_PATH& b ) -> bool
1099 {
1101 b.GetCachedPageNumber() );
1102
1103 if( retval < 0 )
1104 return true;
1105 else if( retval > 0 )
1106 return false;
1107
1109 return true;
1110 else if( a.GetVirtualPageNumber() > b.GetVirtualPageNumber() )
1111 return false;
1112
1113 // Enforce strict ordering. If the page numbers are the same, use UUIDs
1114 return a.GetCurrentHash() < b.GetCurrentHash();
1115 } );
1116
1117 if( aUpdateVirtualPageNums )
1118 {
1119 int virtualPageNum = 1;
1120
1121 for( SCH_SHEET_PATH& sheet : *this )
1122 sheet.SetVirtualPageNumber( virtualPageNum++ );
1123 }
1124}
1125
1126
1127bool SCH_SHEET_LIST::NameExists( const wxString& aSheetName ) const
1128{
1129 for( const SCH_SHEET_PATH& sheet : *this )
1130 {
1131 if( sheet.Last()->GetName() == aSheetName )
1132 return true;
1133 }
1134
1135 return false;
1136}
1137
1138
1139bool SCH_SHEET_LIST::PageNumberExists( const wxString& aPageNumber ) const
1140{
1141 for( const SCH_SHEET_PATH& sheet : *this )
1142 {
1143 if( sheet.GetPageNumber() == aPageNumber )
1144 return true;
1145 }
1146
1147 return false;
1148}
1149
1150
1151void SCH_SHEET_LIST::TrimToPageNumbers( const std::vector<wxString>& aPageInclusions )
1152{
1153 auto it = std::remove_if( begin(), end(),
1154 [&]( const SCH_SHEET_PATH& sheet )
1155 {
1156 return std::find( aPageInclusions.begin(),
1157 aPageInclusions.end(),
1158 sheet.GetPageNumber() ) == aPageInclusions.end();
1159 } );
1160
1161 erase( it, end() );
1162}
1163
1164
1166{
1167 for( const SCH_SHEET_PATH& sheet : *this )
1168 {
1169 if( sheet.LastScreen() && sheet.LastScreen()->IsContentModified() )
1170 return true;
1171 }
1172
1173 return false;
1174}
1175
1176
1178{
1179 for( const SCH_SHEET_PATH& sheet : *this )
1180 {
1181 if( sheet.LastScreen() )
1182 sheet.LastScreen()->SetContentModified( false );
1183 }
1184}
1185
1186
1187SCH_ITEM* SCH_SHEET_LIST::ResolveItem( const KIID& aID, SCH_SHEET_PATH* aPathOut, bool aAllowNullptrReturn ) const
1188{
1189 for( const SCH_SHEET_PATH& sheet : *this )
1190 {
1191 SCH_ITEM* item = sheet.ResolveItem( aID );
1192
1193 if( item )
1194 {
1195 if( aPathOut )
1196 *aPathOut = sheet;
1197
1198 return item;
1199 }
1200 }
1201
1202 // Not found; weak reference has been deleted.
1203 if( aAllowNullptrReturn )
1204 return nullptr;
1205 else
1207}
1208
1209
1211{
1212 for( SCH_ITEM* aItem : LastScreen()->Items() )
1213 {
1214 if( aItem->m_Uuid == aID )
1215 return aItem;
1216
1217 SCH_ITEM* childMatch = nullptr;
1218
1219 aItem->RunOnChildren(
1220 [&]( SCH_ITEM* aChild )
1221 {
1222 if( aChild->m_Uuid == aID )
1223 childMatch = aChild;
1224 },
1226
1227 if( childMatch )
1228 return childMatch;
1229 }
1230
1231 return nullptr;
1232}
1233
1234
1235void SCH_SHEET_LIST::FillItemMap( std::map<KIID, EDA_ITEM*>& aMap )
1236{
1237 for( const SCH_SHEET_PATH& sheet : *this )
1238 {
1239 SCH_SCREEN* screen = sheet.LastScreen();
1240
1241 for( SCH_ITEM* aItem : screen->Items() )
1242 {
1243 aMap[ aItem->m_Uuid ] = aItem;
1244
1245 aItem->RunOnChildren(
1246 [&]( SCH_ITEM* aChild )
1247 {
1248 aMap[ aChild->m_Uuid ] = aChild;
1249 },
1251 }
1252 }
1253}
1254
1255
1257{
1258 // List of reference for power symbols
1259 SCH_REFERENCE_LIST references;
1260 SCH_REFERENCE_LIST additionalreferences; // Todo: add as a parameter to this function
1261
1262 // Map of locked symbols (not used, but needed by Annotate()
1263 SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
1264
1265 // Build the list of power symbols:
1266 for( SCH_SHEET_PATH& sheet : *this )
1267 {
1268 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
1269 {
1270 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1271 LIB_SYMBOL* libSymbol = symbol->GetLibSymbolRef().get();
1272
1273 if( libSymbol && libSymbol->IsPower() )
1274 {
1275 SCH_REFERENCE schReference( symbol, sheet );
1276 references.AddItem( schReference );
1277 }
1278 }
1279 }
1280
1281 // Find duplicate, and silently clear annotation of duplicate
1282 std::map<wxString, int> ref_list; // stores the existing references
1283
1284 for( unsigned ii = 0; ii< references.GetCount(); ++ii )
1285 {
1286 wxString curr_ref = references[ii].GetRef();
1287
1288 if( curr_ref.IsEmpty() )
1289 continue;
1290
1291 if( ref_list.find( curr_ref ) == ref_list.end() )
1292 {
1293 ref_list[curr_ref] = ii;
1294 continue;
1295 }
1296
1297 // Possible duplicate, if the ref ends by a number:
1298 if( curr_ref.Last() < '0' && curr_ref.Last() > '9' )
1299 continue; // not annotated
1300
1301 // Duplicate: clear annotation by removing the number ending the ref
1302 while( !curr_ref.IsEmpty() && curr_ref.Last() >= '0' && curr_ref.Last() <= '9' )
1303 curr_ref.RemoveLast();
1304
1305 references[ii].SetRef( curr_ref );
1306 }
1307
1308 // Break full symbol reference into name (prefix) and number:
1309 // example: IC1 become IC, and 1
1310 references.SplitReferences();
1311
1312 // Ensure all power symbols have the reference starting by '#'
1313 // (Not sure this is really useful)
1314 for( unsigned ii = 0; ii< references.GetCount(); ++ii )
1315 {
1316 SCH_REFERENCE& ref_unit = references[ii];
1317
1318 if( ref_unit.GetRef()[0] != '#' )
1319 {
1320 wxString new_ref = "#" + ref_unit.GetRef();
1321 ref_unit.SetRef( new_ref );
1322 ref_unit.SetRefNum( ii );
1323 }
1324 }
1325}
1326
1327
1328void SCH_SHEET_LIST::GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols,
1329 bool aForceIncludeOrphanSymbols ) const
1330{
1331 for( const SCH_SHEET_PATH& sheet : *this )
1332 sheet.GetSymbols( aReferences, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
1333}
1334
1335
1337 const SCH_SHEET_PATH& aSheetPath,
1338 bool aIncludePowerSymbols,
1339 bool aForceIncludeOrphanSymbols ) const
1340{
1341 for( const SCH_SHEET_PATH& sheet : *this )
1342 {
1343 if( sheet.IsContainedWithin( aSheetPath ) )
1344 sheet.GetSymbols( aReferences, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
1345 }
1346}
1347
1348
1349void SCH_SHEET_LIST::GetSheetsWithinPath( std::vector<SCH_SHEET_PATH>& aSheets,
1350 const SCH_SHEET_PATH& aSheetPath ) const
1351{
1352 for( const SCH_SHEET_PATH& sheet : *this )
1353 {
1354 if( sheet.IsContainedWithin( aSheetPath ) )
1355 aSheets.push_back( sheet );
1356 }
1357}
1358
1359
1360std::optional<SCH_SHEET_PATH> SCH_SHEET_LIST::GetSheetPathByKIIDPath( const KIID_PATH& aPath,
1361 bool aIncludeLastSheet ) const
1362{
1363 for( const SCH_SHEET_PATH& sheet : *this )
1364 {
1365 KIID_PATH testPath = sheet.Path();
1366
1367 if( !aIncludeLastSheet )
1368 testPath.pop_back();
1369
1370 if( testPath == aPath )
1371 return SCH_SHEET_PATH( sheet );
1372 }
1373
1374 return std::nullopt;
1375}
1376
1377
1379 bool aIncludePowerSymbols ) const
1380{
1381 for( auto it = begin(); it != end(); ++it )
1382 {
1384 ( *it ).GetMultiUnitSymbols( tempMap, aIncludePowerSymbols );
1385
1386 for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : tempMap )
1387 {
1388 // Merge this list into the main one
1389 unsigned n_refs = pair.second.GetCount();
1390
1391 for( unsigned thisRef = 0; thisRef < n_refs; ++thisRef )
1392 aRefList[pair.first].AddItem( pair.second[thisRef] );
1393 }
1394 }
1395}
1396
1397
1398bool SCH_SHEET_LIST::TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy,
1399 const wxString& aDestFileName )
1400{
1401 if( empty() )
1402 return false;
1403
1404 SCHEMATIC* sch = at( 0 ).LastScreen()->Schematic();
1405
1406 wxCHECK_MSG( sch, false, "No SCHEMATIC found in SCH_SHEET_LIST::TestForRecursion!" );
1407
1408 wxFileName rootFn = sch->GetFileName();
1409 wxFileName destFn = aDestFileName;
1410
1411 if( destFn.IsRelative() )
1412 destFn.MakeAbsolute( rootFn.GetPath() );
1413
1414 // Test each SCH_SHEET_PATH in this SCH_SHEET_LIST for potential recursion.
1415 for( unsigned i = 0; i < size(); i++ )
1416 {
1417 // Test each SCH_SHEET_PATH in the source sheet.
1418 for( unsigned j = 0; j < aSrcSheetHierarchy.size(); j++ )
1419 {
1420 const SCH_SHEET_PATH* sheetPath = &aSrcSheetHierarchy[j];
1421
1422 for( unsigned k = 0; k < sheetPath->size(); k++ )
1423 {
1424 if( at( i ).TestForRecursion( sheetPath->GetSheet( k )->GetFileName(),
1425 aDestFileName ) )
1426 {
1427 return true;
1428 }
1429 }
1430 }
1431 }
1432
1433 // The source sheet file can safely be added to the destination sheet file.
1434 return false;
1435}
1436
1437
1439{
1440 for( SCH_SHEET_PATH& path : *this )
1441 {
1442 if( path.Path() == aPath->Path() )
1443 return &path;
1444 }
1445
1446 return nullptr;
1447}
1448
1449
1451{
1452 for( SCH_SHEET_PATH& sheetpath : *this )
1453 {
1454 if( sheetpath.LastScreen() == aScreen )
1455 return sheetpath;
1456 }
1457
1458 return SCH_SHEET_PATH();
1459}
1460
1461
1463{
1464 SCH_SHEET_LIST retval;
1465
1466 for( const SCH_SHEET_PATH& sheetpath : *this )
1467 {
1468 if( sheetpath.LastScreen() == aScreen )
1469 retval.push_back( sheetpath );
1470 }
1471
1472 return retval;
1473}
1474
1475
1477 const std::vector<SCH_SYMBOL_INSTANCE>& aSymbolInstances )
1478{
1479 for( SCH_SHEET_PATH& sheetPath : *this )
1480 {
1481 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
1482 {
1483 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1484
1485 wxCHECK2( symbol, continue );
1486
1487 KIID_PATH sheetPathWithSymbolUuid = sheetPath.Path();
1488 sheetPathWithSymbolUuid.push_back( symbol->m_Uuid );
1489
1490 auto it = std::find_if( aSymbolInstances.begin(), aSymbolInstances.end(),
1491 [ sheetPathWithSymbolUuid ]( const SCH_SYMBOL_INSTANCE& r ) -> bool
1492 {
1493 return sheetPathWithSymbolUuid == r.m_Path;
1494 } );
1495
1496 if( it == aSymbolInstances.end() )
1497 {
1498 wxLogTrace( traceSchSheetPaths, "No symbol instance found for symbol '%s'",
1499 sheetPathWithSymbolUuid.AsString() );
1500 continue;
1501 }
1502
1503 // Symbol instance paths are stored and looked up in memory with the root path so use
1504 // the full path here.
1505 symbol->AddHierarchicalReference( sheetPath.Path(), it->m_Reference, it->m_Unit );
1506 symbol->GetField( FIELD_T::REFERENCE )->SetText( it->m_Reference );
1507
1508 if( !it->m_Value.IsEmpty() )
1509 symbol->SetValueFieldText( it->m_Value );
1510
1511 if( !it->m_Footprint.IsEmpty() )
1512 symbol->SetFootprintFieldText( it->m_Footprint );
1513
1514 symbol->UpdatePrefix();
1515 }
1516 }
1517}
1518
1519
1520void SCH_SHEET_LIST::UpdateSheetInstanceData( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances )
1521{
1522
1523 for( SCH_SHEET_PATH& path : *this )
1524 {
1525 SCH_SHEET* sheet = path.Last();
1526
1527 wxCHECK2( sheet && path.Last(), continue );
1528
1529 auto it = std::find_if( aSheetInstances.begin(), aSheetInstances.end(),
1530 [&path]( const SCH_SHEET_INSTANCE& r ) -> bool
1531 {
1532 return path.Path() == r.m_Path;
1533 } );
1534
1535 if( it == aSheetInstances.end() )
1536 {
1537 wxLogTrace( traceSchSheetPaths, "No sheet instance found for path '%s'",
1538 path.Path().AsString() );
1539 continue;
1540 }
1541
1542 wxLogTrace( traceSchSheetPaths, "Setting sheet '%s' instance '%s' page number '%s'",
1543 ( sheet->GetName().IsEmpty() ) ? wxString( wxT( "root" ) ) : sheet->GetName(),
1544 path.Path().AsString(), it->m_PageNumber );
1545 path.SetPageNumber( it->m_PageNumber );
1546 }
1547}
1548
1549
1550std::vector<KIID_PATH> SCH_SHEET_LIST::GetPaths() const
1551{
1552 std::vector<KIID_PATH> paths;
1553
1554 for( const SCH_SHEET_PATH& sheetPath : *this )
1555 paths.emplace_back( sheetPath.Path() );
1556
1557 return paths;
1558}
1559
1560
1561std::vector<SCH_SHEET_INSTANCE> SCH_SHEET_LIST::GetSheetInstances() const
1562{
1563 std::vector<SCH_SHEET_INSTANCE> retval;
1564
1565 for( const SCH_SHEET_PATH& path : *this )
1566 {
1567 const SCH_SHEET* sheet = path.Last();
1568
1569 wxCHECK2( sheet, continue );
1570
1571 SCH_SHEET_INSTANCE instance;
1572 SCH_SHEET_PATH tmpPath = path;
1573
1574 tmpPath.pop_back();
1575 instance.m_Path = tmpPath.Path();
1576 instance.m_PageNumber = path.GetPageNumber();
1577
1578 retval.push_back( std::move( instance ) );
1579 }
1580
1581 return retval;
1582}
1583
1584
1586{
1587 for( const SCH_SHEET_PATH& instance : *this )
1588 {
1589 if( !instance.GetPageNumber().IsEmpty() )
1590 return false;
1591 }
1592
1593 return true;
1594}
1595
1596
1598{
1599 // Don't accidentally renumber existing sheets.
1600 wxCHECK( AllSheetPageNumbersEmpty(), /* void */ );
1601
1602 wxString tmp;
1603 int pageNumber = 1;
1604
1605 for( SCH_SHEET_PATH& instance : *this )
1606 {
1607 if( instance.Last()->IsVirtualRootSheet() )
1608 continue;
1609
1610 tmp.Printf( "%d", pageNumber );
1611 instance.SetPageNumber( tmp );
1612 pageNumber += 1;
1613 }
1614}
1615
1616
1618 const wxString& aProjectName )
1619{
1620 for( SCH_SHEET_PATH& sheetPath : *this )
1621 sheetPath.AddNewSymbolInstances( aPrefixSheetPath, aProjectName );
1622}
1623
1624
1626{
1627 for( SCH_SHEET_PATH& sheetPath : *this )
1628 sheetPath.RemoveSymbolInstances( aPrefixSheetPath );
1629}
1630
1631
1633 int aLastVirtualPageNumber )
1634{
1635 wxString pageNumber;
1636 int lastUsedPageNumber = 1;
1637 int nextVirtualPageNumber = aLastVirtualPageNumber;
1638
1639 // Fetch the list of page numbers already in use.
1640 std::vector< wxString > usedPageNumbers;
1641
1642 if( aPrefixSheetPath.size() )
1643 {
1644 SCH_SHEET_LIST prefixHierarchy( aPrefixSheetPath.at( 0 ) );
1645
1646 for( const SCH_SHEET_PATH& path : prefixHierarchy )
1647 {
1648 pageNumber = path.GetPageNumber();
1649
1650 if( !pageNumber.IsEmpty() )
1651 usedPageNumbers.emplace_back( pageNumber );
1652 }
1653 }
1654
1655 for( SCH_SHEET_PATH& sheetPath : *this )
1656 {
1657 KIID_PATH tmp = sheetPath.Path();
1658 SCH_SHEET_PATH newSheetPath( aPrefixSheetPath );
1659
1660 // Prefix the new hierarchical path.
1661 newSheetPath = newSheetPath + sheetPath;
1662
1663 // Sheets cannot have themselves in the path.
1664 tmp.pop_back();
1665
1666 SCH_SHEET* sheet = sheetPath.Last();
1667
1668 wxCHECK2( sheet, continue );
1669
1670 nextVirtualPageNumber += 1;
1671
1672 SCH_SHEET_INSTANCE instance;
1673
1674 // Add the instance if it doesn't already exist
1675 if( !sheet->getInstance( instance, tmp, true ) )
1676 {
1677 sheet->addInstance( tmp );
1678 sheet->getInstance( instance, tmp, true );
1679 }
1680
1681 // Get a new page number if we don't have one
1682 if( instance.m_PageNumber.IsEmpty() )
1683 {
1684 // Generate the next available page number.
1685 do
1686 {
1687 pageNumber.Printf( wxT( "%d" ), lastUsedPageNumber );
1688 lastUsedPageNumber += 1;
1689 } while( std::find( usedPageNumbers.begin(), usedPageNumbers.end(), pageNumber ) !=
1690 usedPageNumbers.end() );
1691
1692 instance.m_PageNumber = pageNumber;
1693 newSheetPath.SetVirtualPageNumber( nextVirtualPageNumber );
1694 }
1695
1696 newSheetPath.SetPageNumber( instance.m_PageNumber );
1697 usedPageNumbers.push_back( instance.m_PageNumber );
1698 }
1699}
1700
1701
1702void SCH_SHEET_LIST::CheckForMissingSymbolInstances( const wxString& aProjectName )
1703{
1704 wxLogTrace( traceSchSheetPaths,
1705 "SCH_SHEET_LIST::CheckForMissingSymbolInstances: Processing %zu sheet paths",
1706 size() );
1707
1708 for( SCH_SHEET_PATH& sheetPath : *this )
1709 {
1710 wxLogTrace( traceSchSheetPaths,
1711 " Processing sheet path: '%s' (size=%zu, KIID_PATH='%s')",
1712 sheetPath.PathHumanReadable( false ),
1713 sheetPath.size(),
1714 sheetPath.Path().AsString() );
1715 sheetPath.CheckForMissingSymbolInstances( aProjectName );
1716 }
1717}
1718
1719
1721{
1722 int lastVirtualPageNumber = 1;
1723
1724 for( const SCH_SHEET_PATH& sheetPath : *this )
1725 {
1726 if( sheetPath.GetVirtualPageNumber() > lastVirtualPageNumber )
1727 lastVirtualPageNumber = sheetPath.GetVirtualPageNumber();
1728 }
1729
1730 return lastVirtualPageNumber;
1731}
1732
1733
1734bool SCH_SHEET_LIST::HasPath( const KIID_PATH& aPath ) const
1735{
1736 for( const SCH_SHEET_PATH& path : *this )
1737 {
1738 if( path.Path() == aPath )
1739 return true;
1740 }
1741
1742 return false;
1743}
1744
1745
1746bool SCH_SHEET_LIST::ContainsSheet( const SCH_SHEET* aSheet ) const
1747{
1748 for( const SCH_SHEET_PATH& path : *this )
1749 {
1750 for( size_t i = 0; i < path.size(); i++ )
1751 {
1752 if( path.at( i ) == aSheet )
1753 return true;
1754 }
1755 }
1756
1757 return false;
1758}
1759
1760
1761std::optional<SCH_SHEET_PATH> SCH_SHEET_LIST::GetOrdinalPath( const SCH_SCREEN* aScreen ) const
1762{
1763 // Sheet paths with sheets that do not have a screen object are not valid.
1764 if( !aScreen )
1765 return std::nullopt;
1766
1767 for( const SCH_SHEET_PATH& path: *this )
1768 {
1769 if( path.LastScreen() == aScreen )
1770 return std::optional<SCH_SHEET_PATH>( path );
1771 }
1772
1773 return std::nullopt;
1774}
bool IsContentModified() const
Definition base_screen.h:60
void SetContentModified(bool aModified=true)
Definition base_screen.h:59
wxString GetClass() const override
Return the class name.
void SetPosition(const VECTOR2I &) override
static DELETED_SHEET_ITEM * GetInstance()
double Similarity(const SCH_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
bool operator==(const SCH_ITEM &aOther) const override
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
const KIID m_Uuid
Definition eda_item.h:521
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
virtual void UpdateHatching() const
virtual bool IsVisible() const
Definition eda_text.h:187
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:398
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
wxString AsString() const
Definition kiid.cpp:368
Definition kiid.h:49
wxString AsString() const
Definition kiid.cpp:247
Define a library symbol object.
Definition lib_symbol.h:83
bool IsPower() const override
int GetUnitCount() const override
Holds all the data relating to one schematic.
Definition schematic.h:88
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
SCHEMATIC_SETTINGS & Settings() const
wxString GetCurrentVariant() const
Return the current variant being edited.
VECTOR2I GetPosition() const override
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:116
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0, const wxString &aVariantName=wxEmptyString) const
void SetText(const wxString &aText) override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this label.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode)
Definition sch_item.h:630
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:252
int GetUnit() const
Definition sch_item.h:238
virtual void SetUnit(int aUnit)
Definition sch_item.h:237
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:54
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
std::vector< SCH_FIELD > & GetFields()
Definition sch_label.h:212
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
void SplitReferences()
Attempt to split all reference designators into a name (U) and number (1).
void AddItem(const SCH_REFERENCE &aItem)
A helper to define a symbol's reference designator in a schematic.
void SetRef(const wxString &aReference)
void SetRefNum(int aNum)
wxString GetRef() const
void SetSheetNumber(int aSheetNumber)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:118
const wxString & GetFileName() const
Definition sch_screen.h:153
SCHEMATIC * Schematic() const
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
void GetSheets(std::vector< SCH_ITEM * > *aItems) const
Similar to Items().OfType( SCH_SHEET_T ), but return the sheets in a deterministic order (L-R,...
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.
SCH_ITEM * ResolveItem(const KIID &aID, SCH_SHEET_PATH *aPathOut=nullptr, bool aAllowNullptrReturn=false) const
Fetch a SCH_ITEM by ID.
void GetMultiUnitSymbols(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, bool aIncludePowerSymbols=true) const
Add a SCH_REFERENCE_LIST object to aRefList for each same-reference set of multi-unit parts in the li...
std::optional< SCH_SHEET_PATH > GetOrdinalPath(const SCH_SCREEN *aScreen) const
Return the ordinal sheet path of aScreen.
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Fill an item cache for temporary use when many items need to be fetched.
SCH_SHEET_PATH m_currentSheetPath
void TrimToPageNumbers(const std::vector< wxString > &aPageInclusions)
Truncates the list by removing sheet's with page numbers not in the given list.
void SortByPageNumbers(bool aUpdateVirtualPageNums=true)
Sort the list of sheets by page number.
void AddNewSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath, const wxString &aProjectName)
Attempt to add new symbol instances for all symbols in this list of sheet paths prefixed with aPrefix...
bool NameExists(const wxString &aSheetName) const
std::vector< SCH_SHEET_INSTANCE > GetSheetInstances() const
Fetch the instance information for all of the sheets in the hierarchy.
void UpdateSheetInstanceData(const std::vector< SCH_SHEET_INSTANCE > &aSheetInstances)
Update all of the sheet instance information using aSheetInstances.
void SetInitialPageNumbers()
Set initial sheet page numbers.
void RemoveSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath)
SCH_SHEET_LIST FindAllSheetsForScreen(const SCH_SCREEN *aScreen) const
Return a SCH_SHEET_LIST with a copy of all the SCH_SHEET_PATH using a particular screen.
bool AllSheetPageNumbersEmpty() const
Check all of the sheet instance for empty page numbers.
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets.
bool IsModified() const
Check the entire hierarchy for any modifications.
SCH_SHEET_LIST(SCH_SHEET *aSheet=nullptr)
Construct a flattened list of SCH_SHEET_PATH objects from aSheet.
void AnnotatePowerSymbols()
Silently annotate the not yet annotated power symbols of the entire hierarchy of the sheet path list.
int GetLastVirtualPageNumber() const
void UpdateSymbolInstanceData(const std::vector< SCH_SYMBOL_INSTANCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
void GetSheetsWithinPath(std::vector< SCH_SHEET_PATH > &aSheets, const SCH_SHEET_PATH &aSheetPath) const
Add a SCH_SHEET_PATH object to aSheets for each sheet in the list that are contained within aSheetPat...
bool PageNumberExists(const wxString &aPageNumber) const
void SortByHierarchicalPageNumbers(bool aUpdateVirtualPageNums=true)
This works like SortByPageNumbers, but it sorts the sheets first by their hierarchical depth and then...
void AddNewSheetInstances(const SCH_SHEET_PATH &aPrefixSheetPath, int aLastVirtualPageNumber)
bool ContainsSheet(const SCH_SHEET *aSheet) const
std::vector< KIID_PATH > GetPaths() const
void GetSymbolsWithinPath(SCH_REFERENCE_LIST &aReferences, const SCH_SHEET_PATH &aSheetPath, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets that are contained wi...
void BuildSheetList(SCH_SHEET *aSheet, bool aCheckIntegrity)
Build the list of sheets and their sheet path from aSheet.
SCH_SHEET_PATH FindSheetForScreen(const SCH_SCREEN *aScreen)
Return the first SCH_SHEET_PATH object (not necessarily the only one) using a particular screen.
void CheckForMissingSymbolInstances(const wxString &aProjectName)
bool HasPath(const KIID_PATH &aPath) const
SCH_SHEET_PATH * FindSheetForPath(const SCH_SHEET_PATH *aPath)
Return a pointer to the first SCH_SHEET_PATH object (not necessarily the only one) matching the provi...
bool TestForRecursion(const SCH_SHEET_LIST &aSrcSheetHierarchy, const wxString &aDestFileName)
Test every SCH_SHEET_PATH in this SCH_SHEET_LIST to verify if adding the sheets stored in aSrcSheetHi...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool GetExcludedFromBOM() const
void AppendMultiUnitSymbol(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, SCH_SYMBOL *aSymbol, bool aIncludePowerSymbols=true) const
Append a SCH_REFERENCE_LIST object to aRefList based on aSymbol, storing same-reference set of multi-...
const SCH_SHEET * GetSheet(unsigned aIndex) const
bool empty() const
Forwarded method from std::vector.
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Adds SCH_REFERENCE object to aReferences for each symbol in the sheet.
int ComparePageNum(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare sheets by their page number.
size_t GetCurrentHash() const
bool operator==(const SCH_SHEET_PATH &d1) const
void AddNewSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath, const wxString &aProjectName)
Attempt to add new symbol instances for all symbols in this sheet path prefixed with aPrefixSheetPath...
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
bool TestForRecursion(const wxString &aSrcFileName, const wxString &aDestFileName)
Test the SCH_SHEET_PATH file names to check adding the sheet stored in the file aSrcFileName to the s...
void UpdateAllScreenReferences() const
Update all the symbol references for this sheet path.
void MakeFilePathRelativeToParentSheet()
Make the sheet file name relative to its parent sheet.
SCH_ITEM * ResolveItem(const KIID &aID) const
Fetch a SCH_ITEM by ID.
wxString GetCachedPageNumber() const
std::vector< SCH_SHEET * > m_sheets
SCH_SCREEN * LastScreen()
int Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare if this is the same sheet path as aSheetPathToTest.
void GetMultiUnitSymbols(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, bool aIncludePowerSymbols=true) const
Add a SCH_REFERENCE_LIST object to aRefList for each same-reference set of multi-unit parts in the sh...
void initFromOther(const SCH_SHEET_PATH &aOther)
wxString m_cached_page_number
wxString GetPageNumber() const
void RemoveSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath)
void CheckForMissingSymbolInstances(const wxString &aProjectName)
bool IsContainedWithin(const SCH_SHEET_PATH &aSheetPathToTest) const
Check if this path is contained inside aSheetPathToTest.
SCH_SHEET * at(size_t aIndex) const
Forwarded method from std::vector.
void SetVirtualPageNumber(int aPageNumber)
Set the sheet instance virtual page number.
void AppendSymbol(SCH_REFERENCE_LIST &aReferences, SCH_SYMBOL *aSymbol, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Append a SCH_REFERENCE object to aReferences based on aSymbol.
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false, bool aEscapeSheetNames=false) const
Return the sheet path in a human readable form made from the sheet names.
std::map< std::pair< wxString, wxString >, bool > m_recursion_test_cache
bool GetExcludedFromSim() const
wxString PathAsString() const
Return the path of time stamps which do not changes even when editing sheet parameters.
bool GetExcludedFromBoard() const
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
SCH_SHEET_PATH & operator=(const SCH_SHEET_PATH &aOther)
int GetPageNumberAsInt() const
bool GetDNP() const
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
SCH_SHEET_PATH operator+(const SCH_SHEET_PATH &aOther)
int m_virtualPageNumber
Page numbers are maintained by the sheet load order.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
int GetVirtualPageNumber() const
void pop_back()
Forwarded method from std::vector.
void InitializeAttributes(const SCH_SHEET &aSheet)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:382
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:376
bool getInstance(SCH_SHEET_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
bool addInstance(const KIID_PATH &aInstance)
Add a new instance aSheetPath to the instance list.
wxString getPageNumber(const KIID_PATH &aParentPath) const
Return the sheet page number for aParentPath.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
wxString GetName() const
Definition sch_sheet.h:142
bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
static int ComparePageNum(const wxString &aPageNumberA, const wxString &aPageNumberB)
Compare page numbers of schematic sheets.
void setPageNumber(const KIID_PATH &aInstance, const wxString &aPageNumber)
Set the page number for the sheet instance aInstance.
bool IsVirtualRootSheet() const
bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flags.
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition sch_sheet.h:467
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
Schematic symbol object.
Definition sch_symbol.h:76
void UpdatePrefix()
Set the prefix based on the current reference designator.
bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:135
void RemoveInstance(const SCH_SHEET_PATH &aInstancePath)
bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
void SetFootprintFieldText(const wxString &aFootprint)
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
void SetValueFieldText(const wxString &aValue, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
bool GetExcludedFromPosFiles(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool GetInstance(SCH_SYMBOL_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:184
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
bool m_ExcludedFromBOM
bool m_ExcludedFromPosFiles
bool m_ExcludedFromSim
bool m_ExcludedFromBoard
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
@ NO_RECURSE
Definition eda_item.h:52
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
const wxChar *const traceSchSheetPaths
Flag to enable debug output of schematic symbol sheet path manipulation code.
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
Definition hash.h:32
KIID niluuid(0)
STL namespace.
Collection of utility functions for component reference designators (refdes)
@ AUTOPLACE_AUTO
Definition sch_item.h:70
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Container to map reference designators for multi-unit parts.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_NETNAME
A simple container for sheet instance information.
A simple container for schematic symbol instance information.
size_t operator()(const SCH_SHEET_PATH &path) const
@ INTERSHEET_REFS
Global label cross-reference page numbers.
@ REFERENCE
Field Reference of part, i.e. "IC21".
std::string path
VECTOR2I end
wxLogTrace helper definitions.
@ SCH_SYMBOL_T
Definition typeinfo.h:176
@ SCH_SHAPE_T
Definition typeinfo.h:153
@ NOT_USED
the 3d code uses this value
Definition typeinfo.h:79
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:172
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695