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 <symbol_library.h>
33#include <sch_sheet_path.h>
34#include <sch_symbol.h>
35#include <sch_sheet.h>
36#include <schematic.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
100{
101 m_DNP = aSymbol.GetDNP();
104}
105
106
107namespace std
108{
110 {
111 return path.GetCurrentHash();
112 }
113}
114
115
121
122
124{
125 initFromOther( aOther );
126}
127
128
130{
131 initFromOther( aOther );
132 return *this;
133}
134
135
136// Move assignment operator
138{
139 m_sheets = std::move( aOther.m_sheets );
140
141 m_virtualPageNumber = aOther.m_virtualPageNumber;
142 m_current_hash = aOther.m_current_hash;
143 m_cached_page_number = aOther.m_cached_page_number;
144
145 m_recursion_test_cache = std::move( aOther.m_recursion_test_cache );
146
147 return *this;
148}
149
150
152{
153 SCH_SHEET_PATH retv = *this;
154
155 size_t size = aOther.size();
156
157 for( size_t i = 0; i < size; i++ )
158 retv.push_back( aOther.at( i ) );
159
160 return retv;
161}
162
163
165{
166 m_sheets = aOther.m_sheets;
170
171 // Note: don't copy m_recursion_test_cache as it is slow and we want std::vector<SCH_SHEET_PATH>
172 // to be very fast to construct for use in the connectivity algorithm.
174}
175
176
178{
179 // The root sheet path is empty. All other sheet paths must start with the root sheet path.
180 return ( m_sheets.size() == 0 ) || ( GetSheet( 0 )->IsRootSheet() );
181}
182
183
185{
186 m_current_hash = 0;
187
188 for( SCH_SHEET* sheet : m_sheets )
189 hash_combine( m_current_hash, sheet->m_Uuid.Hash() );
190}
191
192
193int SCH_SHEET_PATH::Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const
194{
195 if( size() > aSheetPathToTest.size() )
196 return 1;
197
198 if( size() < aSheetPathToTest.size() )
199 return -1;
200
201 // otherwise, same number of sheets.
202 for( unsigned i = 0; i < size(); i++ )
203 {
204 if( at( i )->m_Uuid < aSheetPathToTest.at( i )->m_Uuid )
205 return -1;
206
207 if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
208 return 1;
209 }
210
211 return 0;
212}
213
214
215int SCH_SHEET_PATH::ComparePageNum( const SCH_SHEET_PATH& aSheetPathToTest ) const
216{
217 wxString pageA = this->GetPageNumber();
218 wxString pageB = aSheetPathToTest.GetPageNumber();
219
220 int pageNumComp = SCH_SHEET::ComparePageNum( pageA, pageB );
221
222 if( pageNumComp == 0 )
223 {
224 int virtualPageA = GetVirtualPageNumber();
225 int virtualPageB = aSheetPathToTest.GetVirtualPageNumber();
226
227 if( virtualPageA > virtualPageB )
228 pageNumComp = 1;
229 else if( virtualPageA < virtualPageB )
230 pageNumComp = -1;
231 }
232
233 return pageNumComp;
234}
235
236
237bool SCH_SHEET_PATH::IsContainedWithin( const SCH_SHEET_PATH& aSheetPathToTest ) const
238{
239 if( aSheetPathToTest.size() > size() )
240 return false;
241
242 for( size_t i = 0; i < aSheetPathToTest.size(); ++i )
243 {
244 if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
245 {
246 wxLogTrace( traceSchSheetPaths, "Sheet path '%s' is not within path '%s'.",
247 aSheetPathToTest.Path().AsString(), Path().AsString() );
248
249 return false;
250 }
251 }
252
253 wxLogTrace( traceSchSheetPaths, "Sheet path '%s' is within path '%s'.",
254 aSheetPathToTest.Path().AsString(), Path().AsString() );
255
256 return true;
257}
258
259
261{
262 if( !empty() )
263 return m_sheets.back();
264
265 return nullptr;
266}
267
268
270{
271 SCH_SHEET* lastSheet = Last();
272
273 if( lastSheet )
274 return lastSheet->GetScreen();
275
276 return nullptr;
277}
278
279
281{
282 SCH_SHEET* lastSheet = Last();
283
284 if( lastSheet )
285 return lastSheet->GetScreen();
286
287 return nullptr;
288}
289
290
292{
293 for( SCH_SHEET* sheet : m_sheets )
294 {
295 if( sheet->GetExcludedFromSim() )
296 return true;
297 }
298
299 return false;
300}
301
302
304{
305 for( SCH_SHEET* sheet : m_sheets )
306 {
307 if( sheet->GetExcludedFromBOM() )
308 return true;
309 }
310
311 return false;
312}
313
314
316{
317 for( SCH_SHEET* sheet : m_sheets )
318 {
319 if( sheet->GetExcludedFromBoard() )
320 return true;
321 }
322
323 return false;
324}
325
326
328{
329 for( SCH_SHEET* sheet : m_sheets )
330 {
331 if( sheet->GetDNP() )
332 return true;
333 }
334
335 return false;
336}
337
338
340{
341 wxString s;
342
343 s = wxT( "/" ); // This is the root path
344
345 // Start at 1 to avoid the root sheet, which does not need to be added to the path.
346 // Its timestamp changes anyway.
347 for( unsigned i = 1; i < size(); i++ )
348 s += at( i )->m_Uuid.AsString() + "/";
349
350 return s;
351}
352
353
355{
357 path.reserve( m_sheets.size() );
358
359 for( const SCH_SHEET* sheet : m_sheets )
360 path.push_back( sheet->m_Uuid );
361
362 return path;
363}
364
365
366wxString SCH_SHEET_PATH::PathHumanReadable( bool aUseShortRootName,
367 bool aStripTrailingSeparator ) const
368{
369 wxString s;
370
371 if( aUseShortRootName )
372 {
373 s = wxS( "/" ); // Use only the short name in netlists
374 }
375 else
376 {
377 wxString fileName;
378
379 if( !empty() && at( 0 )->GetScreen() )
380 fileName = at( 0 )->GetScreen()->GetFileName();
381
382 wxFileName fn = fileName;
383
384 s = fn.GetName() + wxS( "/" );
385 }
386
387 // Start at 1 since we've already processed the root sheet.
388 for( unsigned i = 1; i < size(); i++ )
389 s << at( i )->GetField( FIELD_T::SHEET_NAME )->GetShownText( false ) << wxS( "/" );
390
391 if( aStripTrailingSeparator && s.EndsWith( "/" ) )
392 s = s.Left( s.length() - 1 );
393
394 return s;
395}
396
397
399{
400 std::vector<SCH_ITEM*> items;
401
402 std::copy_if( LastScreen()->Items().begin(), LastScreen()->Items().end(),
403 std::back_inserter( items ),
404 []( SCH_ITEM* aItem )
405 {
406 return ( aItem->Type() == SCH_SYMBOL_T
407 || aItem->Type() == SCH_GLOBAL_LABEL_T
408 || aItem->Type() == SCH_SHAPE_T );
409 } );
410
411 std::optional<wxString> variantName;
412 const SCHEMATIC* schematic = LastScreen()->Schematic();
413
414 if( schematic )
415 variantName = schematic->GetCurrentVariant();
416
417 for( SCH_ITEM* item : items )
418 {
419 if( item->Type() == SCH_SYMBOL_T )
420 {
421 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
422
423 symbol->GetField( FIELD_T::REFERENCE )->SetText( symbol->GetRef( this ) );
424 symbol->SetUnit( symbol->GetUnitSelection( this ) );
425 LastScreen()->Update( item, false );
426 }
427 else if( item->Type() == SCH_GLOBAL_LABEL_T )
428 {
429 SCH_GLOBALLABEL* label = static_cast<SCH_GLOBALLABEL*>( item );
430
431 if( label->GetFields().size() > 0 ) // Possible when reading a legacy .sch schematic
432 {
433 SCH_FIELD* intersheetRefs = label->GetField( FIELD_T::INTERSHEET_REFS );
434
435 // Fixup for legacy files which didn't store a position for the intersheet refs
436 // unless they were shown.
437 if( intersheetRefs->GetPosition() == VECTOR2I() && !intersheetRefs->IsVisible() )
439
440 intersheetRefs->SetVisible( label->Schematic()->Settings().m_IntersheetRefsShow );
441 LastScreen()->Update( intersheetRefs );
442 }
443 }
444 else if( item->Type() == SCH_SHAPE_T )
445 {
446 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
447 shape->UpdateHatching();
448 }
449 }
450}
451
452
453void SCH_SHEET_PATH::GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols,
454 bool aForceIncludeOrphanSymbols ) const
455{
456 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
457 {
458 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
459 AppendSymbol( aReferences, symbol, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
460 }
461}
462
463
465 bool aIncludePowerSymbols,
466 bool aForceIncludeOrphanSymbols ) const
467{
468 // Skip pseudo-symbols, which have a reference starting with #. This mainly
469 // affects power symbols.
470 if( aIncludePowerSymbols || aSymbol->GetRef( this )[0] != wxT( '#' ) )
471 {
472 if( aSymbol->GetLibSymbolRef() || aForceIncludeOrphanSymbols )
473 {
474 SCH_REFERENCE schReference( aSymbol, *this );
475
476 schReference.SetSheetNumber( GetPageNumberAsInt() );
477 aReferences.AddItem( schReference );
478 }
479 }
480}
481
482
484 bool aIncludePowerSymbols ) const
485{
486 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
487 {
488 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
489 AppendMultiUnitSymbol( aRefList, symbol, aIncludePowerSymbols );
490 }
491}
492
493
495 SCH_SYMBOL* aSymbol,
496 bool aIncludePowerSymbols ) const
497{
498 // Skip pseudo-symbols, which have a reference starting with #. This mainly
499 // affects power symbols.
500 if( !aIncludePowerSymbols && aSymbol->GetRef( this )[0] == wxT( '#' ) )
501 return;
502
503 LIB_SYMBOL* symbol = aSymbol->GetLibSymbolRef().get();
504
505 if( symbol && symbol->GetUnitCount() > 1 )
506 {
507 SCH_REFERENCE schReference = SCH_REFERENCE( aSymbol, *this );
508 schReference.SetSheetNumber( GetPageNumberAsInt() );
509 wxString reference_str = schReference.GetRef();
510
511 // Never lock unassigned references
512 if( reference_str[reference_str.Len() - 1] == '?' )
513 return;
514
515 aRefList[reference_str].AddItem( schReference );
516 }
517}
518
519
521{
522 return m_current_hash == d1.GetCurrentHash();
523}
524
525
526bool SCH_SHEET_PATH::TestForRecursion( const wxString& aSrcFileName, const wxString& aDestFileName )
527{
528 auto pair = std::make_pair( aSrcFileName, aDestFileName );
529
530 if( m_recursion_test_cache.count( pair ) )
531 return m_recursion_test_cache.at( pair );
532
533 SCHEMATIC* sch = LastScreen()->Schematic();
534
535 wxCHECK_MSG( sch, false, "No SCHEMATIC found in SCH_SHEET_PATH::TestForRecursion!" );
536
537 wxFileName rootFn = sch->GetFileName();
538 wxFileName srcFn = aSrcFileName;
539 wxFileName destFn = aDestFileName;
540
541 if( srcFn.IsRelative() )
542 srcFn.MakeAbsolute( rootFn.GetPath() );
543
544 if( destFn.IsRelative() )
545 destFn.MakeAbsolute( rootFn.GetPath() );
546
547 // The source and destination sheet file names cannot be the same.
548 if( srcFn == destFn )
549 {
550 m_recursion_test_cache[pair] = true;
551 return true;
552 }
553
557 unsigned i = 0;
558
559 while( i < size() )
560 {
561 wxFileName cmpFn = at( i )->GetFileName();
562
563 if( cmpFn.IsRelative() )
564 cmpFn.MakeAbsolute( rootFn.GetPath() );
565
566 // Test if the file name of the destination sheet is in anywhere in this sheet path.
567 if( cmpFn == destFn )
568 break;
569
570 i++;
571 }
572
573 // The destination sheet file name was not found in the sheet path or the destination
574 // sheet file name is the root sheet so no recursion is possible.
575 if( i >= size() || i == 0 )
576 {
577 m_recursion_test_cache[pair] = false;
578 return false;
579 }
580
581 // Walk back up to the root sheet to see if the source file name is already a parent in
582 // the sheet path. If so, recursion will occur.
583 do
584 {
585 i -= 1;
586
587 wxFileName cmpFn = at( i )->GetFileName();
588
589 if( cmpFn.IsRelative() )
590 cmpFn.MakeAbsolute( rootFn.GetPath() );
591
592 if( cmpFn == srcFn )
593 {
594 m_recursion_test_cache[pair] = true;
595 return true;
596 }
597
598 } while( i != 0 );
599
600 // The source sheet file name is not a parent of the destination sheet file name.
601 m_recursion_test_cache[pair] = false;
602 return false;
603}
604
605
607{
608 SCH_SHEET* sheet = Last();
609
610 wxCHECK( sheet, wxEmptyString );
611
612 KIID_PATH tmpPath = Path();
613 tmpPath.pop_back();
614
615 return sheet->getPageNumber( tmpPath );
616}
617
619{
620 long page;
621 wxString pageStr = GetPageNumber();
622
623 if( pageStr.ToLong( &page ) )
624 return (int) page;
625
626 return GetVirtualPageNumber();
627}
628
629
630void SCH_SHEET_PATH::SetPageNumber( const wxString& aPageNumber )
631{
632 SCH_SHEET* sheet = Last();
633
634 wxCHECK( sheet, /* void */ );
635
636 KIID_PATH tmpPath = Path();
637
638 tmpPath.pop_back();
639
640 sheet->addInstance( tmpPath );
641 sheet->setPageNumber( tmpPath, aPageNumber );
642}
643
644
646 const wxString& aProjectName )
647{
648 wxCHECK( !aProjectName.IsEmpty(), /* void */ );
649
650 SCH_SHEET_PATH newSheetPath( aPrefixSheetPath );
651 SCH_SHEET_PATH currentSheetPath( *this );
652
653 // Prefix the new hierarchical path.
654 newSheetPath = newSheetPath + currentSheetPath;
655
656 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
657 {
658 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
659
660 wxCHECK2( symbol, continue );
661
662 SCH_SYMBOL_INSTANCE newSymbolInstance;
663
664 if( symbol->GetInstance( newSymbolInstance, Path(), true ) )
665 {
666 newSymbolInstance.m_ProjectName = aProjectName;
667
668 // Use an existing symbol instance for this path if it exists.
669 newSymbolInstance.m_Path = newSheetPath.Path();
670 symbol->AddHierarchicalReference( newSymbolInstance );
671 }
672 else if( !symbol->GetInstances().empty() )
673 {
674 newSymbolInstance.m_ProjectName = aProjectName;
675
676 // Use the first symbol instance if any symbol instance data exists.
677 newSymbolInstance = symbol->GetInstances()[0];
678 newSymbolInstance.m_Path = newSheetPath.Path();
679 symbol->AddHierarchicalReference( newSymbolInstance );
680 }
681 else
682 {
683 newSymbolInstance.m_ProjectName = aProjectName;
684
685 // Fall back to the last saved symbol field and unit settings if there is no
686 // instance data.
687 newSymbolInstance.m_Path = newSheetPath.Path();
688 newSymbolInstance.m_Reference = symbol->GetField( FIELD_T::REFERENCE )->GetText();
689 newSymbolInstance.m_Unit = symbol->GetUnit();
690 symbol->AddHierarchicalReference( newSymbolInstance );
691 }
692 }
693}
694
695
697{
698 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
699 {
700 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
701
702 wxCHECK2( symbol, continue );
703
704 SCH_SHEET_PATH fullSheetPath( aPrefixSheetPath );
705 SCH_SHEET_PATH currentSheetPath( *this );
706
707 // Prefix the hierarchical path of the symbol instance to be removed.
708 fullSheetPath = fullSheetPath + currentSheetPath;
709 symbol->RemoveInstance( fullSheetPath );
710 }
711}
712
713
714void SCH_SHEET_PATH::CheckForMissingSymbolInstances( const wxString& aProjectName )
715{
716 wxCHECK( !aProjectName.IsEmpty() && LastScreen(), /* void */ );
717
718 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
719 {
720 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
721
722 wxCHECK2( symbol, continue );
723
724 SCH_SYMBOL_INSTANCE symbolInstance;
725
726 if( !symbol->GetInstance( symbolInstance, Path() ) )
727 {
728 wxLogTrace( traceSchSheetPaths, "Adding missing symbol \"%s\" instance data for "
729 "sheet path '%s'.",
730 symbol->m_Uuid.AsString(), PathHumanReadable( false ) );
731
732 // Legacy schematics that are not shared do not contain separate instance data.
733 // The symbol reference and unit are saved in the reference field and unit entries.
734 if( ( LastScreen()->GetRefCount() <= 1 ) &&
735 ( LastScreen()->GetFileFormatVersionAtLoad() <= 20200310 ) )
736 {
737 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
738 symbolInstance.m_Reference = refField->GetShownText( this, true );
739 symbolInstance.m_Unit = symbol->GetUnit();
740 }
741 else
742 {
743 // When schematics are shared, we cannot know which instance the current symbol
744 // reference field and unit belong to. In this case, we clear the reference
745 // annotation and set the unit to 1.
746 symbolInstance.m_Reference = UTIL::GetRefDesUnannotated( symbol->GetPrefix() );
747 }
748
749 symbolInstance.m_ProjectName = aProjectName;
750 symbolInstance.m_Path = Path();
751 symbol->AddHierarchicalReference( symbolInstance );
752 }
753 }
754}
755
756
758{
759 wxCHECK( m_sheets.size() > 1, /* void */ );
760
761 wxFileName sheetFileName = Last()->GetFileName();
762
763 // If the sheet file name is absolute, then the user requested is so don't make it relative.
764 if( sheetFileName.IsAbsolute() )
765 return;
766
767 SCH_SCREEN* screen = LastScreen();
768 SCH_SCREEN* parentScreen = m_sheets[ m_sheets.size() - 2 ]->GetScreen();
769
770 wxCHECK( screen && parentScreen, /* void */ );
771
772 wxFileName fileName = screen->GetFileName();
773 wxFileName parentFileName = parentScreen->GetFileName();
774
775 // SCH_SCREEN file names must be absolute. If they are not, someone set them incorrectly
776 // on load or on creation.
777 wxCHECK( fileName.IsAbsolute() && parentFileName.IsAbsolute(), /* void */ );
778
779 if( fileName.GetPath() == parentFileName.GetPath() )
780 {
781 Last()->SetFileName( fileName.GetFullName() );
782 }
783 else if( fileName.MakeRelativeTo( parentFileName.GetPath() ) )
784 {
785 Last()->SetFileName( fileName.GetFullPath() );
786 }
787 else
788 {
789 Last()->SetFileName( screen->GetFileName() );
790 }
791
792 wxLogTrace( tracePathsAndFiles,
793 wxT( "\n File name: '%s'"
794 "\n parent file name '%s',"
795 "\n sheet '%s' file name '%s'." ),
796 screen->GetFileName(), parentScreen->GetFileName(), PathHumanReadable(),
797 Last()->GetFileName() );
798}
799
800
802{
803 if( aSheet != nullptr )
804 BuildSheetList( aSheet, false );
805}
806
807
808void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity )
809{
810 if( !aSheet )
811 return;
812
813 std::vector<SCH_SHEET*> badSheets;
814
815 m_currentSheetPath.push_back( aSheet );
816 m_currentSheetPath.SetVirtualPageNumber( static_cast<int>( size() ) + 1 );
817 push_back( m_currentSheetPath );
818
819 if( m_currentSheetPath.LastScreen() )
820 {
821 wxString parentFileName = aSheet->GetFileName();
822 std::vector<SCH_ITEM*> childSheets;
823 m_currentSheetPath.LastScreen()->GetSheets( &childSheets );
824
825 for( SCH_ITEM* item : childSheets )
826 {
827 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
828
829 if( aCheckIntegrity )
830 {
831 if( !m_currentSheetPath.TestForRecursion( sheet->GetFileName(), parentFileName ) )
832 BuildSheetList( sheet, true );
833 else
834 badSheets.push_back( sheet );
835 }
836 else
837 {
838 // If we are not performing a full recursion test, at least check if we are in
839 // a simple recursion scenario to prevent stack overflow crashes
840 wxCHECK2_MSG( sheet->GetFileName() != aSheet->GetFileName(), continue,
841 wxT( "Recursion prevented in SCH_SHEET_LIST::BuildSheetList" ) );
842
843 BuildSheetList( sheet, false );
844 }
845 }
846 }
847
848 if( aCheckIntegrity )
849 {
850 for( SCH_SHEET* sheet : badSheets )
851 {
852 m_currentSheetPath.LastScreen()->Remove( sheet );
853 m_currentSheetPath.LastScreen()->SetContentModified();
854 }
855 }
856
857 m_currentSheetPath.pop_back();
858}
859
860
861void SCH_SHEET_LIST::SortByHierarchicalPageNumbers( bool aUpdateVirtualPageNums )
862{
863 for( const SCH_SHEET_PATH& path : *this )
864 path.CachePageNumber();
865
866 std::sort( begin(), end(),
867 []( const SCH_SHEET_PATH& a, const SCH_SHEET_PATH& b ) -> bool
868 {
869 // Find the divergence point in the paths
870 size_t common_len = 0;
871 size_t min_len = std::min( a.size(), b.size() );
872
873 while( common_len < min_len && a.at( common_len )->m_Uuid == b.at( common_len )->m_Uuid )
874 common_len++;
875
876 // If one path is a prefix of the other, the shorter one comes first
877 // This ensures parents come before children
878 if( common_len == a.size() )
879 return true; // a is a prefix of b - a is the parent
880 if( common_len == b.size() )
881 return false; // b is a prefix of a - b is the parent
882
883 // Paths diverge at common_len
884 // If they share the same parent, sort by page number
885 // This ensures siblings are sorted by page number
886 SCH_SHEET* sheet_a = a.at( common_len );
887 SCH_SHEET* sheet_b = b.at( common_len );
888
889 // Create partial paths to get to these sheets for page number comparison
890 KIID_PATH ancestor;
891 for( size_t i = 0; i < common_len; i++ )
892 ancestor.push_back( a.at( i )->m_Uuid );
893
894 // Compare page numbers - use the last sheet's page number
895 wxString page_a = sheet_a->getPageNumber( ancestor );
896 wxString page_b = sheet_b->getPageNumber( ancestor );
897
898 int retval = SCH_SHEET::ComparePageNum( page_a, page_b );
899
900 if( retval != 0 )
901 return retval < 0;
902
903 // If page numbers are the same, use virtual page numbers as a tie-breaker
905 return true;
906 else if( a.GetVirtualPageNumber() > b.GetVirtualPageNumber() )
907 return false;
908
909 // Finally, use UUIDs for stable ordering when everything else is equal
910 return a.GetCurrentHash() < b.GetCurrentHash();
911 } );
912
913 if( aUpdateVirtualPageNums )
914 {
915 int virtualPageNum = 1;
916
917 for( SCH_SHEET_PATH& sheet : *this )
918 sheet.SetVirtualPageNumber( virtualPageNum++ );
919 }
920}
921
922
923void SCH_SHEET_LIST::SortByPageNumbers( bool aUpdateVirtualPageNums )
924{
925 for( const SCH_SHEET_PATH& path : *this )
926 path.CachePageNumber();
927
928 std::sort( begin(), end(),
929 []( const SCH_SHEET_PATH& a, const SCH_SHEET_PATH& b ) -> bool
930 {
933
934 if( retval < 0 )
935 return true;
936 else if( retval > 0 )
937 return false;
938
940 return true;
941 else if( a.GetVirtualPageNumber() > b.GetVirtualPageNumber() )
942 return false;
943
944 // Enforce strict ordering. If the page numbers are the same, use UUIDs
945 return a.GetCurrentHash() < b.GetCurrentHash();
946 } );
947
948 if( aUpdateVirtualPageNums )
949 {
950 int virtualPageNum = 1;
951
952 for( SCH_SHEET_PATH& sheet : *this )
953 sheet.SetVirtualPageNumber( virtualPageNum++ );
954 }
955}
956
957
958bool SCH_SHEET_LIST::NameExists( const wxString& aSheetName ) const
959{
960 for( const SCH_SHEET_PATH& sheet : *this )
961 {
962 if( sheet.Last()->GetName() == aSheetName )
963 return true;
964 }
965
966 return false;
967}
968
969
970bool SCH_SHEET_LIST::PageNumberExists( const wxString& aPageNumber ) const
971{
972 for( const SCH_SHEET_PATH& sheet : *this )
973 {
974 if( sheet.GetPageNumber() == aPageNumber )
975 return true;
976 }
977
978 return false;
979}
980
981
982void SCH_SHEET_LIST::TrimToPageNumbers( const std::vector<wxString>& aPageInclusions )
983{
984 auto it = std::remove_if( begin(), end(),
985 [&]( const SCH_SHEET_PATH& sheet )
986 {
987 return std::find( aPageInclusions.begin(),
988 aPageInclusions.end(),
989 sheet.GetPageNumber() ) == aPageInclusions.end();
990 } );
991
992 erase( it, end() );
993}
994
995
997{
998 for( const SCH_SHEET_PATH& sheet : *this )
999 {
1000 if( sheet.LastScreen() && sheet.LastScreen()->IsContentModified() )
1001 return true;
1002 }
1003
1004 return false;
1005}
1006
1007
1009{
1010 for( const SCH_SHEET_PATH& sheet : *this )
1011 {
1012 if( sheet.LastScreen() )
1013 sheet.LastScreen()->SetContentModified( false );
1014 }
1015}
1016
1017
1018SCH_ITEM* SCH_SHEET_LIST::ResolveItem( const KIID& aID, SCH_SHEET_PATH* aPathOut, bool aAllowNullptrReturn ) const
1019{
1020 for( const SCH_SHEET_PATH& sheet : *this )
1021 {
1022 SCH_ITEM* item = sheet.ResolveItem( aID );
1023
1024 if( item )
1025 {
1026 if( aPathOut )
1027 *aPathOut = sheet;
1028
1029 return item;
1030 }
1031 }
1032
1033 // Not found; weak reference has been deleted.
1034 if( aAllowNullptrReturn )
1035 return nullptr;
1036 else
1038}
1039
1040
1042{
1043 for( SCH_ITEM* aItem : LastScreen()->Items() )
1044 {
1045 if( aItem->m_Uuid == aID )
1046 return aItem;
1047
1048 SCH_ITEM* childMatch = nullptr;
1049
1050 aItem->RunOnChildren(
1051 [&]( SCH_ITEM* aChild )
1052 {
1053 if( aChild->m_Uuid == aID )
1054 childMatch = aChild;
1055 },
1057
1058 if( childMatch )
1059 return childMatch;
1060 }
1061
1062 return nullptr;
1063}
1064
1065
1066void SCH_SHEET_LIST::FillItemMap( std::map<KIID, EDA_ITEM*>& aMap )
1067{
1068 for( const SCH_SHEET_PATH& sheet : *this )
1069 {
1070 SCH_SCREEN* screen = sheet.LastScreen();
1071
1072 for( SCH_ITEM* aItem : screen->Items() )
1073 {
1074 aMap[ aItem->m_Uuid ] = aItem;
1075
1076 aItem->RunOnChildren(
1077 [&]( SCH_ITEM* aChild )
1078 {
1079 aMap[ aChild->m_Uuid ] = aChild;
1080 },
1082 }
1083 }
1084}
1085
1086
1088{
1089 // List of reference for power symbols
1090 SCH_REFERENCE_LIST references;
1091 SCH_REFERENCE_LIST additionalreferences; // Todo: add as a parameter to this function
1092
1093 // Map of locked symbols (not used, but needed by Annotate()
1094 SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
1095
1096 // Build the list of power symbols:
1097 for( SCH_SHEET_PATH& sheet : *this )
1098 {
1099 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
1100 {
1101 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1102 LIB_SYMBOL* libSymbol = symbol->GetLibSymbolRef().get();
1103
1104 if( libSymbol && libSymbol->IsPower() )
1105 {
1106 SCH_REFERENCE schReference( symbol, sheet );
1107 references.AddItem( schReference );
1108 }
1109 }
1110 }
1111
1112 // Find duplicate, and silently clear annotation of duplicate
1113 std::map<wxString, int> ref_list; // stores the existing references
1114
1115 for( unsigned ii = 0; ii< references.GetCount(); ++ii )
1116 {
1117 wxString curr_ref = references[ii].GetRef();
1118
1119 if( curr_ref.IsEmpty() )
1120 continue;
1121
1122 if( ref_list.find( curr_ref ) == ref_list.end() )
1123 {
1124 ref_list[curr_ref] = ii;
1125 continue;
1126 }
1127
1128 // Possible duplicate, if the ref ends by a number:
1129 if( curr_ref.Last() < '0' && curr_ref.Last() > '9' )
1130 continue; // not annotated
1131
1132 // Duplicate: clear annotation by removing the number ending the ref
1133 while( !curr_ref.IsEmpty() && curr_ref.Last() >= '0' && curr_ref.Last() <= '9' )
1134 curr_ref.RemoveLast();
1135
1136 references[ii].SetRef( curr_ref );
1137 }
1138
1139 // Break full symbol reference into name (prefix) and number:
1140 // example: IC1 become IC, and 1
1141 references.SplitReferences();
1142
1143 // Ensure all power symbols have the reference starting by '#'
1144 // (Not sure this is really useful)
1145 for( unsigned ii = 0; ii< references.GetCount(); ++ii )
1146 {
1147 SCH_REFERENCE& ref_unit = references[ii];
1148
1149 if( ref_unit.GetRef()[0] != '#' )
1150 {
1151 wxString new_ref = "#" + ref_unit.GetRef();
1152 ref_unit.SetRef( new_ref );
1153 ref_unit.SetRefNum( ii );
1154 }
1155 }
1156}
1157
1158
1159void SCH_SHEET_LIST::GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols,
1160 bool aForceIncludeOrphanSymbols ) const
1161{
1162 for( const SCH_SHEET_PATH& sheet : *this )
1163 sheet.GetSymbols( aReferences, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
1164}
1165
1166
1168 const SCH_SHEET_PATH& aSheetPath,
1169 bool aIncludePowerSymbols,
1170 bool aForceIncludeOrphanSymbols ) const
1171{
1172 for( const SCH_SHEET_PATH& sheet : *this )
1173 {
1174 if( sheet.IsContainedWithin( aSheetPath ) )
1175 sheet.GetSymbols( aReferences, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
1176 }
1177}
1178
1179
1180void SCH_SHEET_LIST::GetSheetsWithinPath( std::vector<SCH_SHEET_PATH>& aSheets,
1181 const SCH_SHEET_PATH& aSheetPath ) const
1182{
1183 for( const SCH_SHEET_PATH& sheet : *this )
1184 {
1185 if( sheet.IsContainedWithin( aSheetPath ) )
1186 aSheets.push_back( sheet );
1187 }
1188}
1189
1190
1191std::optional<SCH_SHEET_PATH> SCH_SHEET_LIST::GetSheetPathByKIIDPath( const KIID_PATH& aPath,
1192 bool aIncludeLastSheet ) const
1193{
1194 for( const SCH_SHEET_PATH& sheet : *this )
1195 {
1196 KIID_PATH testPath = sheet.Path();
1197
1198 if( !aIncludeLastSheet )
1199 testPath.pop_back();
1200
1201 if( testPath == aPath )
1202 return SCH_SHEET_PATH( sheet );
1203 }
1204
1205 return std::nullopt;
1206}
1207
1208
1210 bool aIncludePowerSymbols ) const
1211{
1212 for( auto it = begin(); it != end(); ++it )
1213 {
1215 ( *it ).GetMultiUnitSymbols( tempMap, aIncludePowerSymbols );
1216
1217 for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : tempMap )
1218 {
1219 // Merge this list into the main one
1220 unsigned n_refs = pair.second.GetCount();
1221
1222 for( unsigned thisRef = 0; thisRef < n_refs; ++thisRef )
1223 aRefList[pair.first].AddItem( pair.second[thisRef] );
1224 }
1225 }
1226}
1227
1228
1229bool SCH_SHEET_LIST::TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy,
1230 const wxString& aDestFileName )
1231{
1232 if( empty() )
1233 return false;
1234
1235 SCHEMATIC* sch = at( 0 ).LastScreen()->Schematic();
1236
1237 wxCHECK_MSG( sch, false, "No SCHEMATIC found in SCH_SHEET_LIST::TestForRecursion!" );
1238
1239 wxFileName rootFn = sch->GetFileName();
1240 wxFileName destFn = aDestFileName;
1241
1242 if( destFn.IsRelative() )
1243 destFn.MakeAbsolute( rootFn.GetPath() );
1244
1245 // Test each SCH_SHEET_PATH in this SCH_SHEET_LIST for potential recursion.
1246 for( unsigned i = 0; i < size(); i++ )
1247 {
1248 // Test each SCH_SHEET_PATH in the source sheet.
1249 for( unsigned j = 0; j < aSrcSheetHierarchy.size(); j++ )
1250 {
1251 const SCH_SHEET_PATH* sheetPath = &aSrcSheetHierarchy[j];
1252
1253 for( unsigned k = 0; k < sheetPath->size(); k++ )
1254 {
1255 if( at( i ).TestForRecursion( sheetPath->GetSheet( k )->GetFileName(),
1256 aDestFileName ) )
1257 {
1258 return true;
1259 }
1260 }
1261 }
1262 }
1263
1264 // The source sheet file can safely be added to the destination sheet file.
1265 return false;
1266}
1267
1268
1270{
1271 for( SCH_SHEET_PATH& path : *this )
1272 {
1273 if( path.Path() == aPath->Path() )
1274 return &path;
1275 }
1276
1277 return nullptr;
1278}
1279
1280
1282{
1283 for( SCH_SHEET_PATH& sheetpath : *this )
1284 {
1285 if( sheetpath.LastScreen() == aScreen )
1286 return sheetpath;
1287 }
1288
1289 return SCH_SHEET_PATH();
1290}
1291
1292
1294{
1295 SCH_SHEET_LIST retval;
1296
1297 for( const SCH_SHEET_PATH& sheetpath : *this )
1298 {
1299 if( sheetpath.LastScreen() == aScreen )
1300 retval.push_back( sheetpath );
1301 }
1302
1303 return retval;
1304}
1305
1306
1308 const std::vector<SCH_SYMBOL_INSTANCE>& aSymbolInstances )
1309{
1310 for( SCH_SHEET_PATH& sheetPath : *this )
1311 {
1312 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
1313 {
1314 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1315
1316 wxCHECK2( symbol, continue );
1317
1318 KIID_PATH sheetPathWithSymbolUuid = sheetPath.Path();
1319 sheetPathWithSymbolUuid.push_back( symbol->m_Uuid );
1320
1321 auto it = std::find_if( aSymbolInstances.begin(), aSymbolInstances.end(),
1322 [ sheetPathWithSymbolUuid ]( const SCH_SYMBOL_INSTANCE& r ) -> bool
1323 {
1324 return sheetPathWithSymbolUuid == r.m_Path;
1325 } );
1326
1327 if( it == aSymbolInstances.end() )
1328 {
1329 wxLogTrace( traceSchSheetPaths, "No symbol instance found for symbol '%s'",
1330 sheetPathWithSymbolUuid.AsString() );
1331 continue;
1332 }
1333
1334 // Symbol instance paths are stored and looked up in memory with the root path so use
1335 // the full path here.
1336 symbol->AddHierarchicalReference( sheetPath.Path(), it->m_Reference, it->m_Unit );
1337 symbol->GetField( FIELD_T::REFERENCE )->SetText( it->m_Reference );
1338
1339 if( !it->m_Value.IsEmpty() )
1340 symbol->SetValueFieldText( it->m_Value );
1341
1342 if( !it->m_Footprint.IsEmpty() )
1343 symbol->SetFootprintFieldText( it->m_Footprint );
1344
1345 symbol->UpdatePrefix();
1346 }
1347 }
1348}
1349
1350
1351void SCH_SHEET_LIST::UpdateSheetInstanceData( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances )
1352{
1353
1354 for( SCH_SHEET_PATH& path : *this )
1355 {
1356 SCH_SHEET* sheet = path.Last();
1357
1358 wxCHECK2( sheet && path.Last(), continue );
1359
1360 auto it = std::find_if( aSheetInstances.begin(), aSheetInstances.end(),
1361 [&path]( const SCH_SHEET_INSTANCE& r ) -> bool
1362 {
1363 return path.Path() == r.m_Path;
1364 } );
1365
1366 if( it == aSheetInstances.end() )
1367 {
1368 wxLogTrace( traceSchSheetPaths, "No sheet instance found for path '%s'",
1369 path.Path().AsString() );
1370 continue;
1371 }
1372
1373 wxLogTrace( traceSchSheetPaths, "Setting sheet '%s' instance '%s' page number '%s'",
1374 ( sheet->GetName().IsEmpty() ) ? wxString( wxT( "root" ) ) : sheet->GetName(),
1375 path.Path().AsString(), it->m_PageNumber );
1376 path.SetPageNumber( it->m_PageNumber );
1377 }
1378}
1379
1380
1381std::vector<KIID_PATH> SCH_SHEET_LIST::GetPaths() const
1382{
1383 std::vector<KIID_PATH> paths;
1384
1385 for( const SCH_SHEET_PATH& sheetPath : *this )
1386 paths.emplace_back( sheetPath.Path() );
1387
1388 return paths;
1389}
1390
1391
1392std::vector<SCH_SHEET_INSTANCE> SCH_SHEET_LIST::GetSheetInstances() const
1393{
1394 std::vector<SCH_SHEET_INSTANCE> retval;
1395
1396 for( const SCH_SHEET_PATH& path : *this )
1397 {
1398 const SCH_SHEET* sheet = path.Last();
1399
1400 wxCHECK2( sheet, continue );
1401
1402 SCH_SHEET_INSTANCE instance;
1403 SCH_SHEET_PATH tmpPath = path;
1404
1405 tmpPath.pop_back();
1406 instance.m_Path = tmpPath.Path();
1407 instance.m_PageNumber = path.GetPageNumber();
1408
1409 retval.push_back( std::move( instance ) );
1410 }
1411
1412 return retval;
1413}
1414
1415
1417{
1418 for( const SCH_SHEET_PATH& instance : *this )
1419 {
1420 if( !instance.GetPageNumber().IsEmpty() )
1421 return false;
1422 }
1423
1424 return true;
1425}
1426
1427
1429{
1430 // Don't accidentally renumber existing sheets.
1431 wxCHECK( AllSheetPageNumbersEmpty(), /* void */ );
1432
1433 wxString tmp;
1434 int pageNumber = 1;
1435
1436 for( SCH_SHEET_PATH& instance : *this )
1437 {
1438 tmp.Printf( "%d", pageNumber );
1439 instance.SetPageNumber( tmp );
1440 pageNumber += 1;
1441 }
1442}
1443
1444
1446 const wxString& aProjectName )
1447{
1448 for( SCH_SHEET_PATH& sheetPath : *this )
1449 sheetPath.AddNewSymbolInstances( aPrefixSheetPath, aProjectName );
1450}
1451
1452
1454{
1455 for( SCH_SHEET_PATH& sheetPath : *this )
1456 sheetPath.RemoveSymbolInstances( aPrefixSheetPath );
1457}
1458
1459
1461 int aLastVirtualPageNumber )
1462{
1463 wxString pageNumber;
1464 int lastUsedPageNumber = 1;
1465 int nextVirtualPageNumber = aLastVirtualPageNumber;
1466
1467 // Fetch the list of page numbers already in use.
1468 std::vector< wxString > usedPageNumbers;
1469
1470 if( aPrefixSheetPath.size() )
1471 {
1472 SCH_SHEET_LIST prefixHierarchy( aPrefixSheetPath.at( 0 ) );
1473
1474 for( const SCH_SHEET_PATH& path : prefixHierarchy )
1475 {
1476 pageNumber = path.GetPageNumber();
1477
1478 if( !pageNumber.IsEmpty() )
1479 usedPageNumbers.emplace_back( pageNumber );
1480 }
1481 }
1482
1483 for( SCH_SHEET_PATH& sheetPath : *this )
1484 {
1485 KIID_PATH tmp = sheetPath.Path();
1486 SCH_SHEET_PATH newSheetPath( aPrefixSheetPath );
1487
1488 // Prefix the new hierarchical path.
1489 newSheetPath = newSheetPath + sheetPath;
1490
1491 // Sheets cannot have themselves in the path.
1492 tmp.pop_back();
1493
1494 SCH_SHEET* sheet = sheetPath.Last();
1495
1496 wxCHECK2( sheet, continue );
1497
1498 nextVirtualPageNumber += 1;
1499
1500 SCH_SHEET_INSTANCE instance;
1501
1502 // Add the instance if it doesn't already exist
1503 if( !sheet->getInstance( instance, tmp, true ) )
1504 {
1505 sheet->addInstance( tmp );
1506 sheet->getInstance( instance, tmp, true );
1507 }
1508
1509 // Get a new page number if we don't have one
1510 if( instance.m_PageNumber.IsEmpty() )
1511 {
1512 // Generate the next available page number.
1513 do
1514 {
1515 pageNumber.Printf( wxT( "%d" ), lastUsedPageNumber );
1516 lastUsedPageNumber += 1;
1517 } while( std::find( usedPageNumbers.begin(), usedPageNumbers.end(), pageNumber ) !=
1518 usedPageNumbers.end() );
1519
1520 instance.m_PageNumber = pageNumber;
1521 newSheetPath.SetVirtualPageNumber( nextVirtualPageNumber );
1522 }
1523
1524 newSheetPath.SetPageNumber( instance.m_PageNumber );
1525 usedPageNumbers.push_back( instance.m_PageNumber );
1526 }
1527}
1528
1529
1530void SCH_SHEET_LIST::CheckForMissingSymbolInstances( const wxString& aProjectName )
1531{
1532 for( SCH_SHEET_PATH& sheetPath : *this )
1533 sheetPath.CheckForMissingSymbolInstances( aProjectName );
1534}
1535
1536
1538{
1539 int lastVirtualPageNumber = 1;
1540
1541 for( const SCH_SHEET_PATH& sheetPath : *this )
1542 {
1543 if( sheetPath.GetVirtualPageNumber() > lastVirtualPageNumber )
1544 lastVirtualPageNumber = sheetPath.GetVirtualPageNumber();
1545 }
1546
1547 return lastVirtualPageNumber;
1548}
1549
1550
1551bool SCH_SHEET_LIST::HasPath( const KIID_PATH& aPath ) const
1552{
1553 for( const SCH_SHEET_PATH& path : *this )
1554 {
1555 if( path.Path() == aPath )
1556 return true;
1557 }
1558
1559 return false;
1560}
1561
1562
1563bool SCH_SHEET_LIST::ContainsSheet( const SCH_SHEET* aSheet ) const
1564{
1565 for( const SCH_SHEET_PATH& path : *this )
1566 {
1567 for( size_t i = 0; i < path.size(); i++ )
1568 {
1569 if( path.at( i ) == aSheet )
1570 return true;
1571 }
1572 }
1573
1574 return false;
1575}
1576
1577
1578std::optional<SCH_SHEET_PATH> SCH_SHEET_LIST::GetOrdinalPath( const SCH_SCREEN* aScreen ) const
1579{
1580 // Sheet paths with sheets that do not have a screen object are not valid.
1581 if( !aScreen )
1582 return std::nullopt;
1583
1584 for( const SCH_SHEET_PATH& path: *this )
1585 {
1586 if( path.LastScreen() == aScreen )
1587 return std::optional<SCH_SHEET_PATH>( path );
1588 }
1589
1590 return std::nullopt;
1591}
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:516
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
virtual void UpdateHatching() const
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
virtual bool IsVisible() const
Definition eda_text.h:187
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:397
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
wxString AsString() const
Definition kiid.cpp:356
Definition kiid.h:49
wxString AsString() const
Definition kiid.cpp:246
Define a library symbol object.
Definition lib_symbol.h:87
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
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) 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:609
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:244
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:51
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:117
const wxString & GetFileName() const
Definition sch_screen.h:152
SCHEMATIC * Schematic() const
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
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
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
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.
bool IsFullPath() const
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.
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.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:47
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:327
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:321
bool IsRootSheet() const
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:113
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:116
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.
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
Schematic symbol object.
Definition sch_symbol.h:75
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:134
void RemoveInstance(const SCH_SHEET_PATH &aInstancePath)
void SetValueFieldText(const wxString &aValue)
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.
bool GetInstance(SCH_SYMBOL_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
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:183
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
wxString GetPrefix() const
Definition sch_symbol.h:235
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
bool m_ExcludedFromBOM
bool m_ExcludedFromSim
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
wxString GetRefDesUnannotated(const wxString &aSource)
Return an unannotated refdes from either a prefix or an existing refdes.
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.
A simple container for sheet instance information.
A simple container for schematic symbol instance information.
size_t operator()(const SCH_SHEET_PATH &path) const
Definition for symbol library class.
@ INTERSHEET_REFS
Global label cross-reference page numbers.
@ REFERENCE
Field Reference of part, i.e. "IC21".
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