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  return virtualPageA > virtualPageB ? 1 : -1;
179  }
180  else
181  {
182  return pageNumComp;
183  }
184 }
185 
186 
187 bool SCH_SHEET_PATH::IsContainedWithin( const SCH_SHEET_PATH& aSheetPathToTest ) const
188 {
189  if( aSheetPathToTest.size() > size() )
190  return false;
191 
192  for( size_t i = 0; i < aSheetPathToTest.size(); ++i )
193  {
194  if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
195  return false;
196  }
197 
198  return true;
199 }
200 
201 
203 {
204  if( !empty() )
205  return m_sheets.back();
206 
207  return nullptr;
208 }
209 
210 
212 {
213  SCH_SHEET* lastSheet = Last();
214 
215  if( lastSheet )
216  return lastSheet->GetScreen();
217 
218  return nullptr;
219 }
220 
221 
223 {
224  SCH_SHEET* lastSheet = Last();
225 
226  if( lastSheet )
227  return lastSheet->GetScreen();
228 
229  return nullptr;
230 }
231 
232 
234 {
235  wxString s;
236 
237  s = wxT( "/" ); // This is the root path
238 
239  // Start at 1 to avoid the root sheet, which does not need to be added to the path.
240  // Its timestamp changes anyway.
241  for( unsigned i = 1; i < size(); i++ )
242  s += at( i )->m_Uuid.AsString() + "/";
243 
244  return s;
245 }
246 
247 
249 {
250  KIID_PATH path;
251 
252  for( const SCH_SHEET* sheet : m_sheets )
253  path.push_back( sheet->m_Uuid );
254 
255  return path;
256 }
257 
258 
260 {
261  KIID_PATH path;
262 
263  for( size_t i = 1; i < size(); i++ )
264  path.push_back( at( i )->m_Uuid );
265 
266  return path;
267 }
268 
269 
270 wxString SCH_SHEET_PATH::PathHumanReadable( bool aUseShortRootName ) const
271 {
272  wxString s;
273  wxString fileName;
274 
275  if( !empty() && at( 0 )->GetScreen() )
276  fileName = at( 0 )->GetScreen()->GetFileName();
277 
278  wxFileName fn = fileName;
279 
280  if( aUseShortRootName )
281  s = wxT( "/" ); // Use only the short name in netlists
282  else
283  s = fn.GetName() + wxT( "/" );
284 
285  // Start at 1 since we've already processed the root sheet.
286  for( unsigned i = 1; i < size(); i++ )
287  s = s + at( i )->GetFields()[ SHEETNAME ].GetShownText() + wxT( "/" );
288 
289  return s;
290 }
291 
292 
294 {
295  for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
296  {
297  SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
298  symbol->GetField( REFERENCE_FIELD )->SetText( symbol->GetRef( this ) );
299  symbol->GetField( VALUE_FIELD )->SetText( symbol->GetValue( this, false ) );
300  symbol->GetField( FOOTPRINT_FIELD )->SetText( symbol->GetFootprint( this, false ) );
301  symbol->UpdateUnit( symbol->GetUnitSelection( this ) );
302  }
303 }
304 
305 
306 
307 void SCH_SHEET_PATH::GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols,
308  bool aForceIncludeOrphanSymbols ) const
309 {
310  for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
311  {
312  SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
313  AppendSymbol( aReferences, symbol, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
314  }
315 }
316 
317 
319  bool aIncludePowerSymbols,
320  bool aForceIncludeOrphanSymbols ) const
321 {
322  // Skip pseudo-symbols, which have a reference starting with #. This mainly
323  // affects power symbols.
324  if( aIncludePowerSymbols || aSymbol->GetRef( this )[0] != wxT( '#' ) )
325  {
326  LIB_SYMBOL* symbol = aSymbol->GetLibSymbolRef().get();
327 
328  if( symbol || aForceIncludeOrphanSymbols )
329  {
330  SCH_REFERENCE schReference( aSymbol, symbol, *this );
331 
332  schReference.SetSheetNumber( m_virtualPageNumber );
333  aReferences.AddItem( schReference );
334  }
335  }
336 }
337 
338 
340  bool aIncludePowerSymbols ) const
341 {
342  for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
343  {
344  SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
345  AppendMultiUnitSymbol( aRefList, symbol, aIncludePowerSymbols );
346  }
347 }
348 
349 
351  SCH_SYMBOL* aSymbol,
352  bool aIncludePowerSymbols ) const
353 {
354  // Skip pseudo-symbols, which have a reference starting with #. This mainly
355  // affects power symbols.
356  if( !aIncludePowerSymbols && aSymbol->GetRef( this )[0] == wxT( '#' ) )
357  return;
358 
359  LIB_SYMBOL* symbol = aSymbol->GetLibSymbolRef().get();
360 
361  if( symbol && symbol->GetUnitCount() > 1 )
362  {
363  SCH_REFERENCE schReference = SCH_REFERENCE( aSymbol, symbol, *this );
364  schReference.SetSheetNumber( m_virtualPageNumber );
365  wxString reference_str = schReference.GetRef();
366 
367  // Never lock unassigned references
368  if( reference_str[reference_str.Len() - 1] == '?' )
369  return;
370 
371  aRefList[reference_str].AddItem( schReference );
372  }
373 }
374 
375 
377 {
378  return m_current_hash == d1.GetCurrentHash();
379 }
380 
381 
382 bool SCH_SHEET_PATH::TestForRecursion( const wxString& aSrcFileName, const wxString& aDestFileName )
383 {
384  auto pair = std::make_pair( aSrcFileName, aDestFileName );
385 
386  if( m_recursion_test_cache.count( pair ) )
387  return m_recursion_test_cache.at( pair );
388 
389  SCHEMATIC* sch = LastScreen()->Schematic();
390 
391  wxCHECK_MSG( sch, false, "No SCHEMATIC found in SCH_SHEET_PATH::TestForRecursion!" );
392 
393  wxFileName rootFn = sch->GetFileName();
394  wxFileName srcFn = aSrcFileName;
395  wxFileName destFn = aDestFileName;
396 
397  if( srcFn.IsRelative() )
398  srcFn.MakeAbsolute( rootFn.GetPath() );
399 
400  if( destFn.IsRelative() )
401  destFn.MakeAbsolute( rootFn.GetPath() );
402 
403 
404  // The source and destination sheet file names cannot be the same.
405  if( srcFn == destFn )
406  {
407  m_recursion_test_cache[pair] = true;
408  return true;
409  }
410 
414  unsigned i = 0;
415 
416  while( i < size() )
417  {
418  wxFileName cmpFn = at( i )->GetFileName();
419 
420  if( cmpFn.IsRelative() )
421  cmpFn.MakeAbsolute( rootFn.GetPath() );
422 
423  // Test if the file name of the destination sheet is in anywhere in this sheet path.
424  if( cmpFn == destFn )
425  break;
426 
427  i++;
428  }
429 
430  // The destination sheet file name was not found in the sheet path or the destination
431  // sheet file name is the root sheet so no recursion is possible.
432  if( i >= size() || i == 0 )
433  {
434  m_recursion_test_cache[pair] = false;
435  return false;
436  }
437 
438  // Walk back up to the root sheet to see if the source file name is already a parent in
439  // the sheet path. If so, recursion will occur.
440  do
441  {
442  i -= 1;
443 
444  wxFileName cmpFn = at( i )->GetFileName();
445 
446  if( cmpFn.IsRelative() )
447  cmpFn.MakeAbsolute( rootFn.GetPath() );
448 
449  if( cmpFn == srcFn )
450  {
451  m_recursion_test_cache[pair] = true;
452  return true;
453  }
454 
455  } while( i != 0 );
456 
457  // The source sheet file name is not a parent of the destination sheet file name.
458  m_recursion_test_cache[pair] = false;
459  return false;
460 }
461 
462 
464 {
465  SCH_SHEET* sheet = Last();
466 
467  wxCHECK( sheet, wxEmptyString );
468 
469  return sheet->GetPageNumber( *this );
470 }
471 
472 
473 void SCH_SHEET_PATH::SetPageNumber( const wxString& aPageNumber )
474 {
475  SCH_SHEET* sheet = Last();
476 
477  wxCHECK( sheet, /* void */ );
478 
479  sheet->SetPageNumber( *this, aPageNumber );
480 }
481 
482 
484 {
485  wxCHECK( m_sheets.size() > 1, /* void */ );
486 
487  wxFileName sheetFileName = Last()->GetFileName();
488 
489  // If the sheet file name is absolute, then the user requested is so don't make it relative.
490  if( sheetFileName.IsAbsolute() )
491  return;
492 
493  SCH_SCREEN* screen = LastScreen();
494  SCH_SCREEN* parentScreen = m_sheets[ m_sheets.size() - 2 ]->GetScreen();
495 
496  wxCHECK( screen && parentScreen, /* void */ );
497 
498  wxFileName fileName = screen->GetFileName();
499  wxFileName parentFileName = parentScreen->GetFileName();
500 
501  // SCH_SCREEN file names must be absolute. If they are not, someone set them incorrectly
502  // on load or on creation.
503  wxCHECK( fileName.IsAbsolute() && parentFileName.IsAbsolute(), /* void */ );
504 
505  if( fileName.GetPath() == parentFileName.GetPath() )
506  {
507  Last()->SetFileName( fileName.GetFullName() );
508  }
509  else if( fileName.MakeRelativeTo( parentFileName.GetPath() ) )
510  {
511  Last()->SetFileName( fileName.GetFullPath() );
512  }
513  else
514  {
515  Last()->SetFileName( screen->GetFileName() );
516  }
517 
518  wxLogTrace( tracePathsAndFiles,
519  wxT( "\n File name: '%s'"
520  "\n parent file name '%s',"
521  "\n sheet '%s' file name '%s'." ),
522  screen->GetFileName(), parentScreen->GetFileName(), PathHumanReadable(),
523  Last()->GetFileName() );
524 }
525 
526 
527 SCH_SHEET_LIST::SCH_SHEET_LIST( SCH_SHEET* aSheet, bool aCheckIntegrity )
528 {
529  if( aSheet != nullptr )
530  {
531  BuildSheetList( aSheet, aCheckIntegrity );
532 
533  if( aSheet->IsRootSheet() )
535  }
536 }
537 
538 
539 void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity )
540 {
541  wxCHECK_RET( aSheet != nullptr, wxT( "Cannot build sheet list from undefined sheet." ) );
542 
543  std::vector<SCH_SHEET*> badSheets;
544 
545  m_currentSheetPath.push_back( aSheet );
546  m_currentSheetPath.SetVirtualPageNumber( static_cast<int>( size() ) + 1 );
547  push_back( m_currentSheetPath );
548 
550  {
551  wxString parentFileName = aSheet->GetFileName();
552  std::vector<SCH_ITEM*> childSheets;
553  m_currentSheetPath.LastScreen()->GetSheets( &childSheets );
554 
555  for( SCH_ITEM* item : childSheets )
556  {
557  SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
558 
559  if( aCheckIntegrity )
560  {
561  if( !m_currentSheetPath.TestForRecursion( sheet->GetFileName(), parentFileName ) )
562  BuildSheetList( sheet, true );
563  else
564  badSheets.push_back( sheet );
565  }
566  else
567  {
568  BuildSheetList( sheet, false );
569  }
570  }
571  }
572 
573  if( aCheckIntegrity )
574  {
575  for( SCH_SHEET* sheet : badSheets )
576  {
579  }
580  }
581 
583 }
584 
585 
586 void SCH_SHEET_LIST::SortByPageNumbers( bool aUpdateVirtualPageNums )
587 {
588  std::sort( begin(), end(),
589  []( SCH_SHEET_PATH a, SCH_SHEET_PATH b ) -> bool
590  {
591  return a.ComparePageNum( b ) < 0;
592  } );
593 
594  if( aUpdateVirtualPageNums )
595  {
596  int virtualPageNum = 1;
597 
598  for( SCH_SHEET_PATH& sheet : *this )
599  {
600  sheet.SetVirtualPageNumber( virtualPageNum++ );
601  }
602  }
603 }
604 
605 
606 bool SCH_SHEET_LIST::NameExists( const wxString& aSheetName ) const
607 {
608  for( const SCH_SHEET_PATH& sheet : *this )
609  {
610  if( sheet.Last()->GetName() == aSheetName )
611  return true;
612  }
613 
614  return false;
615 }
616 
617 
618 bool SCH_SHEET_LIST::PageNumberExists( const wxString& aPageNumber ) const
619 {
620  for( const SCH_SHEET_PATH& sheet : *this )
621  {
622  if( sheet.GetPageNumber() == aPageNumber )
623  return true;
624  }
625 
626  return false;
627 }
628 
629 
631 {
632  for( const SCH_SHEET_PATH& sheet : *this )
633  {
634  if( sheet.LastScreen() && sheet.LastScreen()->IsContentModified() )
635  return true;
636  }
637 
638  return false;
639 }
640 
641 
643 {
644  for( const SCH_SHEET_PATH& sheet : *this )
645  {
646  if( sheet.LastScreen() )
647  sheet.LastScreen()->SetContentModified( false );
648  }
649 }
650 
651 
652 SCH_ITEM* SCH_SHEET_LIST::GetItem( const KIID& aID, SCH_SHEET_PATH* aPathOut ) const
653 {
654  for( const SCH_SHEET_PATH& sheet : *this )
655  {
656  SCH_SCREEN* screen = sheet.LastScreen();
657 
658  for( SCH_ITEM* aItem : screen->Items() )
659  {
660  if( aItem->m_Uuid == aID )
661  {
662  if( aPathOut )
663  *aPathOut = sheet;
664 
665  return aItem;
666  }
667 
668  SCH_ITEM* childMatch = nullptr;
669 
670  aItem->RunOnChildren(
671  [&]( SCH_ITEM* aChild )
672  {
673  if( aChild->m_Uuid == aID )
674  childMatch = aChild;
675  } );
676 
677  if( childMatch )
678  {
679  if( aPathOut )
680  *aPathOut = sheet;
681 
682  return childMatch;
683  }
684  }
685  }
686 
687  // Not found; weak reference has been deleted.
689 }
690 
691 
692 void SCH_SHEET_LIST::FillItemMap( std::map<KIID, EDA_ITEM*>& aMap )
693 {
694  for( const SCH_SHEET_PATH& sheet : *this )
695  {
696  SCH_SCREEN* screen = sheet.LastScreen();
697 
698  for( SCH_ITEM* aItem : screen->Items() )
699  {
700  aMap[ aItem->m_Uuid ] = aItem;
701 
702  aItem->RunOnChildren(
703  [&]( SCH_ITEM* aChild )
704  {
705  aMap[ aChild->m_Uuid ] = aChild;
706  } );
707  }
708  }
709 }
710 
711 
713 {
714  // List of reference for power symbols
715  SCH_REFERENCE_LIST references;
716  SCH_REFERENCE_LIST additionalreferences; // Todo: add as a parameter to this function
717 
718  // Map of locked symbols (not used, but needed by Annotate()
719  SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
720 
721  // Build the list of power symbols:
722  for( SCH_SHEET_PATH& sheet : *this )
723  {
724  for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
725  {
726  SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
727  LIB_SYMBOL* libSymbol = symbol->GetLibSymbolRef().get();
728 
729  if( libSymbol && libSymbol->IsPower() )
730  {
731  SCH_REFERENCE schReference( symbol, libSymbol, sheet );
732  references.AddItem( schReference );
733  }
734  }
735  }
736 
737  // Find duplicate, and silently clear annotation of duplicate
738  std::map<wxString, int> ref_list; // stores the existing references
739 
740  for( unsigned ii = 0; ii< references.GetCount(); ++ii )
741  {
742  wxString curr_ref = references[ii].GetRef();
743 
744  if( ref_list.find( curr_ref ) == ref_list.end() )
745  {
746  ref_list[curr_ref] = ii;
747  continue;
748  }
749 
750  // Possible duplicate, if the ref ends by a number:
751  if( curr_ref.Last() < '0' && curr_ref.Last() > '9' )
752  continue; // not annotated
753 
754  // Duplicate: clear annotation by removing the number ending the ref
755  while( curr_ref.Last() >= '0' && curr_ref.Last() <= '9' )
756  curr_ref.RemoveLast();
757 
758  references[ii].SetRef( curr_ref );
759  }
760 
761  // Break full symbol reference into name (prefix) and number:
762  // example: IC1 become IC, and 1
763  references.SplitReferences();
764 
765  // Ensure all power symbols have the reference starting by '#'
766  // (Not sure this is really useful)
767  for( unsigned ii = 0; ii< references.GetCount(); ++ii )
768  {
769  if( references[ii].GetRef()[0] != '#' )
770  {
771  wxString new_ref = "#" + references[ii].GetRef();
772  references[ii].SetRef( new_ref );
773  }
774  }
775 
776  // Recalculate and update reference numbers in schematic
777  references.Annotate( false, 0, 100, lockedSymbols, additionalreferences );
778  references.UpdateAnnotation();
779 }
780 
781 
782 void SCH_SHEET_LIST::GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols,
783  bool aForceIncludeOrphanSymbols ) const
784 {
785  for( const SCH_SHEET_PATH& sheet : *this )
786  sheet.GetSymbols( aReferences, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
787 }
788 
789 
791  const SCH_SHEET_PATH& aSheetPath,
792  bool aIncludePowerSymbols,
793  bool aForceIncludeOrphanSymbols ) const
794 {
795  for( const SCH_SHEET_PATH& sheet : *this )
796  {
797  if( sheet.IsContainedWithin( aSheetPath ) )
798  sheet.GetSymbols( aReferences, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
799  }
800 }
801 
802 
804  const SCH_SHEET_PATH& aSheetPath ) const
805 {
806  for( const SCH_SHEET_PATH& sheet : *this )
807  {
808  if( sheet.IsContainedWithin( aSheetPath ) )
809  aSheets.push_back( sheet );
810  }
811 }
812 
813 
815  bool aIncludePowerSymbols ) const
816 {
817  for( SCH_SHEET_PATHS::const_iterator it = begin(); it != end(); ++it )
818  {
820  ( *it ).GetMultiUnitSymbols( tempMap );
821 
822  for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : tempMap )
823  {
824  // Merge this list into the main one
825  unsigned n_refs = pair.second.GetCount();
826 
827  for( unsigned thisRef = 0; thisRef < n_refs; ++thisRef )
828  aRefList[pair.first].AddItem( pair.second[thisRef] );
829  }
830  }
831 }
832 
833 
834 bool SCH_SHEET_LIST::TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy,
835  const wxString& aDestFileName )
836 {
837  if( empty() )
838  return false;
839 
840  SCHEMATIC* sch = at( 0 ).LastScreen()->Schematic();
841 
842  wxCHECK_MSG( sch, false, "No SCHEMATIC found in SCH_SHEET_LIST::TestForRecursion!" );
843 
844  wxFileName rootFn = sch->GetFileName();
845  wxFileName destFn = aDestFileName;
846 
847  if( destFn.IsRelative() )
848  destFn.MakeAbsolute( rootFn.GetPath() );
849 
850  // Test each SCH_SHEET_PATH in this SCH_SHEET_LIST for potential recursion.
851  for( unsigned i = 0; i < size(); i++ )
852  {
853  // Test each SCH_SHEET_PATH in the source sheet.
854  for( unsigned j = 0; j < aSrcSheetHierarchy.size(); j++ )
855  {
856  const SCH_SHEET_PATH* sheetPath = &aSrcSheetHierarchy[j];
857 
858  for( unsigned k = 0; k < sheetPath->size(); k++ )
859  {
860  if( at( i ).TestForRecursion( sheetPath->GetSheet( k )->GetFileName(),
861  aDestFileName ) )
862  {
863  return true;
864  }
865  }
866  }
867  }
868 
869  // The source sheet file can safely be added to the destination sheet file.
870  return false;
871 }
872 
873 
875 {
876  for( SCH_SHEET_PATH& sheetpath : *this )
877  {
878  if( sheetpath.LastScreen() == aScreen )
879  return &sheetpath;
880  }
881 
882  return nullptr;
883 }
884 
885 
887 {
888  SCH_SHEET_LIST retval;
889 
890  for( const SCH_SHEET_PATH& sheetpath : *this )
891  {
892  if( sheetpath.LastScreen() == aScreen )
893  retval.push_back( sheetpath );
894  }
895 
896  return retval;
897 }
898 
899 
901  const std::vector<SYMBOL_INSTANCE_REFERENCE>& aSymbolInstances )
902 {
903  SCH_REFERENCE_LIST symbolInstances;
904 
905  GetSymbols( symbolInstances, true, true );
906 
907  std::map<KIID_PATH, wxString> pathNameCache;
908 
909  // Calculating the name of a path is somewhat expensive; on large designs with many symbols
910  // this can blow up to a serious amount of time when loading the schematic
911  auto getName = [&pathNameCache]( const KIID_PATH& aPath ) -> const wxString&
912  {
913  if( pathNameCache.count( aPath ) )
914  return pathNameCache.at( aPath );
915 
916  pathNameCache[aPath] = aPath.AsString();
917  return pathNameCache[aPath];
918  };
919 
920  for( size_t i = 0; i < symbolInstances.GetCount(); i++ )
921  {
922  // The instance paths are stored in the file sans root path so the comparison
923  // should not include the root path.
924  wxString path = symbolInstances[i].GetPath();
925 
926  auto it = std::find_if( aSymbolInstances.begin(), aSymbolInstances.end(),
927  [ path, &getName ]( const SYMBOL_INSTANCE_REFERENCE& r ) -> bool
928  {
929  return path == getName( r.m_Path );
930  } );
931 
932  if( it == aSymbolInstances.end() )
933  {
934  wxLogTrace( traceSchSheetPaths, "No symbol instance found for path '%s'", path );
935  continue;
936  }
937 
938  SCH_SYMBOL* symbol = symbolInstances[ i ].GetSymbol();
939 
940  wxCHECK2( symbol, continue );
941 
942  // Symbol instance paths are stored and looked up in memory with the root path so use
943  // the full path here.
944  symbol->AddHierarchicalReference( symbolInstances[i].GetSheetPath().Path(),
945  it->m_Reference, it->m_Unit, it->m_Value,
946  it->m_Footprint );
947  symbol->GetField( REFERENCE_FIELD )->SetText( it->m_Reference );
948  }
949 }
950 
951 
952 void SCH_SHEET_LIST::UpdateSheetInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances )
953 {
954 
955  for( const SCH_SHEET_PATH& path : *this )
956  {
957  SCH_SHEET* sheet = path.Last();
958 
959  wxCHECK2( sheet, continue );
960 
961  auto it = std::find_if( aSheetInstances.begin(), aSheetInstances.end(),
962  [ path ]( const SCH_SHEET_INSTANCE& r ) -> bool
963  {
964  return path.PathWithoutRootUuid() == r.m_Path;
965  } );
966 
967  if( it == aSheetInstances.end() )
968  {
969  wxLogTrace( traceSchSheetPaths, "No sheet instance found for path '%s'",
970  path.PathWithoutRootUuid().AsString() );
971  continue;
972  }
973 
974  wxLogTrace( traceSchSheetPaths, "Setting sheet '%s' instance '%s' page number '%s'",
975  ( sheet->GetName().IsEmpty() ) ? wxT( "root" ) : sheet->GetName(),
976  path.PathWithoutRootUuid().AsString(), it->m_PageNumber );
977  sheet->AddInstance( path );
978  sheet->SetPageNumber( path, it->m_PageNumber );
979  }
980 }
981 
982 
983 std::vector<KIID_PATH> SCH_SHEET_LIST::GetPaths() const
984 {
985  std::vector<KIID_PATH> paths;
986 
987  for( const SCH_SHEET_PATH& sheetPath : *this )
988  paths.emplace_back( sheetPath.Path() );
989 
990  return paths;
991 }
992 
993 
994 std::vector<SCH_SHEET_INSTANCE> SCH_SHEET_LIST::GetSheetInstances() const
995 {
996  std::vector<SCH_SHEET_INSTANCE> retval;
997 
998  for( const SCH_SHEET_PATH& path : *this )
999  {
1000  const SCH_SHEET* sheet = path.Last();
1001 
1002  wxCHECK2( sheet, continue );
1003 
1004  SCH_SHEET_INSTANCE instance;
1005  instance.m_Path = path.PathWithoutRootUuid();
1006  instance.m_PageNumber = sheet->GetPageNumber( path );
1007 
1008  retval.push_back( instance );
1009  }
1010 
1011  return retval;
1012 }
1013 
1014 
1016 {
1017  for( const SCH_SHEET_PATH& instance : *this )
1018  {
1019  const SCH_SHEET* sheet = instance.Last();
1020 
1021  wxCHECK2( sheet, continue );
1022 
1023  if( !sheet->GetPageNumber( instance ).IsEmpty() )
1024  return false;
1025  }
1026 
1027  return true;
1028 }
1029 
1030 
1032 {
1033  // Don't accidentally renumber existing sheets.
1034  wxCHECK( AllSheetPageNumbersEmpty(), /* void */ );
1035 
1036  wxString tmp;
1037  int pageNumber = 1;
1038 
1039  for( const SCH_SHEET_PATH& instance : *this )
1040  {
1041  SCH_SHEET* sheet = instance.Last();
1042 
1043  wxCHECK2( sheet, continue );
1044 
1045  sheet->AddInstance( instance );
1046  tmp.Printf( "%d", pageNumber );
1047  sheet->SetPageNumber( instance, tmp );
1048  pageNumber += 1;
1049  }
1050 }
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:677
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:323
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:1200
wxString AsString() const
Definition: kiid.cpp:230
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:444
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:443
void UpdateAllScreenReferences()
Update all the symbol references for this sheet path.
int GetVirtualPageNumber() const
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:105
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:1183
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:164
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:343
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:103
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:204
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:533
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:317
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:575
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:626
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:402
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:1163
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:1138
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".