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