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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <set>
23
24#include <refdes_utils.h>
25#include <hash.h>
26#include <sch_screen.h>
27#include <sch_marker.h>
28#include <sch_label.h>
29#include <sch_shape.h>
30#include <sch_sheet_path.h>
31#include <sch_symbol.h>
32#include <sch_sheet.h>
33#include <schematic.h>
34#include <string_utils.h>
35#include <template_fieldnames.h>
36#include <trace_helpers.h>
37
38#include <wx/filename.h>
39#include <wx/log.h>
40
41
48{
49public:
51 SCH_ITEM( nullptr, NOT_USED )
52 {}
53
54 wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const override
55 {
56 return _( "(Deleted Item)" );
57 }
58
59 wxString GetClass() const override
60 {
61 return wxT( "DELETED_SHEET_ITEM" );
62 }
63
65 {
66 static DELETED_SHEET_ITEM* item = nullptr;
67
68 if( !item )
69 item = new DELETED_SHEET_ITEM();
70
71 return item;
72 }
73
74 // pure virtuals:
75 void SetPosition( const VECTOR2I& ) override {}
76 void Move( const VECTOR2I& aMoveVector ) override {}
77 void MirrorHorizontally( int aCenter ) override {}
78 void MirrorVertically( int aCenter ) override {}
79 void Rotate( const VECTOR2I& aCenter, bool aRotateCCW ) override {}
80
81 double Similarity( const SCH_ITEM& aOther ) const override
82 {
83 return 0.0;
84 }
85
86 bool operator==( const SCH_ITEM& aOther ) const override
87 {
88 return false;
89 }
90
91#if defined(DEBUG)
92 void Show( int , std::ostream& ) const override {}
93#endif
94};
95
96
98{
99 m_DNP = aSymbol.GetDNP();
104
105 // Snapshot the base pin-map override so a variant created for an unrelated attribute does not
106 // mask the base override on read (issue #2282).
108}
109
110
112{
113 return m_DNP != aSymbol.GetDNP() || m_ExcludedFromBOM != aSymbol.GetExcludedFromBOM()
116 || !m_PinMapOverride.IsDefault() || m_SymbolOverride.has_value();
117}
118
119
121{
122 m_DNP = aSheet.GetDNP();
126 m_ExcludedFromPosFiles = false; // Sheets don't have position files exclusion
127}
128
129
131{
132 return m_DNP != aSheet.GetDNP() || m_ExcludedFromBOM != aSheet.GetExcludedFromBOM()
133 || m_ExcludedFromSim != aSheet.GetExcludedFromSim() || !m_Fields.empty();
134}
135
136
137namespace std
138{
140 {
141 return path.GetCurrentHash();
142 }
143}
144
145
151
152
154{
155 initFromOther( aOther );
156}
157
158
160{
161 initFromOther( aOther );
162 return *this;
163}
164
165
166// Move assignment operator
168{
169 m_sheets = std::move( aOther.m_sheets );
170
171 m_virtualPageNumber = aOther.m_virtualPageNumber;
172 m_current_hash = aOther.m_current_hash;
173 m_cached_page_number = aOther.m_cached_page_number;
174 m_cached_path_valid = aOther.m_cached_path_valid;
175 m_cached_path = std::move( aOther.m_cached_path );
176
177 m_recursion_test_cache = std::move( aOther.m_recursion_test_cache );
178
179 return *this;
180}
181
182
184{
185 SCH_SHEET_PATH retv = *this;
186
187 size_t size = aOther.size();
188
189 for( size_t i = 0; i < size; i++ )
190 retv.push_back( aOther.at( i ) );
191
192 return retv;
193}
194
195
197{
198 m_sheets = aOther.m_sheets;
204
205 // Note: don't copy m_recursion_test_cache as it is slow and we want std::vector<SCH_SHEET_PATH>
206 // to be very fast to construct for use in the connectivity algorithm.
208}
209
211{
212 m_current_hash = 0;
213 m_cached_path_valid = false;
214
215 for( SCH_SHEET* sheet : m_sheets )
216 hash_combine( m_current_hash, sheet->m_Uuid.Hash() );
217}
218
219
220int SCH_SHEET_PATH::Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const
221{
222 if( size() > aSheetPathToTest.size() )
223 return 1;
224
225 if( size() < aSheetPathToTest.size() )
226 return -1;
227
228 // otherwise, same number of sheets.
229 for( unsigned i = 0; i < size(); i++ )
230 {
231 if( at( i )->m_Uuid < aSheetPathToTest.at( i )->m_Uuid )
232 return -1;
233
234 if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
235 return 1;
236 }
237
238 return 0;
239}
240
241
242int SCH_SHEET_PATH::ComparePageNum( const SCH_SHEET_PATH& aSheetPathToTest ) const
243{
244 wxString pageA = this->GetPageNumber();
245 wxString pageB = aSheetPathToTest.GetPageNumber();
246
247 int pageNumComp = SCH_SHEET::ComparePageNum( pageA, pageB );
248
249 if( pageNumComp == 0 )
250 {
251 int virtualPageA = GetVirtualPageNumber();
252 int virtualPageB = aSheetPathToTest.GetVirtualPageNumber();
253
254 if( virtualPageA > virtualPageB )
255 pageNumComp = 1;
256 else if( virtualPageA < virtualPageB )
257 pageNumComp = -1;
258 }
259
260 return pageNumComp;
261}
262
263
264bool SCH_SHEET_PATH::IsContainedWithin( const SCH_SHEET_PATH& aSheetPathToTest ) const
265{
266 if( aSheetPathToTest.size() > size() )
267 return false;
268
269 for( size_t i = 0; i < aSheetPathToTest.size(); ++i )
270 {
271 if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
272 {
273 wxLogTrace( traceSchSheetPaths, "Sheet path '%s' is not within path '%s'.",
274 aSheetPathToTest.Path().AsString(), Path().AsString() );
275
276 return false;
277 }
278 }
279
280 wxLogTrace( traceSchSheetPaths, "Sheet path '%s' is within path '%s'.",
281 aSheetPathToTest.Path().AsString(), Path().AsString() );
282
283 return true;
284}
285
286
288{
289 if( !empty() )
290 return m_sheets.back();
291
292 return nullptr;
293}
294
295
297{
298 SCH_SHEET* lastSheet = Last();
299
300 if( lastSheet )
301 return lastSheet->GetScreen();
302
303 return nullptr;
304}
305
306
308{
309 SCH_SHEET* lastSheet = Last();
310
311 if( lastSheet )
312 return lastSheet->GetScreen();
313
314 return nullptr;
315}
316
317
319{
320 for( SCH_SHEET* sheet : m_sheets )
321 {
322 if( sheet->GetExcludedFromSim() )
323 return true;
324 }
325
326 return false;
327}
328
329
330bool SCH_SHEET_PATH::GetExcludedFromSim( const wxString& aVariantName ) const
331{
332 if( aVariantName.IsEmpty() )
333 return GetExcludedFromSim();
334
335 SCH_SHEET_PATH copy = *this;
336
337 while( !copy.empty() )
338 {
339 SCH_SHEET* sheet = copy.Last();
340 copy.pop_back();
341
342 if( sheet->GetExcludedFromSim( &copy, aVariantName ) )
343 return true;
344 }
345
346 return false;
347}
348
349
351{
352 for( SCH_SHEET* sheet : m_sheets )
353 {
354 if( sheet->GetExcludedFromBOM() )
355 return true;
356 }
357
358 return false;
359}
360
361
362bool SCH_SHEET_PATH::GetExcludedFromBOM( const wxString& aVariantName ) const
363{
364 if( aVariantName.IsEmpty() )
365 return GetExcludedFromBOM();
366
367 SCH_SHEET_PATH copy = *this;
368
369 while( !copy.empty() )
370 {
371 SCH_SHEET* sheet = copy.Last();
372 copy.pop_back();
373
374 if( sheet->GetExcludedFromBOM( &copy, aVariantName ) )
375 return true;
376 }
377
378 return false;
379}
380
381
383{
384 for( SCH_SHEET* sheet : m_sheets )
385 {
386 if( sheet->GetExcludedFromBoard() )
387 return true;
388 }
389
390 return false;
391}
392
393
394bool SCH_SHEET_PATH::GetExcludedFromBoard( const wxString& aVariantName ) const
395{
396 if( aVariantName.IsEmpty() )
397 return GetExcludedFromBoard();
398
399 SCH_SHEET_PATH copy = *this;
400
401 while( !copy.empty() )
402 {
403 SCH_SHEET* sheet = copy.Last();
404 copy.pop_back();
405
406 if( sheet->GetExcludedFromBoard( &copy, aVariantName ) )
407 return true;
408 }
409
410 return false;
411}
412
413
415{
416 for( SCH_SHEET* sheet : m_sheets )
417 {
418 if( sheet->GetDNP() )
419 return true;
420 }
421
422 return false;
423}
424
425
426bool SCH_SHEET_PATH::GetDNP( const wxString& aVariantName ) const
427{
428 if( aVariantName.IsEmpty() )
429 return GetDNP();
430
431 SCH_SHEET_PATH copy = *this;
432
433 while( !copy.empty() )
434 {
435 SCH_SHEET* sheet = copy.Last();
436 copy.pop_back();
437
438 if( sheet->GetDNP( &copy, aVariantName ) )
439 return true;
440 }
441
442 return false;
443}
444
445
447{
448 wxString s;
449
450 s = wxT( "/" ); // This is the root path
451
452 // Start at 1 to avoid the root sheet, which does not need to be added to the path.
453 // Its timestamp changes anyway.
454 for( unsigned i = 1; i < size(); i++ )
455 s += at( i )->m_Uuid.AsString() + "/";
456
457 return s;
458}
459
460
462{
464 return m_cached_path;
465
466 m_cached_path.clear();
467 size_t size = m_sheets.size();
468
469 if( m_sheets.empty() )
470 {
471 m_cached_path_valid = true;
472 return m_cached_path;
473 }
474
475 if( m_sheets[0]->m_Uuid != niluuid )
476 {
477 m_cached_path.reserve( size );
478 m_cached_path.push_back( m_sheets[0]->m_Uuid );
479 }
480 else
481 {
482 // Skip the virtual root
483 m_cached_path.reserve( size - 1 );
484 }
485
486 for( size_t i = 1; i < size; i++ )
487 m_cached_path.push_back( m_sheets[i]->m_Uuid );
488
489 m_cached_path_valid = true;
490 return m_cached_path;
491}
492
493
494wxString SCH_SHEET_PATH::PathHumanReadable( bool aUseShortRootName,
495 bool aStripTrailingSeparator,
496 bool aEscapeSheetNames ) const
497{
498 wxString s;
499
500 // Determine the starting index - skip virtual root if present
501 size_t startIdx = 0;
502
503 if( !empty() && at( 0 )->IsVirtualRootSheet() )
504 startIdx = 1;
505
506 if( aUseShortRootName )
507 {
508 s = wxS( "/" ); // Use only the short name in netlists
509 }
510 else
511 {
512 wxString fileName;
513
514 if( size() > startIdx && at( startIdx )->GetScreen() )
515 fileName = at( startIdx )->GetScreen()->GetFileName();
516
517 wxFileName fn = fileName;
518
519 s = fn.GetName() + wxS( "/" );
520 }
521
522 // When the schematic has multiple top-level sheets, the top-level sheet
523 // belongs in the path: otherwise sibling top-level sheets collapse to the
524 // same prefix (just "/") and local labels with identical text on different
525 // top-level sheets end up sharing a net.
526 size_t loopStart = startIdx + 1;
527
528 if( aUseShortRootName && size() > startIdx )
529 {
530 SCH_SHEET* first = at( startIdx );
531 SCHEMATIC* schem = first ? first->Schematic() : nullptr;
532
533 if( schem && schem->GetTopLevelSheets().size() > 1 && first->IsTopLevelSheet() )
534 loopStart = startIdx;
535 }
536
537 for( unsigned i = loopStart; i < size(); i++ )
538 {
539 wxString sheetName = at( i )->GetField( FIELD_T::SHEET_NAME )->GetShownText( false );
540
541 if( aEscapeSheetNames )
542 sheetName = EscapeString( sheetName, CTX_NETNAME );
543
544 s << sheetName << wxS( "/" );
545 }
546
547 if( aStripTrailingSeparator && s.EndsWith( "/" ) )
548 s = s.Left( s.length() - 1 );
549
550 return s;
551}
552
553
555{
556 std::vector<SCH_ITEM*> items;
557
558 std::copy_if( LastScreen()->Items().begin(), LastScreen()->Items().end(),
559 std::back_inserter( items ),
560 []( SCH_ITEM* aItem )
561 {
562 return ( aItem->Type() == SCH_SYMBOL_T
563 || aItem->Type() == SCH_GLOBAL_LABEL_T
564 || aItem->Type() == SCH_SHAPE_T );
565 } );
566
567 for( SCH_ITEM* item : items )
568 {
569 if( item->Type() == SCH_SYMBOL_T )
570 {
571 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
572
573 // GetRef() and GetUnitSelection() are O(1) via the symbol's instance path index.
574 symbol->GetField( FIELD_T::REFERENCE )->SetText( symbol->GetRef( this ) );
575 symbol->SetUnit( symbol->GetUnitSelection( this ) );
576 LastScreen()->Update( item, false );
577 }
578 else if( item->Type() == SCH_GLOBAL_LABEL_T )
579 {
580 SCH_GLOBALLABEL* label = static_cast<SCH_GLOBALLABEL*>( item );
581
582 if( label->GetFields().size() > 0 ) // Possible when reading a legacy .sch schematic
583 {
584 SCH_FIELD* intersheetRefs = label->GetField( FIELD_T::INTERSHEET_REFS );
585
586 // Fixup for legacy files which didn't store a position for the intersheet refs
587 // unless they were shown.
588 if( intersheetRefs->GetPosition() == VECTOR2I() && !intersheetRefs->IsVisible() )
590
591 intersheetRefs->SetVisible( label->Schematic()->Settings().m_IntersheetRefsShow );
592 LastScreen()->Update( intersheetRefs );
593 }
594 }
595 else if( item->Type() == SCH_SHAPE_T )
596 {
597 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
598 shape->UpdateHatching();
599 }
600 }
601}
602
603
604static bool matchesSymbolFilter( const wxString& aReference, SYMBOL_FILTER aSymbolFilter )
605{
606 bool isPowerSymbol = !aReference.IsEmpty() && aReference[0] == wxT( '#' );
607
608 switch( aSymbolFilter )
609 {
610 case SYMBOL_FILTER_POWER: return isPowerSymbol;
611
612 case SYMBOL_FILTER_ALL: return true;
613
615 default: return !isPowerSymbol;
616 }
617}
618
619
621 bool aForceIncludeOrphanSymbols ) const
622{
623 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
624 {
625 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
626 AppendSymbol( aReferences, symbol, aSymbolFilter, aForceIncludeOrphanSymbols );
627 }
628}
629
630
632 bool aForceIncludeOrphanSymbols ) const
633{
634 // Skip pseudo-symbols, which have a reference starting with #. This mainly
635 // affects power symbols.
636 if( matchesSymbolFilter( aSymbol->GetRef( this ), aSymbolFilter ) )
637 {
638 if( aSymbol->GetLibSymbolRef() || aForceIncludeOrphanSymbols )
639 {
640 SCH_REFERENCE schReference( aSymbol, *this );
641
642 schReference.SetSheetNumber( GetPageNumberAsInt() );
643 aReferences.AddItem( schReference );
644 }
645 }
646}
647
648
650{
651 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
652 {
653 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
654 AppendMultiUnitSymbol( aRefList, symbol, aSymbolFilter );
655 }
656}
657
658
660 SYMBOL_FILTER aSymbolFilter ) const
661{
662 // Skip pseudo-symbols, which have a reference starting with #. This mainly
663 // affects power symbols.
664 if( !matchesSymbolFilter( aSymbol->GetRef( this ), aSymbolFilter ) )
665 return;
666
667 LIB_SYMBOL* symbol = aSymbol->GetLibSymbolRef().get();
668
669 if( symbol && symbol->GetUnitCount() > 1 )
670 {
671 SCH_REFERENCE schReference = SCH_REFERENCE( aSymbol, *this );
672 schReference.SetSheetNumber( GetPageNumberAsInt() );
673 wxString reference_str = schReference.GetRef();
674
675 // Never lock unassigned references
676 if( reference_str[reference_str.Len() - 1] == '?' )
677 return;
678
679 aRefList[reference_str].AddItem( schReference );
680 }
681}
682
683
685{
686 return m_current_hash == d1.GetCurrentHash();
687}
688
689
690bool SCH_SHEET_PATH::TestForRecursion( const wxString& aSrcFileName, const wxString& aDestFileName )
691{
692 auto pair = std::make_pair( aSrcFileName, aDestFileName );
693
694 if( m_recursion_test_cache.count( pair ) )
695 return m_recursion_test_cache.at( pair );
696
697 SCHEMATIC* sch = LastScreen()->Schematic();
698
699 wxCHECK_MSG( sch, false, "No SCHEMATIC found in SCH_SHEET_PATH::TestForRecursion!" );
700
701 wxFileName rootFn = sch->GetFileName();
702 wxFileName srcFn = aSrcFileName;
703 wxFileName destFn = aDestFileName;
704
705 if( srcFn.IsRelative() )
706 srcFn.MakeAbsolute( rootFn.GetPath() );
707
708 if( destFn.IsRelative() )
709 destFn.MakeAbsolute( rootFn.GetPath() );
710
711 // The source and destination sheet file names cannot be the same.
712 if( srcFn == destFn )
713 {
714 m_recursion_test_cache[pair] = true;
715 return true;
716 }
717
721 unsigned i = 0;
722
723 while( i < size() )
724 {
725 wxFileName cmpFn = at( i )->GetFileName();
726
727 if( cmpFn.IsRelative() )
728 cmpFn.MakeAbsolute( rootFn.GetPath() );
729
730 // Test if the file name of the destination sheet is in anywhere in this sheet path.
731 if( cmpFn == destFn )
732 break;
733
734 i++;
735 }
736
737 // The destination sheet file name was not found in the sheet path or the destination
738 // sheet file name is the root sheet so no recursion is possible.
739 if( i >= size() || i == 0 )
740 {
741 m_recursion_test_cache[pair] = false;
742 return false;
743 }
744
745 // Walk back up to the root sheet to see if the source file name is already a parent in
746 // the sheet path. If so, recursion will occur.
747 do
748 {
749 i -= 1;
750
751 wxFileName cmpFn = at( i )->GetFileName();
752
753 if( cmpFn.IsRelative() )
754 cmpFn.MakeAbsolute( rootFn.GetPath() );
755
756 if( cmpFn == srcFn )
757 {
758 m_recursion_test_cache[pair] = true;
759 return true;
760 }
761
762 } while( i != 0 );
763
764 // The source sheet file name is not a parent of the destination sheet file name.
765 m_recursion_test_cache[pair] = false;
766 return false;
767}
768
769
771{
772 SCH_SHEET* sheet = Last();
773
774 wxCHECK( sheet, wxEmptyString );
775
776 KIID_PATH tmpPath = Path();
777
778 if( !tmpPath.empty() )
779 tmpPath.pop_back();
780 else
781 return wxEmptyString;
782
783 return sheet->getPageNumber( tmpPath );
784}
785
787{
788 long page;
789 wxString pageStr = GetPageNumber();
790
791 if( pageStr.ToLong( &page ) )
792 return (int) page;
793
794 return GetVirtualPageNumber();
795}
796
797
798void SCH_SHEET_PATH::SetPageNumber( const wxString& aPageNumber )
799{
800 SCH_SHEET* sheet = Last();
801
802 wxCHECK( sheet, /* void */ );
803
804 KIID_PATH tmpPath = Path();
805
806 if( !tmpPath.empty() )
807 {
808 tmpPath.pop_back();
809 }
810 else
811 {
812 wxCHECK_MSG( false, /* void */, wxS( "Sheet paths must have a least one valid sheet." ) );
813 }
814
815 sheet->addInstance( tmpPath );
816 sheet->setPageNumber( tmpPath, aPageNumber );
817}
818
819
821 const wxString& aProjectName )
822{
823 wxCHECK( !aProjectName.IsEmpty(), /* void */ );
824
825 SCH_SHEET_PATH newSheetPath( aPrefixSheetPath );
826 SCH_SHEET_PATH currentSheetPath( *this );
827
828 // Prefix the new hierarchical path.
829 newSheetPath = newSheetPath + currentSheetPath;
830
831 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
832 {
833 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
834
835 wxCHECK2( symbol, continue );
836
837 SCH_SYMBOL_INSTANCE newSymbolInstance;
838
839 if( symbol->GetInstance( newSymbolInstance, Path(), true ) )
840 {
841 newSymbolInstance.m_ProjectName = aProjectName;
842
843 // Use an existing symbol instance for this path if it exists.
844 newSymbolInstance.m_Path = newSheetPath.Path();
845 symbol->AddHierarchicalReference( newSymbolInstance );
846 }
847 else if( !symbol->GetInstances().empty() )
848 {
849 newSymbolInstance.m_ProjectName = aProjectName;
850
851 // Use the first symbol instance if any symbol instance data exists.
852 newSymbolInstance = symbol->GetInstances()[0];
853 newSymbolInstance.m_Path = newSheetPath.Path();
854 symbol->AddHierarchicalReference( newSymbolInstance );
855 }
856 else
857 {
858 newSymbolInstance.m_ProjectName = aProjectName;
859
860 // Fall back to the last saved symbol field and unit settings if there is no
861 // instance data.
862 newSymbolInstance.m_Path = newSheetPath.Path();
863 newSymbolInstance.m_Reference = symbol->GetField( FIELD_T::REFERENCE )->GetText();
864 newSymbolInstance.m_Unit = symbol->GetUnit();
865 symbol->AddHierarchicalReference( newSymbolInstance );
866 }
867 }
868}
869
870
872{
873 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
874 {
875 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
876
877 wxCHECK2( symbol, continue );
878
879 SCH_SHEET_PATH fullSheetPath( aPrefixSheetPath );
880 SCH_SHEET_PATH currentSheetPath( *this );
881
882 // Prefix the hierarchical path of the symbol instance to be removed.
883 fullSheetPath = fullSheetPath + currentSheetPath;
884 symbol->RemoveInstance( fullSheetPath );
885 }
886}
887
888
889void SCH_SHEET_PATH::CheckForMissingSymbolInstances( const wxString& aProjectName )
890{
891 // Skip sheet paths without screens (e.g., sheets that haven't been loaded yet or virtual root)
892 if( aProjectName.IsEmpty() || !LastScreen() )
893 return;
894
895 wxLogTrace( traceSchSheetPaths, "CheckForMissingSymbolInstances for path: %s (project: %s)",
896 PathHumanReadable( false ), aProjectName );
897 wxLogTrace( traceSchSheetPaths, " Sheet path size=%zu, Path().AsString()='%s'",
898 size(), Path().AsString() );
899
900 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
901 {
902 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
903
904 wxCHECK2( symbol, continue );
905
906 SCH_SYMBOL_INSTANCE symbolInstance;
907
908 if( !symbol->GetInstance( symbolInstance, Path() ) )
909 {
910 wxLogTrace( traceSchSheetPaths, "Adding missing symbol \"%s\" instance data for "
911 "sheet path '%s'.",
912 symbol->m_Uuid.AsString(), PathHumanReadable( false ) );
913
914 // Legacy schematics that are not shared do not contain separate instance data.
915 // The symbol reference and unit are saved in the reference field and unit entries.
916 if( !IsSharedPath() && ( LastScreen()->GetFileFormatVersionAtLoad() <= 20200310 ) )
917 {
918 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
919 symbolInstance.m_Reference = refField->GetShownText( this, true );
920 symbolInstance.m_Unit = symbol->GetUnit();
921
922 wxLogTrace( traceSchSheetPaths,
923 " Legacy format: Using reference '%s' from field, unit %d",
924 symbolInstance.m_Reference, symbolInstance.m_Unit );
925 }
926 else if( !symbol->GetInstances().empty() )
927 {
928 // Prefer an instance from the current project; shared schematics may carry
929 // instance data for several projects. Copying the full instance carries
930 // variant DNP / value / field overrides across when v9-imported files have
931 // been re-rooted and their stored paths no longer match.
932 const std::vector<SCH_SYMBOL_INSTANCE>& instances = symbol->GetInstances();
933
934 auto sourceIt = std::find_if( instances.begin(), instances.end(),
935 [&aProjectName]( const SCH_SYMBOL_INSTANCE& aInstance )
936 {
937 return aInstance.m_ProjectName == aProjectName;
938 } );
939
940 if( sourceIt == instances.end() )
941 sourceIt = instances.begin();
942
943 symbolInstance = *sourceIt;
944
945 wxLogTrace( traceSchSheetPaths,
946 " Using available instance (project '%s'): ref=%s, unit=%d, variants=%zu",
947 sourceIt->m_ProjectName, symbolInstance.m_Reference,
948 symbolInstance.m_Unit, symbolInstance.m_Variants.size() );
949 }
950 else
951 {
952 // Fall back to the symbol's reference field and unit if no instance data exists.
953 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
954 symbolInstance.m_Reference = refField->GetText();
955 symbolInstance.m_Unit = symbol->GetUnit();
956
957 wxLogTrace( traceSchSheetPaths,
958 " No instance data: Using reference '%s' from field, unit %d",
959 symbolInstance.m_Reference, symbolInstance.m_Unit );
960 }
961
962 symbolInstance.m_ProjectName = aProjectName;
963 symbolInstance.m_Path = Path();
964 symbol->AddHierarchicalReference( symbolInstance );
965
966 wxLogTrace( traceSchSheetPaths,
967 " Created instance: ref=%s, path=%s",
968 symbolInstance.m_Reference, symbolInstance.m_Path.AsString() );
969 }
970 else
971 {
972 wxLogTrace( traceSchSheetPaths,
973 " Symbol %s already has instance: ref=%s, path=%s",
974 symbol->m_Uuid.AsString(),
975 symbolInstance.m_Reference,
976 symbolInstance.m_Path.AsString() );
977 }
978 }
979}
980
981
983{
984 wxCHECK( m_sheets.size() > 1, /* void */ );
985
986 wxFileName sheetFileName = Last()->GetFileName();
987
988 // If the sheet file name is absolute, then the user requested is so don't make it relative.
989 if( sheetFileName.IsAbsolute() )
990 return;
991
992 SCH_SCREEN* screen = LastScreen();
993 SCH_SCREEN* parentScreen = m_sheets[ m_sheets.size() - 2 ]->GetScreen();
994
995 wxCHECK( screen && parentScreen, /* void */ );
996
997 wxFileName fileName = screen->GetFileName();
998 wxFileName parentFileName = parentScreen->GetFileName();
999
1000 // SCH_SCREEN file names must be absolute. If they are not, someone set them incorrectly
1001 // on load or on creation.
1002 wxCHECK( fileName.IsAbsolute() && parentFileName.IsAbsolute(), /* void */ );
1003
1004 if( fileName.GetPath() == parentFileName.GetPath() )
1005 {
1006 Last()->SetFileName( fileName.GetFullName() );
1007 }
1008 else if( fileName.MakeRelativeTo( parentFileName.GetPath() ) )
1009 {
1010 Last()->SetFileName( fileName.GetFullPath() );
1011 }
1012 else
1013 {
1014 Last()->SetFileName( screen->GetFileName() );
1015 }
1016
1017 wxLogTrace( tracePathsAndFiles,
1018 wxT( "\n File name: '%s'"
1019 "\n parent file name '%s',"
1020 "\n sheet '%s' file name '%s'." ),
1021 screen->GetFileName(), parentScreen->GetFileName(), PathHumanReadable(),
1022 Last()->GetFileName() );
1023}
1024
1025
1027{
1028 SCH_SHEET_PATH tmp = *this;
1029
1030 while( !tmp.empty() )
1031 {
1032 wxCHECK2( tmp.LastScreen(), continue );
1033
1034 if( tmp.LastScreen()->GetRefCount() > 1 )
1035 return true;
1036
1037 tmp.pop_back();
1038 }
1039
1040 return false;
1041}
1042
1043
1045{
1046 if( aSheet != nullptr )
1047 BuildSheetList( aSheet, false );
1048}
1049
1050
1051void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity )
1052{
1053 if( !aSheet )
1054 return;
1055
1056 wxLogTrace( traceSchSheetPaths,
1057 "BuildSheetList called with sheet '%s' (UUID=%s, isVirtualRoot=%d)",
1058 aSheet->GetName(),
1059 aSheet->m_Uuid.AsString(),
1060 aSheet->m_Uuid == niluuid ? 1 : 0 );
1061
1062 // Special handling for virtual root: process its children without adding the root itself
1063 if( aSheet->IsVirtualRootSheet() )
1064 {
1065 wxLogTrace( traceSchSheetPaths, " Skipping virtual root, processing children only" );
1066
1067 if( aSheet->GetScreen() )
1068 {
1069 std::vector<SCH_ITEM*> childSheets;
1070 aSheet->GetScreen()->GetSheets( &childSheets );
1071
1072 for( SCH_ITEM* item : childSheets )
1073 {
1074 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1075 BuildSheetList( sheet, aCheckIntegrity );
1076 }
1077 }
1078
1079 return;
1080 }
1081
1082 std::vector<SCH_SHEET*> badSheets;
1083
1084 m_currentSheetPath.push_back( aSheet );
1085 m_currentSheetPath.SetVirtualPageNumber( static_cast<int>( size() ) + 1 );
1086 push_back( m_currentSheetPath );
1087
1088 if( m_currentSheetPath.LastScreen() )
1089 {
1090 wxString parentFileName = aSheet->GetFileName();
1091 std::vector<SCH_ITEM*> childSheets;
1092 m_currentSheetPath.LastScreen()->GetSheets( &childSheets );
1093
1094 for( SCH_ITEM* item : childSheets )
1095 {
1096 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1097
1098 if( aCheckIntegrity )
1099 {
1100 if( !m_currentSheetPath.TestForRecursion( sheet->GetFileName(), parentFileName ) )
1101 BuildSheetList( sheet, true );
1102 else
1103 badSheets.push_back( sheet );
1104 }
1105 else
1106 {
1107 // If we are not performing a full recursion test, at least check if we are in
1108 // a simple recursion scenario to prevent stack overflow crashes
1109 wxCHECK2_MSG( sheet->GetFileName() != aSheet->GetFileName(), continue,
1110 wxT( "Recursion prevented in SCH_SHEET_LIST::BuildSheetList" ) );
1111
1112 BuildSheetList( sheet, false );
1113 }
1114 }
1115 }
1116
1117 if( aCheckIntegrity )
1118 {
1119 for( SCH_SHEET* sheet : badSheets )
1120 {
1121 m_currentSheetPath.LastScreen()->Remove( sheet );
1122 m_currentSheetPath.LastScreen()->SetContentModified();
1123 }
1124 }
1125
1126 m_currentSheetPath.pop_back();
1127}
1128
1129
1130void SCH_SHEET_LIST::SortByHierarchicalPageNumbers( bool aUpdateVirtualPageNums )
1131{
1132 for( const SCH_SHEET_PATH& path : *this )
1133 path.CachePageNumber();
1134
1135 std::sort( begin(), end(),
1136 []( const SCH_SHEET_PATH& a, const SCH_SHEET_PATH& b ) -> bool
1137 {
1138 // Find the divergence point in the paths
1139 size_t common_len = 0;
1140 size_t min_len = std::min( a.size(), b.size() );
1141
1142 while( common_len < min_len && a.at( common_len )->m_Uuid == b.at( common_len )->m_Uuid )
1143 common_len++;
1144
1145 // If one path is a prefix of the other, the shorter one comes first
1146 // This ensures parents come before children
1147 if( common_len == a.size() )
1148 return true; // a is a prefix of b - a is the parent
1149 if( common_len == b.size() )
1150 return false; // b is a prefix of a - b is the parent
1151
1152 // Paths diverge at common_len
1153 // If they share the same parent, sort by page number
1154 // This ensures siblings are sorted by page number
1155 SCH_SHEET* sheet_a = a.at( common_len );
1156 SCH_SHEET* sheet_b = b.at( common_len );
1157
1158 // Create partial paths to get to these sheets for page number comparison
1159 KIID_PATH ancestor;
1160 for( size_t i = 0; i < common_len; i++ )
1161 ancestor.push_back( a.at( i )->m_Uuid );
1162
1163 // Compare page numbers - use the last sheet's page number
1164 wxString page_a = sheet_a->getPageNumber( ancestor );
1165 wxString page_b = sheet_b->getPageNumber( ancestor );
1166
1167 int retval = SCH_SHEET::ComparePageNum( page_a, page_b );
1168
1169 if( retval != 0 )
1170 return retval < 0;
1171
1172 // If page numbers are the same, use virtual page numbers as a tie-breaker
1174 return true;
1175 else if( a.GetVirtualPageNumber() > b.GetVirtualPageNumber() )
1176 return false;
1177
1178 // Finally, use UUIDs for stable ordering when everything else is equal
1179 return a.GetCurrentHash() < b.GetCurrentHash();
1180 } );
1181
1182 if( aUpdateVirtualPageNums )
1183 {
1184 int virtualPageNum = 1;
1185
1186 for( SCH_SHEET_PATH& sheet : *this )
1187 sheet.SetVirtualPageNumber( virtualPageNum++ );
1188 }
1189}
1190
1191
1192void SCH_SHEET_LIST::SortByPageNumbers( bool aUpdateVirtualPageNums )
1193{
1194 for( const SCH_SHEET_PATH& path : *this )
1195 path.CachePageNumber();
1196
1197 std::sort( begin(), end(),
1198 []( const SCH_SHEET_PATH& a, const SCH_SHEET_PATH& b ) -> bool
1199 {
1201 b.GetCachedPageNumber() );
1202
1203 if( retval < 0 )
1204 return true;
1205 else if( retval > 0 )
1206 return false;
1207
1209 return true;
1210 else if( a.GetVirtualPageNumber() > b.GetVirtualPageNumber() )
1211 return false;
1212
1213 // Enforce strict ordering. If the page numbers are the same, use UUIDs
1214 return a.GetCurrentHash() < b.GetCurrentHash();
1215 } );
1216
1217 if( aUpdateVirtualPageNums )
1218 {
1219 int virtualPageNum = 1;
1220
1221 for( SCH_SHEET_PATH& sheet : *this )
1222 sheet.SetVirtualPageNumber( virtualPageNum++ );
1223 }
1224}
1225
1226
1227bool SCH_SHEET_LIST::NameExists( const wxString& aSheetName ) const
1228{
1229 for( const SCH_SHEET_PATH& sheet : *this )
1230 {
1231 if( sheet.Last()->GetName() == aSheetName )
1232 return true;
1233 }
1234
1235 return false;
1236}
1237
1238
1239bool SCH_SHEET_LIST::PageNumberExists( const wxString& aPageNumber ) const
1240{
1241 for( const SCH_SHEET_PATH& sheet : *this )
1242 {
1243 if( sheet.GetPageNumber() == aPageNumber )
1244 return true;
1245 }
1246
1247 return false;
1248}
1249
1250
1251void SCH_SHEET_LIST::TrimToPageNumbers( const std::vector<wxString>& aPageInclusions )
1252{
1253 auto it = std::remove_if( begin(), end(),
1254 [&]( const SCH_SHEET_PATH& sheet )
1255 {
1256 return std::find( aPageInclusions.begin(),
1257 aPageInclusions.end(),
1258 sheet.GetPageNumber() ) == aPageInclusions.end();
1259 } );
1260
1261 erase( it, end() );
1262}
1263
1264
1266{
1267 wxString pageNumber;
1268
1269 // Find the next available page number by checking all existing page numbers
1270 std::set<int> usedPageNumbers;
1271
1272 for( const SCH_SHEET_PATH& path : *this )
1273 {
1274 wxString existingPageNum = path.GetPageNumber();
1275 long pageNum = 0;
1276
1277 if( existingPageNum.ToLong( &pageNum ) && pageNum > 0 )
1278 usedPageNumbers.insert( static_cast<int>( pageNum ) );
1279 }
1280
1281 // Find the first available number starting from 1
1282 int nextAvailable = 1;
1283
1284 while( usedPageNumbers.count( nextAvailable ) > 0 )
1285 nextAvailable++;
1286
1287 pageNumber.Printf( wxT( "%d" ), nextAvailable );
1288 return pageNumber;
1289}
1290
1291
1293{
1294 for( const SCH_SHEET_PATH& sheet : *this )
1295 {
1296 if( sheet.LastScreen() && sheet.LastScreen()->IsContentModified() )
1297 return true;
1298 }
1299
1300 return false;
1301}
1302
1303
1305{
1306 for( const SCH_SHEET_PATH& sheet : *this )
1307 {
1308 if( sheet.LastScreen() )
1309 sheet.LastScreen()->SetContentModified( false );
1310 }
1311}
1312
1313
1314SCH_ITEM* SCH_SHEET_LIST::ResolveItem( const KIID& aID, SCH_SHEET_PATH* aPathOut, bool aAllowNullptrReturn ) const
1315{
1316 for( const SCH_SHEET_PATH& sheet : *this )
1317 {
1318 SCH_ITEM* item = sheet.ResolveItem( aID );
1319
1320 if( item )
1321 {
1322 if( aPathOut )
1323 *aPathOut = sheet;
1324
1325 return item;
1326 }
1327 }
1328
1329 // Not found; weak reference has been deleted.
1330 if( aAllowNullptrReturn )
1331 return nullptr;
1332 else
1334}
1335
1336
1338{
1339 for( SCH_ITEM* aItem : LastScreen()->Items() )
1340 {
1341 if( aItem->m_Uuid == aID )
1342 return aItem;
1343
1344 SCH_ITEM* childMatch = nullptr;
1345
1346 aItem->RunOnChildren(
1347 [&]( SCH_ITEM* aChild )
1348 {
1349 if( aChild->m_Uuid == aID )
1350 childMatch = aChild;
1351 },
1353
1354 if( childMatch )
1355 return childMatch;
1356 }
1357
1358 return nullptr;
1359}
1360
1361
1362void SCH_SHEET_LIST::FillItemMap( std::map<KIID, EDA_ITEM*>& aMap )
1363{
1364 for( const SCH_SHEET_PATH& sheet : *this )
1365 {
1366 SCH_SCREEN* screen = sheet.LastScreen();
1367
1368 for( SCH_ITEM* aItem : screen->Items() )
1369 {
1370 aMap[ aItem->m_Uuid ] = aItem;
1371
1372 aItem->RunOnChildren(
1373 [&]( SCH_ITEM* aChild )
1374 {
1375 aMap[ aChild->m_Uuid ] = aChild;
1376 },
1378 }
1379 }
1380}
1381
1382
1384{
1385 // List of reference for power symbols
1386 SCH_REFERENCE_LIST references;
1387
1388 // Map of locked symbols (not used, but needed by Annotate()
1389 SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
1390
1391 // Build the list of power symbols:
1392 for( SCH_SHEET_PATH& sheet : *this )
1393 {
1394 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
1395 {
1396 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1397 LIB_SYMBOL* libSymbol = symbol->GetLibSymbolRef().get();
1398
1399 if( libSymbol && libSymbol->IsPower() )
1400 {
1401 SCH_REFERENCE schReference( symbol, sheet );
1402 references.AddItem( schReference );
1403 }
1404 }
1405 }
1406
1407 // Find duplicate, and silently clear annotation of duplicate
1408 std::map<wxString, int> ref_list; // stores the existing references
1409
1410 for( unsigned ii = 0; ii< references.GetCount(); ++ii )
1411 {
1412 wxString curr_ref = references[ii].GetRef();
1413
1414 if( curr_ref.IsEmpty() )
1415 continue;
1416
1417 if( ref_list.find( curr_ref ) == ref_list.end() )
1418 {
1419 ref_list[curr_ref] = ii;
1420 continue;
1421 }
1422
1423 // Possible duplicate, if the ref ends by a number:
1424 if( curr_ref.Last() < '0' && curr_ref.Last() > '9' )
1425 continue; // not annotated
1426
1427 // Duplicate: clear annotation by removing the number ending the ref
1428 while( !curr_ref.IsEmpty() && curr_ref.Last() >= '0' && curr_ref.Last() <= '9' )
1429 curr_ref.RemoveLast();
1430
1431 references[ii].SetRef( curr_ref );
1432 }
1433
1434 // Break full symbol reference into name (prefix) and number:
1435 // example: IC1 become IC, and 1
1436 references.SplitReferences();
1437
1438 // Ensure all power symbols have the reference starting by '#'
1439 // (Not sure this is really useful)
1440 for( unsigned ii = 0; ii< references.GetCount(); ++ii )
1441 {
1442 SCH_REFERENCE& ref_unit = references[ii];
1443
1444 if( ref_unit.GetRef()[0] != '#' )
1445 {
1446 wxString new_ref = "#" + ref_unit.GetRef();
1447 ref_unit.SetRef( new_ref );
1448 ref_unit.SetRefNum( ii );
1449 }
1450 }
1451}
1452
1453
1455 bool aForceIncludeOrphanSymbols ) const
1456{
1457 for( const SCH_SHEET_PATH& sheet : *this )
1458 sheet.GetSymbols( aReferences, aSymbolFilter, aForceIncludeOrphanSymbols );
1459}
1460
1461
1463 SYMBOL_FILTER aSymbolFilter, bool aForceIncludeOrphanSymbols ) const
1464{
1465 for( const SCH_SHEET_PATH& sheet : *this )
1466 {
1467 if( sheet.IsContainedWithin( aSheetPath ) )
1468 sheet.GetSymbols( aReferences, aSymbolFilter, aForceIncludeOrphanSymbols );
1469 }
1470}
1471
1472
1473void SCH_SHEET_LIST::GetSheetsWithinPath( std::vector<SCH_SHEET_PATH>& aSheets,
1474 const SCH_SHEET_PATH& aSheetPath ) const
1475{
1476 for( const SCH_SHEET_PATH& sheet : *this )
1477 {
1478 if( sheet.IsContainedWithin( aSheetPath ) )
1479 aSheets.push_back( sheet );
1480 }
1481}
1482
1483
1484std::optional<SCH_SHEET_PATH> SCH_SHEET_LIST::GetSheetPathByKIIDPath( const KIID_PATH& aPath,
1485 bool aIncludeLastSheet ) const
1486{
1487 for( const SCH_SHEET_PATH& sheet : *this )
1488 {
1489 KIID_PATH testPath = sheet.Path();
1490
1491 if( !aIncludeLastSheet )
1492 testPath.pop_back();
1493
1494 if( testPath == aPath )
1495 return SCH_SHEET_PATH( sheet );
1496 }
1497
1498 return std::nullopt;
1499}
1500
1501
1503{
1504 for( auto it = begin(); it != end(); ++it )
1505 {
1507 ( *it ).GetMultiUnitSymbols( tempMap, aSymbolFilter );
1508
1509 for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : tempMap )
1510 {
1511 // Merge this list into the main one
1512 unsigned n_refs = pair.second.GetCount();
1513
1514 for( unsigned thisRef = 0; thisRef < n_refs; ++thisRef )
1515 aRefList[pair.first].AddItem( pair.second[thisRef] );
1516 }
1517 }
1518}
1519
1520
1521bool SCH_SHEET_LIST::TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy,
1522 const wxString& aDestFileName )
1523{
1524 if( empty() )
1525 return false;
1526
1527 SCHEMATIC* sch = at( 0 ).LastScreen()->Schematic();
1528
1529 wxCHECK_MSG( sch, false, "No SCHEMATIC found in SCH_SHEET_LIST::TestForRecursion!" );
1530
1531 wxFileName rootFn = sch->GetFileName();
1532 wxFileName destFn = aDestFileName;
1533
1534 if( destFn.IsRelative() )
1535 destFn.MakeAbsolute( rootFn.GetPath() );
1536
1537 // Test each SCH_SHEET_PATH in this SCH_SHEET_LIST for potential recursion.
1538 for( unsigned i = 0; i < size(); i++ )
1539 {
1540 // Test each SCH_SHEET_PATH in the source sheet.
1541 for( unsigned j = 0; j < aSrcSheetHierarchy.size(); j++ )
1542 {
1543 const SCH_SHEET_PATH* sheetPath = &aSrcSheetHierarchy[j];
1544
1545 for( unsigned k = 0; k < sheetPath->size(); k++ )
1546 {
1547 if( at( i ).TestForRecursion( sheetPath->GetSheet( k )->GetFileName(),
1548 aDestFileName ) )
1549 {
1550 return true;
1551 }
1552 }
1553 }
1554 }
1555
1556 // The source sheet file can safely be added to the destination sheet file.
1557 return false;
1558}
1559
1560
1562{
1563 for( SCH_SHEET_PATH& path : *this )
1564 {
1565 if( path.Path() == aPath->Path() )
1566 return &path;
1567 }
1568
1569 return nullptr;
1570}
1571
1572
1574{
1575 for( SCH_SHEET_PATH& sheetpath : *this )
1576 {
1577 if( sheetpath.LastScreen() == aScreen )
1578 return sheetpath;
1579 }
1580
1581 return SCH_SHEET_PATH();
1582}
1583
1584
1586{
1587 SCH_SHEET_LIST retval;
1588
1589 for( const SCH_SHEET_PATH& sheetpath : *this )
1590 {
1591 if( sheetpath.LastScreen() == aScreen )
1592 retval.push_back( sheetpath );
1593 }
1594
1595 return retval;
1596}
1597
1598
1600 const std::vector<SCH_SYMBOL_INSTANCE>& aSymbolInstances )
1601{
1602 for( SCH_SHEET_PATH& sheetPath : *this )
1603 {
1604 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
1605 {
1606 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1607
1608 wxCHECK2( symbol, continue );
1609
1610 KIID_PATH sheetPathWithSymbolUuid = sheetPath.Path();
1611 sheetPathWithSymbolUuid.push_back( symbol->m_Uuid );
1612
1613 auto it = std::find_if( aSymbolInstances.begin(), aSymbolInstances.end(),
1614 [ sheetPathWithSymbolUuid ]( const SCH_SYMBOL_INSTANCE& r ) -> bool
1615 {
1616 return sheetPathWithSymbolUuid == r.m_Path;
1617 } );
1618
1619 if( it == aSymbolInstances.end() )
1620 {
1621 wxLogTrace( traceSchSheetPaths, "No symbol instance found for symbol '%s'",
1622 sheetPathWithSymbolUuid.AsString() );
1623 continue;
1624 }
1625
1626 // Symbol instance paths are stored and looked up in memory with the root path so use
1627 // the full path here.
1628 symbol->AddHierarchicalReference( sheetPath.Path(), it->m_Reference, it->m_Unit );
1629 symbol->GetField( FIELD_T::REFERENCE )->SetText( it->m_Reference );
1630
1631 if( !it->m_Value.IsEmpty() )
1632 symbol->SetValueFieldText( it->m_Value );
1633
1634 if( !it->m_Footprint.IsEmpty() )
1635 symbol->SetFootprintFieldText( it->m_Footprint );
1636
1637 symbol->UpdatePrefix();
1638 }
1639 }
1640}
1641
1642
1643void SCH_SHEET_LIST::UpdateSheetInstanceData( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances )
1644{
1645
1646 for( SCH_SHEET_PATH& path : *this )
1647 {
1648 SCH_SHEET* sheet = path.Last();
1649
1650 wxCHECK2( sheet && path.Last(), continue );
1651
1652 auto it = std::find_if( aSheetInstances.begin(), aSheetInstances.end(),
1653 [&path]( const SCH_SHEET_INSTANCE& r ) -> bool
1654 {
1655 return path.Path() == r.m_Path;
1656 } );
1657
1658 if( it == aSheetInstances.end() )
1659 {
1660 wxLogTrace( traceSchSheetPaths, "No sheet instance found for path '%s'",
1661 path.Path().AsString() );
1662 continue;
1663 }
1664
1665 wxLogTrace( traceSchSheetPaths, "Setting sheet '%s' instance '%s' page number '%s'",
1666 ( sheet->GetName().IsEmpty() ) ? wxString( wxT( "root" ) ) : sheet->GetName(),
1667 path.Path().AsString(), it->m_PageNumber );
1668 path.SetPageNumber( it->m_PageNumber );
1669 }
1670}
1671
1672
1673std::vector<KIID_PATH> SCH_SHEET_LIST::GetPaths() const
1674{
1675 std::vector<KIID_PATH> paths;
1676
1677 for( const SCH_SHEET_PATH& sheetPath : *this )
1678 paths.emplace_back( sheetPath.Path() );
1679
1680 return paths;
1681}
1682
1683
1684std::vector<SCH_SHEET_INSTANCE> SCH_SHEET_LIST::GetSheetInstances() const
1685{
1686 std::vector<SCH_SHEET_INSTANCE> retval;
1687
1688 for( const SCH_SHEET_PATH& path : *this )
1689 {
1690 const SCH_SHEET* sheet = path.Last();
1691
1692 wxCHECK2( sheet, continue );
1693
1694 SCH_SHEET_INSTANCE instance;
1695 SCH_SHEET_PATH tmpPath = path;
1696
1697 tmpPath.pop_back();
1698 instance.m_Path = tmpPath.Path();
1699 instance.m_PageNumber = path.GetPageNumber();
1700
1701 retval.push_back( std::move( instance ) );
1702 }
1703
1704 return retval;
1705}
1706
1707
1709{
1710 for( const SCH_SHEET_PATH& instance : *this )
1711 {
1712 if( !instance.GetPageNumber().IsEmpty() )
1713 return false;
1714 }
1715
1716 return true;
1717}
1718
1719
1721{
1722 // Don't accidentally renumber existing sheets.
1723 wxCHECK( AllSheetPageNumbersEmpty(), /* void */ );
1724
1725 wxString tmp;
1726 int pageNumber = 1;
1727
1728 for( SCH_SHEET_PATH& instance : *this )
1729 {
1730 if( instance.Last()->IsVirtualRootSheet() )
1731 continue;
1732
1733 tmp.Printf( "%d", pageNumber );
1734 instance.SetPageNumber( tmp );
1735 pageNumber += 1;
1736 }
1737}
1738
1739
1741{
1742 // A page number is claimed by the first sheet in the list that uses it. Any sheet with an
1743 // empty page number, or one repeating a number an earlier sheet already claimed, is reassigned
1744 // to the lowest unused positive integer. The stored string is compared as-is, so custom
1745 // schemes (e.g. "A", "1.1") are preserved when unique. Every distinct existing page number is
1746 // reserved up front so a reassignment never steals a number a later, non-conflicting sheet
1747 // already holds.
1748 std::set<wxString> reservedPageIds;
1749
1750 for( const SCH_SHEET_PATH& instance : *this )
1751 {
1752 if( instance.Last()->IsVirtualRootSheet() )
1753 continue;
1754
1755 const wxString pageNumber = instance.GetPageNumber();
1756
1757 if( !pageNumber.IsEmpty() )
1758 reservedPageIds.insert( pageNumber );
1759 }
1760
1761 std::set<wxString> assignedPageIds;
1762 bool modified = false;
1763 long nextPage = 1;
1764
1765 for( SCH_SHEET_PATH& instance : *this )
1766 {
1767 if( instance.Last()->IsVirtualRootSheet() )
1768 continue;
1769
1770 const wxString pageNumber = instance.GetPageNumber();
1771
1772 // Keep the first sheet to claim a given page number.
1773 if( !pageNumber.IsEmpty() && assignedPageIds.insert( pageNumber ).second )
1774 continue;
1775
1776 wxString pageStr = wxString::Format( wxT( "%ld" ), nextPage );
1777
1778 while( reservedPageIds.count( pageStr ) || assignedPageIds.count( pageStr ) )
1779 {
1780 nextPage++;
1781 pageStr = wxString::Format( wxT( "%ld" ), nextPage );
1782 }
1783
1784 instance.SetPageNumber( pageStr );
1785 assignedPageIds.insert( pageStr );
1786 nextPage++;
1787 modified = true;
1788 }
1789
1790 return modified;
1791}
1792
1793
1795 const wxString& aProjectName )
1796{
1797 for( SCH_SHEET_PATH& sheetPath : *this )
1798 sheetPath.AddNewSymbolInstances( aPrefixSheetPath, aProjectName );
1799}
1800
1801
1803{
1804 for( SCH_SHEET_PATH& sheetPath : *this )
1805 sheetPath.RemoveSymbolInstances( aPrefixSheetPath );
1806}
1807
1808
1810 int aLastVirtualPageNumber )
1811{
1812 wxString pageNumber;
1813 int lastUsedPageNumber = 1;
1814 int nextVirtualPageNumber = aLastVirtualPageNumber;
1815
1816 // Fetch the list of page numbers already in use.
1817 std::vector< wxString > usedPageNumbers;
1818
1819 if( aPrefixSheetPath.size() )
1820 {
1821 SCH_SHEET_LIST prefixHierarchy( aPrefixSheetPath.at( 0 ) );
1822
1823 for( const SCH_SHEET_PATH& path : prefixHierarchy )
1824 {
1825 pageNumber = path.GetPageNumber();
1826
1827 if( !pageNumber.IsEmpty() )
1828 usedPageNumbers.emplace_back( pageNumber );
1829 }
1830 }
1831
1832 for( SCH_SHEET_PATH& sheetPath : *this )
1833 {
1834 KIID_PATH tmp = sheetPath.Path();
1835 SCH_SHEET_PATH newSheetPath( aPrefixSheetPath );
1836
1837 // Prefix the new hierarchical path.
1838 newSheetPath = newSheetPath + sheetPath;
1839
1840 // Sheets cannot have themselves in the path.
1841 tmp.pop_back();
1842
1843 SCH_SHEET* sheet = sheetPath.Last();
1844
1845 wxCHECK2( sheet, continue );
1846
1847 nextVirtualPageNumber += 1;
1848
1849 SCH_SHEET_INSTANCE instance;
1850
1851 // Add the instance if it doesn't already exist
1852 if( !sheet->getInstance( instance, tmp, true ) )
1853 {
1854 sheet->addInstance( tmp );
1855 sheet->getInstance( instance, tmp, true );
1856 }
1857
1858 // Get a new page number if we don't have one
1859 if( instance.m_PageNumber.IsEmpty() )
1860 {
1861 // Generate the next available page number.
1862 do
1863 {
1864 pageNumber.Printf( wxT( "%d" ), lastUsedPageNumber );
1865 lastUsedPageNumber += 1;
1866 } while( std::find( usedPageNumbers.begin(), usedPageNumbers.end(), pageNumber ) !=
1867 usedPageNumbers.end() );
1868
1869 instance.m_PageNumber = pageNumber;
1870 newSheetPath.SetVirtualPageNumber( nextVirtualPageNumber );
1871 }
1872
1873 newSheetPath.SetPageNumber( instance.m_PageNumber );
1874 usedPageNumbers.push_back( instance.m_PageNumber );
1875 }
1876}
1877
1878
1879void SCH_SHEET_LIST::CheckForMissingSymbolInstances( const wxString& aProjectName )
1880{
1881 wxLogTrace( traceSchSheetPaths,
1882 "SCH_SHEET_LIST::CheckForMissingSymbolInstances: Processing %zu sheet paths",
1883 size() );
1884
1885 for( SCH_SHEET_PATH& sheetPath : *this )
1886 {
1887 wxLogTrace( traceSchSheetPaths,
1888 " Processing sheet path: '%s' (size=%zu, KIID_PATH='%s')",
1889 sheetPath.PathHumanReadable( false ),
1890 sheetPath.size(),
1891 sheetPath.Path().AsString() );
1892 sheetPath.CheckForMissingSymbolInstances( aProjectName );
1893 }
1894}
1895
1896
1898{
1899 int lastVirtualPageNumber = 1;
1900
1901 for( const SCH_SHEET_PATH& sheetPath : *this )
1902 {
1903 if( sheetPath.GetVirtualPageNumber() > lastVirtualPageNumber )
1904 lastVirtualPageNumber = sheetPath.GetVirtualPageNumber();
1905 }
1906
1907 return lastVirtualPageNumber;
1908}
1909
1910
1911bool SCH_SHEET_LIST::HasPath( const KIID_PATH& aPath ) const
1912{
1913 for( const SCH_SHEET_PATH& path : *this )
1914 {
1915 if( path.Path() == aPath )
1916 return true;
1917 }
1918
1919 return false;
1920}
1921
1922
1923bool SCH_SHEET_LIST::ContainsSheet( const SCH_SHEET* aSheet ) const
1924{
1925 for( const SCH_SHEET_PATH& path : *this )
1926 {
1927 for( size_t i = 0; i < path.size(); i++ )
1928 {
1929 if( path.at( i ) == aSheet )
1930 return true;
1931 }
1932 }
1933
1934 return false;
1935}
1936
1937
1938std::optional<SCH_SHEET_PATH> SCH_SHEET_LIST::GetOrdinalPath( const SCH_SCREEN* aScreen ) const
1939{
1940 // Sheet paths with sheets that do not have a screen object are not valid.
1941 if( !aScreen )
1942 return std::nullopt;
1943
1944 for( const SCH_SHEET_PATH& path: *this )
1945 {
1946 if( path.LastScreen() == aScreen )
1947 return std::optional<SCH_SHEET_PATH>( path );
1948 }
1949
1950 return std::nullopt;
1951}
bool IsContentModified() const
Definition base_screen.h:56
void SetContentModified(bool aModified=true)
Definition base_screen.h:55
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:531
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
virtual void UpdateHatching() const
virtual bool IsVisible() const
Definition eda_text.h:208
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:381
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:221
wxString AsString() const
Definition kiid.cpp:423
Definition kiid.h:46
wxString AsString() const
Definition kiid.cpp:264
Define a library symbol object.
Definition lib_symbol.h:114
bool IsPower() const override
int GetUnitCount() const override
Holds all the data relating to one schematic.
Definition schematic.h:90
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
SCHEMATIC_SETTINGS & Settings() const
std::vector< SCH_SHEET * > GetTopLevelSheets() const
Get the list of top-level sheets.
VECTOR2I GetPosition() const override
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:128
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:162
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode)
Definition sch_item.h:628
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:268
int GetUnit() const
Definition sch_item.h:233
virtual void SetUnit(int aUnit)
Definition sch_item.h:232
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:52
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
std::vector< SCH_FIELD > & GetFields()
Definition sch_label.h:210
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:115
const wxString & GetFileName() const
Definition sch_screen.h:150
SCHEMATIC * Schematic() const
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
int GetRefCount() const
Definition sch_screen.h:168
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.
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
void GetSymbolsWithinPath(SCH_REFERENCE_LIST &aReferences, const SCH_SHEET_PATH &aSheetPath, SYMBOL_FILTER aSymbolFilter, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets that are contained wi...
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.
wxString GetNextPageNumber() const
bool AllSheetPageNumbersEmpty() const
Check all of the sheet instance for empty page numbers.
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)
void GetMultiUnitSymbols(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, SYMBOL_FILTER aSymbolFilter) const
Add a SCH_REFERENCE_LIST object to aRefList for each same-reference set of multi-unit parts in the li...
bool ContainsSheet(const SCH_SHEET *aSheet) const
bool RepairPageNumbers()
Assign valid page numbers to sheet paths whose stored page number is missing or collides with an earl...
std::vector< KIID_PATH > GetPaths() const
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...
void GetSymbols(SCH_REFERENCE_LIST &aReferences, SYMBOL_FILTER aSymbolFilter, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets.
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...
void AppendSymbol(SCH_REFERENCE_LIST &aReferences, SCH_SYMBOL *aSymbol, SYMBOL_FILTER aSymbolFilter, bool aForceIncludeOrphanSymbols=false) const
Append a SCH_REFERENCE object to aReferences based on aSymbol.
bool IsSharedPath() const
Determine if this sheet path is shared in a complex hierarchy.
bool GetExcludedFromBOM() const
KIID_PATH m_cached_path
const SCH_SHEET * GetSheet(unsigned aIndex) const
bool empty() const
Forwarded method from std::vector.
int ComparePageNum(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare sheets by their page number.
size_t GetCurrentHash() const
void GetMultiUnitSymbols(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, SYMBOL_FILTER aSymbolFilter) const
Add a SCH_REFERENCE_LIST object to aRefList for each same-reference set of multi-unit parts in the sh...
void GetSymbols(SCH_REFERENCE_LIST &aReferences, SYMBOL_FILTER aSymbolFilter, bool aForceIncludeOrphanSymbols=false) const
Adds SCH_REFERENCE object to aReferences for each symbol in the sheet.
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 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.
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.
void AppendMultiUnitSymbol(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, SCH_SYMBOL *aSymbol, SYMBOL_FILTER aSymbolFilter) const
Append a SCH_REFERENCE_LIST object to aRefList based on aSymbol, storing same-reference set of multi-...
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)
bool HasDifferentials(const SCH_SHEET &aSheet) const
Return true if the variant carries any differential against the base sheet values.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:376
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:370
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.
bool IsTopLevelSheet() const
Check if this sheet is a top-level sheet.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
wxString GetName() const
Definition sch_sheet.h:136
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:139
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:461
PIN_MAP_INSTANCE_OVERRIDE m_PinMapOverride
Per-instance pin-to-pad map override for this variant (issue #2282).
std::optional< LIB_ID > m_SymbolOverride
Alternate library symbol to substitute for the base symbol in this variant, if any.
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
bool HasDifferentials(const SCH_SYMBOL &aSymbol) const
Return true if the variant carries any differential against the base symbol values,...
Schematic symbol object.
Definition sch_symbol.h:69
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:128
void RemoveInstance(const SCH_SHEET_PATH &aInstancePath)
PIN_MAP_INSTANCE_OVERRIDE GetPinMapOverride(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
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:177
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
std::map< wxString, wxString > m_Fields
bool m_ExcludedFromPosFiles
bool m_ExcludedFromSim
bool m_ExcludedFromBoard
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
@ NO_RECURSE
Definition eda_item.h:50
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:28
KIID niluuid(0)
STL namespace.
Collection of utility functions for component reference designators (refdes)
@ AUTOPLACE_AUTO
Definition sch_item.h:67
static bool matchesSymbolFilter(const wxString &aReference, SYMBOL_FILTER aSymbolFilter)
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.
SYMBOL_FILTER
@ SYMBOL_FILTER_NON_POWER
@ SYMBOL_FILTER_ALL
@ SYMBOL_FILTER_POWER
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.
std::map< wxString, SCH_SYMBOL_VARIANT > m_Variants
A list of symbol variants.
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:169
@ SCH_SHAPE_T
Definition typeinfo.h:146
@ NOT_USED
the 3d code uses this value
Definition typeinfo.h:72
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:165
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683