KiCad PCB EDA Suite
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 (C) 1992-2021 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 <sch_screen.h>
27 #include <sch_item.h>
28 #include <sch_marker.h>
29 #include <sch_reference_list.h>
30 #include <symbol_library.h>
31 #include <sch_sheet_path.h>
32 #include <sch_symbol.h>
33 #include <sch_sheet.h>
34 #include <schematic.h>
35 #include <template_fieldnames.h>
36 #include <trace_helpers.h>
37 
38 #include <boost/functional/hash.hpp>
39 #include <wx/filename.h>
40 #include <wx/log.h>
41 #include "erc_item.h"
42 
43 
49 {
50 public:
52  SCH_ITEM( nullptr, NOT_USED )
53  {}
54 
55  wxString GetSelectMenuText( EDA_UNITS aUnits ) const override
56  {
57  return _( "(Deleted Item)" );
58  }
59 
60  wxString GetClass() const override
61  {
62  return wxT( "DELETED_SHEET_ITEM" );
63  }
64 
66  {
67  static DELETED_SHEET_ITEM* item = nullptr;
68 
69  if( !item )
70  item = new DELETED_SHEET_ITEM();
71 
72  return item;
73  }
74 
75  // pure virtuals:
76  void SetPosition( const wxPoint& ) override {}
77  void Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) override {}
78  void Move( const wxPoint& aMoveVector ) override {}
79  void MirrorHorizontally( int aCenter ) override {}
80  void MirrorVertically( int aCenter ) override {}
81  void Rotate( const wxPoint& aCenter ) override {}
82 
83 #if defined(DEBUG)
84  void Show( int , std::ostream& ) const override {}
85 #endif
86 };
87 
88 
89 namespace std
90 {
92  {
93  return path.GetCurrentHash();
94  }
95 }
96 
97 
99 {
101  m_current_hash = 0;
102 }
103 
104 
106 {
107  initFromOther( aOther );
108 }
109 
110 
112 {
113  initFromOther( aOther );
114  return *this;
115 }
116 
117 
119 {
120  m_sheets = aOther.m_sheets;
123 
124  // Note: don't copy m_recursion_test_cache as it is slow and we want SCH_SHEET_PATHS to be
125  // very fast to construct for use in the connectivity algorithm.
126 }
127 
128 
130 {
131  return GetSheet( 0 ) && GetSheet( 0 )->IsRootSheet();
132 }
133 
134 
136 {
137  m_current_hash = 0;
138 
139  for( auto sheet : m_sheets )
140  boost::hash_combine( m_current_hash, sheet->m_Uuid.Hash() );
141 }
142 
143 
144 int SCH_SHEET_PATH::Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const
145 {
146  if( size() > aSheetPathToTest.size() )
147  return 1;
148 
149  if( size() < aSheetPathToTest.size() )
150  return -1;
151 
152  //otherwise, same number of sheets.
153  for( unsigned i = 0; i < size(); i++ )
154  {
155  if( at( i )->m_Uuid < aSheetPathToTest.at( i )->m_Uuid )
156  return -1;
157 
158  if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
159  return 1;
160  }
161 
162  return 0;
163 }
164 
165 
166 int SCH_SHEET_PATH::ComparePageNum( const SCH_SHEET_PATH& aSheetPathToTest ) const
167 {
168  wxString pageA = GetPageNumber();
169  wxString pageB = aSheetPathToTest.GetPageNumber();
170 
171  int pageNumComp = SCH_SHEET::ComparePageNum( pageA, pageB );
172 
173  if( pageNumComp == 0 )
174  {
175  int virtualPageA = GetVirtualPageNumber();
176  int virtualPageB = aSheetPathToTest.GetVirtualPageNumber();
177 
178  if( virtualPageA > virtualPageB )
179  pageNumComp = 1;
180  else if( virtualPageA < virtualPageB )
181  pageNumComp = -1;
182  }
183 
184  return pageNumComp;
185 }
186 
187 
188 bool SCH_SHEET_PATH::IsContainedWithin( const SCH_SHEET_PATH& aSheetPathToTest ) const
189 {
190  if( aSheetPathToTest.size() > size() )
191  return false;
192 
193  for( size_t i = 0; i < aSheetPathToTest.size(); ++i )
194  {
195  if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
196  return false;
197  }
198 
199  return true;
200 }
201 
202 
204 {
205  if( !empty() )
206  return m_sheets.back();
207 
208  return nullptr;
209 }
210 
211 
213 {
214  SCH_SHEET* lastSheet = Last();
215 
216  if( lastSheet )
217  return lastSheet->GetScreen();
218 
219  return nullptr;
220 }
221 
222 
224 {
225  SCH_SHEET* lastSheet = Last();
226 
227  if( lastSheet )
228  return lastSheet->GetScreen();
229 
230  return nullptr;
231 }
232 
233 
235 {
236  wxString s;
237 
238  s = wxT( "/" ); // This is the root path
239 
240  // Start at 1 to avoid the root sheet, which does not need to be added to the path.
241  // Its timestamp changes anyway.
242  for( unsigned i = 1; i < size(); i++ )
243  s += at( i )->m_Uuid.AsString() + wxT( "/" );
244 
245  return s;
246 }
247 
248 
250 {
251  KIID_PATH path;
252 
253  for( const SCH_SHEET* sheet : m_sheets )
254  path.push_back( sheet->m_Uuid );
255 
256  return path;
257 }
258 
259 
261 {
262  KIID_PATH path;
263 
264  for( size_t i = 1; i < size(); i++ )
265  path.push_back( at( i )->m_Uuid );
266 
267  return path;
268 }
269 
270 
271 wxString SCH_SHEET_PATH::PathHumanReadable( bool aUseShortRootName ) const
272 {
273  wxString s;
274  wxString fileName;
275 
276  if( !empty() && at( 0 )->GetScreen() )
277  fileName = at( 0 )->GetScreen()->GetFileName();
278 
279  wxFileName fn = fileName;
280 
281  if( aUseShortRootName )
282  s = wxT( "/" ); // Use only the short name in netlists
283  else
284  s = fn.GetName() + wxT( "/" );
285 
286  // Start at 1 since we've already processed the root sheet.
287  for( unsigned i = 1; i < size(); i++ )
288  s = s + at( i )->GetFields()[ SHEETNAME ].GetShownText() + wxT( "/" );
289 
290  return s;
291 }
292 
293 
295 {
296  for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
297  {
298  SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
299  symbol->GetField( REFERENCE_FIELD )->SetText( symbol->GetRef( this ) );
300  symbol->GetField( VALUE_FIELD )->SetText( symbol->GetValue( this, false ) );
301  symbol->GetField( FOOTPRINT_FIELD )->SetText( symbol->GetFootprint( this, false ) );
302  symbol->UpdateUnit( symbol->GetUnitSelection( this ) );
303  }
304 }
305 
306 
307 
308 void SCH_SHEET_PATH::GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols,
309  bool aForceIncludeOrphanSymbols ) const
310 {
311  for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
312  {
313  SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
314  AppendSymbol( aReferences, symbol, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
315  }
316 }
317 
318 
320  bool aIncludePowerSymbols,
321  bool aForceIncludeOrphanSymbols ) const
322 {
323  // Skip pseudo-symbols, which have a reference starting with #. This mainly
324  // affects power symbols.
325  if( aIncludePowerSymbols || aSymbol->GetRef( this )[0] != wxT( '#' ) )
326  {
327  LIB_SYMBOL* symbol = aSymbol->GetLibSymbolRef().get();
328 
329  if( symbol || aForceIncludeOrphanSymbols )
330  {
331  SCH_REFERENCE schReference( aSymbol, symbol, *this );
332 
333  schReference.SetSheetNumber( m_virtualPageNumber );
334  aReferences.AddItem( schReference );
335  }
336  }
337 }
338 
339 
341  bool aIncludePowerSymbols ) const
342 {
343  for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
344  {
345  SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
346  AppendMultiUnitSymbol( aRefList, symbol, aIncludePowerSymbols );
347  }
348 }
349 
350 
352  SCH_SYMBOL* aSymbol,
353  bool aIncludePowerSymbols ) const
354 {
355  // Skip pseudo-symbols, which have a reference starting with #. This mainly
356  // affects power symbols.
357  if( !aIncludePowerSymbols && aSymbol->GetRef( this )[0] == wxT( '#' ) )
358  return;
359 
360  LIB_SYMBOL* symbol = aSymbol->GetLibSymbolRef().get();
361 
362  if( symbol && symbol->GetUnitCount() > 1 )
363  {
364  SCH_REFERENCE schReference = SCH_REFERENCE( aSymbol, symbol, *this );
365  schReference.SetSheetNumber( m_virtualPageNumber );
366  wxString reference_str = schReference.GetRef();
367 
368  // Never lock unassigned references
369  if( reference_str[reference_str.Len() - 1] == '?' )
370  return;
371 
372  aRefList[reference_str].AddItem( schReference );
373  }
374 }
375 
376 
378 {
379  return m_current_hash == d1.GetCurrentHash();
380 }
381 
382 
383 bool SCH_SHEET_PATH::TestForRecursion( const wxString& aSrcFileName, const wxString& aDestFileName )
384 {
385  auto pair = std::make_pair( aSrcFileName, aDestFileName );
386 
387  if( m_recursion_test_cache.count( pair ) )
388  return m_recursion_test_cache.at( pair );
389 
390  SCHEMATIC* sch = LastScreen()->Schematic();
391 
392  wxCHECK_MSG( sch, false, wxT( "No SCHEMATIC found in SCH_SHEET_PATH::TestForRecursion!" ) );
393 
394  wxFileName rootFn = sch->GetFileName();
395  wxFileName srcFn = aSrcFileName;
396  wxFileName destFn = aDestFileName;
397 
398  if( srcFn.IsRelative() )
399  srcFn.MakeAbsolute( rootFn.GetPath() );
400 
401  if( destFn.IsRelative() )
402  destFn.MakeAbsolute( rootFn.GetPath() );
403 
404 
405  // The source and destination sheet file names cannot be the same.
406  if( srcFn == destFn )
407  {
408  m_recursion_test_cache[pair] = true;
409  return true;
410  }
411 
415  unsigned i = 0;
416 
417  while( i < size() )
418  {
419  wxFileName cmpFn = at( i )->GetFileName();
420 
421  if( cmpFn.IsRelative() )
422  cmpFn.MakeAbsolute( rootFn.GetPath() );
423 
424  // Test if the file name of the destination sheet is in anywhere in this sheet path.
425  if( cmpFn == destFn )
426  break;
427 
428  i++;
429  }
430 
431  // The destination sheet file name was not found in the sheet path or the destination
432  // sheet file name is the root sheet so no recursion is possible.
433  if( i >= size() || i == 0 )
434  {
435  m_recursion_test_cache[pair] = false;
436  return false;
437  }
438 
439  // Walk back up to the root sheet to see if the source file name is already a parent in
440  // the sheet path. If so, recursion will occur.
441  do
442  {
443  i -= 1;
444 
445  wxFileName cmpFn = at( i )->GetFileName();
446 
447  if( cmpFn.IsRelative() )
448  cmpFn.MakeAbsolute( rootFn.GetPath() );
449 
450  if( cmpFn == srcFn )
451  {
452  m_recursion_test_cache[pair] = true;
453  return true;
454  }
455 
456  } while( i != 0 );
457 
458  // The source sheet file name is not a parent of the destination sheet file name.
459  m_recursion_test_cache[pair] = false;
460  return false;
461 }
462 
463 
465 {
466  SCH_SHEET* sheet = Last();
467 
468  wxCHECK( sheet, wxEmptyString );
469 
470  return sheet->GetPageNumber( *this );
471 }
472 
473 
474 void SCH_SHEET_PATH::SetPageNumber( const wxString& aPageNumber )
475 {
476  SCH_SHEET* sheet = Last();
477 
478  wxCHECK( sheet, /* void */ );
479 
480  sheet->SetPageNumber( *this, aPageNumber );
481 }
482 
483 
485 {
486  wxCHECK( m_sheets.size() > 1, /* void */ );
487 
488  wxFileName sheetFileName = Last()->GetFileName();
489 
490  // If the sheet file name is absolute, then the user requested is so don't make it relative.
491  if( sheetFileName.IsAbsolute() )
492  return;
493 
494  SCH_SCREEN* screen = LastScreen();
495  SCH_SCREEN* parentScreen = m_sheets[ m_sheets.size() - 2 ]->GetScreen();
496 
497  wxCHECK( screen && parentScreen, /* void */ );
498 
499  wxFileName fileName = screen->GetFileName();
500  wxFileName parentFileName = parentScreen->GetFileName();
501 
502  // SCH_SCREEN file names must be absolute. If they are not, someone set them incorrectly
503  // on load or on creation.
504  wxCHECK( fileName.IsAbsolute() && parentFileName.IsAbsolute(), /* void */ );
505 
506  if( fileName.GetPath() == parentFileName.GetPath() )
507  {
508  Last()->SetFileName( fileName.GetFullName() );
509  }
510  else if( fileName.MakeRelativeTo( parentFileName.GetPath() ) )
511  {
512  Last()->SetFileName( fileName.GetFullPath() );
513  }
514  else
515  {
516  Last()->SetFileName( screen->GetFileName() );
517  }
518 
519  wxLogTrace( tracePathsAndFiles,
520  wxT( "\n File name: '%s'"
521  "\n parent file name '%s',"
522  "\n sheet '%s' file name '%s'." ),
523  screen->GetFileName(), parentScreen->GetFileName(), PathHumanReadable(),
524  Last()->GetFileName() );
525 }
526 
527 
528 SCH_SHEET_LIST::SCH_SHEET_LIST( SCH_SHEET* aSheet, bool aCheckIntegrity )
529 {
530  if( aSheet != nullptr )
531  {
532  BuildSheetList( aSheet, aCheckIntegrity );
533 
534  if( aSheet->IsRootSheet() )
536  }
537 }
538 
539 
540 void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity )
541 {
542  wxCHECK_RET( aSheet != nullptr, wxT( "Cannot build sheet list from undefined sheet." ) );
543 
544  std::vector<SCH_SHEET*> badSheets;
545 
546  m_currentSheetPath.push_back( aSheet );
547  m_currentSheetPath.SetVirtualPageNumber( static_cast<int>( size() ) + 1 );
548  push_back( m_currentSheetPath );
549 
551  {
552  wxString parentFileName = aSheet->GetFileName();
553  std::vector<SCH_ITEM*> childSheets;
554  m_currentSheetPath.LastScreen()->GetSheets( &childSheets );
555 
556  for( SCH_ITEM* item : childSheets )
557  {
558  SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
559 
560  if( aCheckIntegrity )
561  {
562  if( !m_currentSheetPath.TestForRecursion( sheet->GetFileName(), parentFileName ) )
563  BuildSheetList( sheet, true );
564  else
565  badSheets.push_back( sheet );
566  }
567  else
568  {
569  BuildSheetList( sheet, false );
570  }
571  }
572  }
573 
574  if( aCheckIntegrity )
575  {
576  for( SCH_SHEET* sheet : badSheets )
577  {
580  }
581  }
582 
584 }
585 
586 
587 void SCH_SHEET_LIST::SortByPageNumbers( bool aUpdateVirtualPageNums )
588 {
589  std::sort( begin(), end(),
590  []( SCH_SHEET_PATH a, SCH_SHEET_PATH b ) -> bool
591  {
592  return a.ComparePageNum( b ) < 0;
593  } );
594 
595  if( aUpdateVirtualPageNums )
596  {
597  int virtualPageNum = 1;
598 
599  for( SCH_SHEET_PATH& sheet : *this )
600  {
601  sheet.SetVirtualPageNumber( virtualPageNum++ );
602  }
603  }
604 }
605 
606 
607 bool SCH_SHEET_LIST::NameExists( const wxString& aSheetName ) const
608 {
609  for( const SCH_SHEET_PATH& sheet : *this )
610  {
611  if( sheet.Last()->GetName() == aSheetName )
612  return true;
613  }
614 
615  return false;
616 }
617 
618 
619 bool SCH_SHEET_LIST::PageNumberExists( const wxString& aPageNumber ) const
620 {
621  for( const SCH_SHEET_PATH& sheet : *this )
622  {
623  if( sheet.GetPageNumber() == aPageNumber )
624  return true;
625  }
626 
627  return false;
628 }
629 
630 
632 {
633  for( const SCH_SHEET_PATH& sheet : *this )
634  {
635  if( sheet.LastScreen() && sheet.LastScreen()->IsContentModified() )
636  return true;
637  }
638 
639  return false;
640 }
641 
642 
644 {
645  for( const SCH_SHEET_PATH& sheet : *this )
646  {
647  if( sheet.LastScreen() )
648  sheet.LastScreen()->SetContentModified( false );
649  }
650 }
651 
652 
653 SCH_ITEM* SCH_SHEET_LIST::GetItem( const KIID& aID, SCH_SHEET_PATH* aPathOut ) const
654 {
655  for( const SCH_SHEET_PATH& sheet : *this )
656  {
657  SCH_SCREEN* screen = sheet.LastScreen();
658 
659  for( SCH_ITEM* aItem : screen->Items() )
660  {
661  if( aItem->m_Uuid == aID )
662  {
663  if( aPathOut )
664  *aPathOut = sheet;
665 
666  return aItem;
667  }
668 
669  SCH_ITEM* childMatch = nullptr;
670 
671  aItem->RunOnChildren(
672  [&]( SCH_ITEM* aChild )
673  {
674  if( aChild->m_Uuid == aID )
675  childMatch = aChild;
676  } );
677 
678  if( childMatch )
679  {
680  if( aPathOut )
681  *aPathOut = sheet;
682 
683  return childMatch;
684  }
685  }
686  }
687 
688  // Not found; weak reference has been deleted.
690 }
691 
692 
693 void SCH_SHEET_LIST::FillItemMap( std::map<KIID, EDA_ITEM*>& aMap )
694 {
695  for( const SCH_SHEET_PATH& sheet : *this )
696  {
697  SCH_SCREEN* screen = sheet.LastScreen();
698 
699  for( SCH_ITEM* aItem : screen->Items() )
700  {
701  aMap[ aItem->m_Uuid ] = aItem;
702 
703  aItem->RunOnChildren(
704  [&]( SCH_ITEM* aChild )
705  {
706  aMap[ aChild->m_Uuid ] = aChild;
707  } );
708  }
709  }
710 }
711 
712 
714 {
715  // List of reference for power symbols
716  SCH_REFERENCE_LIST references;
717  SCH_REFERENCE_LIST additionalreferences; // Todo: add as a parameter to this function
718 
719  // Map of locked symbols (not used, but needed by Annotate()
720  SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
721 
722  // Build the list of power symbols:
723  for( SCH_SHEET_PATH& sheet : *this )
724  {
725  for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
726  {
727  SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
728  LIB_SYMBOL* libSymbol = symbol->GetLibSymbolRef().get();
729 
730  if( libSymbol && libSymbol->IsPower() )
731  {
732  SCH_REFERENCE schReference( symbol, libSymbol, sheet );
733  references.AddItem( schReference );
734  }
735  }
736  }
737 
738  // Find duplicate, and silently clear annotation of duplicate
739  std::map<wxString, int> ref_list; // stores the existing references
740 
741  for( unsigned ii = 0; ii< references.GetCount(); ++ii )
742  {
743  wxString curr_ref = references[ii].GetRef();
744 
745  if( ref_list.find( curr_ref ) == ref_list.end() )
746  {
747  ref_list[curr_ref] = ii;
748  continue;
749  }
750 
751  // Possible duplicate, if the ref ends by a number:
752  if( curr_ref.Last() < '0' && curr_ref.Last() > '9' )
753  continue; // not annotated
754 
755  // Duplicate: clear annotation by removing the number ending the ref
756  while( curr_ref.Last() >= '0' && curr_ref.Last() <= '9' )
757  curr_ref.RemoveLast();
758 
759  references[ii].SetRef( curr_ref );
760  }
761 
762  // Break full symbol reference into name (prefix) and number:
763  // example: IC1 become IC, and 1
764  references.SplitReferences();
765 
766  // Ensure all power symbols have the reference starting by '#'
767  // (Not sure this is really useful)
768  for( unsigned ii = 0; ii< references.GetCount(); ++ii )
769  {
770  if( references[ii].GetRef()[0] != '#' )
771  {
772  wxString new_ref = wxT( "#" ) + references[ii].GetRef();
773  references[ii].SetRef( new_ref );
774  }
775  }
776 
777  // Recalculate and update reference numbers in schematic
778  references.Annotate( false, 0, 100, lockedSymbols, additionalreferences );
779  references.UpdateAnnotation();
780 }
781 
782 
783 void SCH_SHEET_LIST::GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols,
784  bool aForceIncludeOrphanSymbols ) const
785 {
786  for( const SCH_SHEET_PATH& sheet : *this )
787  sheet.GetSymbols( aReferences, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
788 }
789 
790 
792  const SCH_SHEET_PATH& aSheetPath,
793  bool aIncludePowerSymbols,
794  bool aForceIncludeOrphanSymbols ) const
795 {
796  for( const SCH_SHEET_PATH& sheet : *this )
797  {
798  if( sheet.IsContainedWithin( aSheetPath ) )
799  sheet.GetSymbols( aReferences, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
800  }
801 }
802 
803 
805  const SCH_SHEET_PATH& aSheetPath ) const
806 {
807  for( const SCH_SHEET_PATH& sheet : *this )
808  {
809  if( sheet.IsContainedWithin( aSheetPath ) )
810  aSheets.push_back( sheet );
811  }
812 }
813 
814 
816  bool aIncludePowerSymbols ) const
817 {
818  for( SCH_SHEET_PATHS::const_iterator it = begin(); it != end(); ++it )
819  {
821  ( *it ).GetMultiUnitSymbols( tempMap );
822 
823  for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : tempMap )
824  {
825  // Merge this list into the main one
826  unsigned n_refs = pair.second.GetCount();
827 
828  for( unsigned thisRef = 0; thisRef < n_refs; ++thisRef )
829  aRefList[pair.first].AddItem( pair.second[thisRef] );
830  }
831  }
832 }
833 
834 
835 bool SCH_SHEET_LIST::TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy,
836  const wxString& aDestFileName )
837 {
838  if( empty() )
839  return false;
840 
841  SCHEMATIC* sch = at( 0 ).LastScreen()->Schematic();
842 
843  wxCHECK_MSG( sch, false, wxT( "No SCHEMATIC found in SCH_SHEET_LIST::TestForRecursion!" ) );
844 
845  wxFileName rootFn = sch->GetFileName();
846  wxFileName destFn = aDestFileName;
847 
848  if( destFn.IsRelative() )
849  destFn.MakeAbsolute( rootFn.GetPath() );
850 
851  // Test each SCH_SHEET_PATH in this SCH_SHEET_LIST for potential recursion.
852  for( unsigned i = 0; i < size(); i++ )
853  {
854  // Test each SCH_SHEET_PATH in the source sheet.
855  for( unsigned j = 0; j < aSrcSheetHierarchy.size(); j++ )
856  {
857  const SCH_SHEET_PATH* sheetPath = &aSrcSheetHierarchy[j];
858 
859  for( unsigned k = 0; k < sheetPath->size(); k++ )
860  {
861  if( at( i ).TestForRecursion( sheetPath->GetSheet( k )->GetFileName(),
862  aDestFileName ) )
863  {
864  return true;
865  }
866  }
867  }
868  }
869 
870  // The source sheet file can safely be added to the destination sheet file.
871  return false;
872 }
873 
874 
876 {
877  for( SCH_SHEET_PATH& sheetpath : *this )
878  {
879  if( sheetpath.LastScreen() == aScreen )
880  return &sheetpath;
881  }
882 
883  return nullptr;
884 }
885 
886 
888 {
889  SCH_SHEET_LIST retval;
890 
891  for( const SCH_SHEET_PATH& sheetpath : *this )
892  {
893  if( sheetpath.LastScreen() == aScreen )
894  retval.push_back( sheetpath );
895  }
896 
897  return retval;
898 }
899 
900 
902  const std::vector<SYMBOL_INSTANCE_REFERENCE>& aSymbolInstances )
903 {
904  SCH_REFERENCE_LIST symbolInstances;
905 
906  GetSymbols( symbolInstances, true, true );
907 
908  std::map<KIID_PATH, wxString> pathNameCache;
909 
910  // Calculating the name of a path is somewhat expensive; on large designs with many symbols
911  // this can blow up to a serious amount of time when loading the schematic
912  auto getName = [&pathNameCache]( const KIID_PATH& aPath ) -> const wxString&
913  {
914  if( pathNameCache.count( aPath ) )
915  return pathNameCache.at( aPath );
916 
917  pathNameCache[aPath] = aPath.AsString();
918  return pathNameCache[aPath];
919  };
920 
921  for( size_t i = 0; i < symbolInstances.GetCount(); i++ )
922  {
923  // The instance paths are stored in the file sans root path so the comparison
924  // should not include the root path.
925  wxString path = symbolInstances[i].GetPath();
926 
927  auto it = std::find_if( aSymbolInstances.begin(), aSymbolInstances.end(),
928  [ path, &getName ]( const SYMBOL_INSTANCE_REFERENCE& r ) -> bool
929  {
930  return path == getName( r.m_Path );
931  } );
932 
933  if( it == aSymbolInstances.end() )
934  {
935  wxLogTrace( traceSchSheetPaths, wxT( "No symbol instance found for path '%s'" ), path );
936  continue;
937  }
938 
939  SCH_SYMBOL* symbol = symbolInstances[ i ].GetSymbol();
940 
941  wxCHECK2( symbol, continue );
942 
943  // Symbol instance paths are stored and looked up in memory with the root path so use
944  // the full path here.
945  symbol->AddHierarchicalReference( symbolInstances[i].GetSheetPath().Path(),
946  it->m_Reference, it->m_Unit, it->m_Value,
947  it->m_Footprint );
948  symbol->GetField( REFERENCE_FIELD )->SetText( it->m_Reference );
949  }
950 }
951 
952 
953 void SCH_SHEET_LIST::UpdateSheetInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances )
954 {
955 
956  for( const SCH_SHEET_PATH& path : *this )
957  {
958  SCH_SHEET* sheet = path.Last();
959 
960  wxCHECK2( sheet, continue );
961 
962  auto it = std::find_if( aSheetInstances.begin(), aSheetInstances.end(),
963  [ path ]( const SCH_SHEET_INSTANCE& r ) -> bool
964  {
965  return path.PathWithoutRootUuid() == r.m_Path;
966  } );
967 
968  if( it == aSheetInstances.end() )
969  {
970  wxLogTrace( traceSchSheetPaths, wxT( "No sheet instance found for path '%s'" ),
971  path.PathWithoutRootUuid().AsString() );
972  continue;
973  }
974 
975  wxLogTrace( traceSchSheetPaths, wxT( "Setting sheet '%s' instance '%s' page number '%s'" ),
976  ( sheet->GetName().IsEmpty() ) ? wxT( "root" ) : sheet->GetName(),
977  path.PathWithoutRootUuid().AsString(), it->m_PageNumber );
978  sheet->AddInstance( path );
979  sheet->SetPageNumber( path, it->m_PageNumber );
980  }
981 }
982 
983 
984 std::vector<KIID_PATH> SCH_SHEET_LIST::GetPaths() const
985 {
986  std::vector<KIID_PATH> paths;
987 
988  for( const SCH_SHEET_PATH& sheetPath : *this )
989  paths.emplace_back( sheetPath.Path() );
990 
991  return paths;
992 }
993 
994 
995 std::vector<SCH_SHEET_INSTANCE> SCH_SHEET_LIST::GetSheetInstances() const
996 {
997  std::vector<SCH_SHEET_INSTANCE> retval;
998 
999  for( const SCH_SHEET_PATH& path : *this )
1000  {
1001  const SCH_SHEET* sheet = path.Last();
1002 
1003  wxCHECK2( sheet, continue );
1004 
1005  SCH_SHEET_INSTANCE instance;
1006  instance.m_Path = path.PathWithoutRootUuid();
1007  instance.m_PageNumber = sheet->GetPageNumber( path );
1008 
1009  retval.push_back( instance );
1010  }
1011 
1012  return retval;
1013 }
1014 
1015 
1017 {
1018  for( const SCH_SHEET_PATH& instance : *this )
1019  {
1020  const SCH_SHEET* sheet = instance.Last();
1021 
1022  wxCHECK2( sheet, continue );
1023 
1024  if( !sheet->GetPageNumber( instance ).IsEmpty() )
1025  return false;
1026  }
1027 
1028  return true;
1029 }
1030 
1031 
1033 {
1034  // Don't accidentally renumber existing sheets.
1035  wxCHECK( AllSheetPageNumbersEmpty(), /* void */ );
1036 
1037  wxString tmp;
1038  int pageNumber = 1;
1039 
1040  for( const SCH_SHEET_PATH& instance : *this )
1041  {
1042  SCH_SHEET* sheet = instance.Last();
1043 
1044  wxCHECK2( sheet, continue );
1045 
1046  sheet->AddInstance( instance );
1047  tmp.Printf( wxT( "%d" ), pageNumber );
1048  sheet->SetPageNumber( instance, tmp );
1049  pageNumber += 1;
1050  }
1051 }
void Move(const wxPoint &aMoveVector) override
Move the item by aMoveVector to a new position.
Field Reference of part, i.e. "IC21".
bool IsContainedWithin(const SCH_SHEET_PATH &aSheetPathToTest) const
Check if this path is contained inside aSheetPathToTest.
void SetSheetNumber(int aSheetNumber)
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:230
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...
const wxChar *const traceSchSheetPaths
Flag to enable debug output of schematic symbol sheet path manipulation code.
const wxString & GetFileName() const
Definition: sch_screen.h:145
void initFromOther(const SCH_SHEET_PATH &aOther)
bool Remove(SCH_ITEM *aItem)
Remove aItem from the schematic associated with this screen.
Definition: sch_screen.cpp:273
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
bool IsContentModified() const
Definition: base_screen.h:60
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
int ComparePageNum(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare sheets by their page number.
SCH_SHEET_PATH * FindSheetForScreen(const SCH_SCREEN *aScreen)
Return a pointer to the first SCH_SHEET_PATH object (not necessarily the only one) using a particular...
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:705
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...
Holds all the data relating to one schematic.
Definition: schematic.h:59
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.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void SetFileName(const wxString &aFilename)
Definition: sch_sheet.h:320
bool IsModified() const
Check the entire hierarchy for any modifications.
bool operator==(const SCH_SHEET_PATH &d1) const
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,...
bool PageNumberExists(const wxString &aPageNumber) const
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
wxString PathHumanReadable(bool aUseShortRootName=true) const
Return the sheet path in a human readable form made from the sheet names.
the 3d code uses this value
Definition: typeinfo.h:79
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
static int ComparePageNum(const wxString &aPageNumberA, const wxString &aPageNumberB)
Compares page numbers of schematic sheets.
Definition: sch_sheet.cpp:1227
wxString AsString() const
Definition: kiid.cpp:236
Definition: bitmap.cpp:64
std::map< std::pair< wxString, wxString >, bool > m_recursion_test_cache
Page numbers are maintained by the sheet load order.
wxString PathAsString() const
Return the path of time stamps which do not changes even when editing sheet parameters.
bool IsPower() const
Definition: lib_symbol.cpp:459
A singleton item of this class is returned for a weak reference that no longer exists.
void AddItem(const SCH_REFERENCE &aItem)
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:464
void UpdateAllScreenReferences()
Update all the symbol references for this sheet path.
int GetVirtualPageNumber() const
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:102
Define a library symbol object.
Definition: lib_symbol.h:96
wxString GetClass() const override
Return the class name.
void SetPageNumber(const SCH_SHEET_PATH &aInstance, const wxString &aPageNumber)
Set the page number for the sheet instance aInstance.
Definition: sch_sheet.cpp:1210
void UpdateSheetInstances(const std::vector< SCH_SHEET_INSTANCE > &aSheetInstances)
Update all of the sheet instance information using aSheetInstances.
static void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
Definition: hash_eda.h:67
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:165
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
void UpdateUnit(int aUnit)
Change the unit number to aUnit without setting any internal flags.
Definition: sch_symbol.cpp:364
void Print(const RENDER_SETTINGS *aSettings, const wxPoint &aOffset) override
Print a schematic item.
void pop_back()
Forwarded method from std::vector.
std::vector< SCH_FIELD > & GetFields()
Definition: sch_sheet.h:90
wxString GetRef() const
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Fill an item cache for temporary use when many items need to be fetched.
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction)
Definition: sch_item.h:444
Definition: kiid.h:44
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...
void UpdateAnnotation()
Update the symbol references for the schematic project (or the current sheet).
SCH_SHEET_PATH & operator=(const SCH_SHEET_PATH &aOther)
Field Value of part, i.e. "3.3K".
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:124
wxString GetName() const
Definition: sch_sheet.h:100
size_t size() const
Forwarded method from std::vector.
std::vector< SCH_SHEET_PATH > SCH_SHEET_PATHS
SCH_SHEET_PATH m_currentSheetPath
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
void SetVirtualPageNumber(int aPageNumber)
Set the sheet instance virtual page number.
std::vector< SCH_SHEET * > m_sheets
wxString GetPageNumber() const
bool IsRootSheet() const
Definition: sch_sheet.cpp:207
size_t operator()(const SCH_SHEET_PATH &path) const
int GetUnitCount() const override
For items with units, return the number of units.
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:554
void BuildSheetList(SCH_SHEET *aSheet, bool aCheckIntegrity)
Build the list of sheets and their sheet path from aSheet.
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-...
bool NameExists(const wxString &aSheetName) const
A simple container for schematic symbol instance information.
size_t GetCount() const
Definition for symbol library class.
#define _(s)
std::vector< SCH_SHEET_INSTANCE > GetSheetInstances() const
Fetch the instance information for all of the sheets in the hiearchy.
wxLogTrace helper definitions.
void SetPosition(const wxPoint &) override
wxString GetFileName() const override
Helper to retrieve the filename from the root sheet screen.
Definition: schematic.cpp:161
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:314
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.
const wxString GetValue(const SCH_SHEET_PATH *sheet, bool aResolve) const
Return the instance-specific value for the given sheet path.
Definition: sch_symbol.cpp:596
E_SERIE r
Definition: eserie.cpp:41
void UpdateSymbolInstances(const std::vector< SYMBOL_INSTANCE_REFERENCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Container to map reference designators for multi-unit parts.
KIID_PATH PathWithoutRootUuid() const
Get the sheet path as an KIID_PATH without the root sheet UUID prefix.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
const KIID m_Uuid
Definition: eda_item.h:474
void SetContentModified(bool aModified=true)
Definition: base_screen.h:59
void MakeFilePathRelativeToParentSheet()
Make the sheet file name relative to its parent sheet.
EDA_UNITS
Definition: eda_units.h:38
SCH_ITEM * GetItem(const KIID &aID, SCH_SHEET_PATH *aPathOut=nullptr) const
Fetch a SCH_ITEM by ID.
void Rotate(const wxPoint &aCenter) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
bool AllSheetPageNumbersEmpty() const
Check all of the sheet instance for empty page numbers.
A simple container for sheet instance information.
const SCH_SHEET * GetSheet(unsigned aIndex) const
void Annotate(bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent=false)
Set the reference designators in the list that have not been annotated.
Schematic symbol object.
Definition: sch_symbol.h:78
SCH_SCREEN * LastScreen()
static DELETED_SHEET_ITEM * GetInstance()
void SplitReferences()
Attempt to split all reference designators into a name (U) and number (1).
SCHEMATIC * Schematic() const
Definition: sch_screen.cpp:92
SCH_SHEET_LIST(SCH_SHEET *aSheet=nullptr, bool aCheckIntegrity=false)
Construct a flattened list of SCH_SHEET_PATH objects from aSheet.
size_t GetCurrentHash() const
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
SCH_SHEET * at(size_t aIndex) 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.
void SortByPageNumbers(bool aUpdateVirtualPageNums=true)
Sort the list of sheets by page number.
std::vector< KIID_PATH > GetPaths() const
static bool empty(const wxTextEntryBase *aCtrl)
const wxString GetFootprint(const SCH_SHEET_PATH *sheet, bool aResolve) const
Return the instance-specific footprint assignment for the given sheet path.
Definition: sch_symbol.cpp:654
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit, const wxString &aValue=wxEmptyString, const wxString &aFootprint=wxEmptyString)
Add a full hierarchical reference to this symbol.
Definition: sch_symbol.cpp:423
bool empty() const
Forwarded method from std::vector.
void AnnotatePowerSymbols()
Silently annotate the not yet annotated power symbols of the entire hierarchy of the sheet path list.
bool IsFullPath() const
wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Return the text to display to be used in the selection clarification context menu when multiple items...
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...
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
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 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...
int Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare if this is the same sheet path as aSheetPathToTest.
void SetInitialPageNumbers()
Set initial sheet page numbers.
wxString GetPageNumber(const SCH_SHEET_PATH &aInstance) const
Return the sheet page number for aInstance.
Definition: sch_sheet.cpp:1190
A helper to define a symbol's reference designator in a schematic.
bool AddInstance(const SCH_SHEET_PATH &aInstance)
Add a new instance aSheetPath to the instance list.
Definition: sch_sheet.cpp:1165
void GetSheetsWithinPath(SCH_SHEET_PATHS &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...
Field Name Module PCB, i.e. "16DIP300".