You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

902 lines
22 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 1992-2011 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. * @file sch_sheet_path.cpp
  27. * @brief SCH_SHEET_PATH class implementation.
  28. */
  29. #include <fctsys.h>
  30. #include <general.h>
  31. #include <dlist.h>
  32. #include <class_sch_screen.h>
  33. #include <sch_item_struct.h>
  34. #include <sch_reference_list.h>
  35. #include <class_library.h>
  36. #include <sch_sheet.h>
  37. #include <sch_sheet_path.h>
  38. #include <sch_component.h>
  39. #include <template_fieldnames.h>
  40. #include <dialogs/dialog_schematic_find.h>
  41. #include <boost/foreach.hpp>
  42. #include <wx/filename.h>
  43. SCH_SHEET_PATH::SCH_SHEET_PATH()
  44. {
  45. for( int i = 0; i<DSLSZ; i++ )
  46. m_sheets[i] = NULL;
  47. m_numSheets = 0;
  48. }
  49. bool SCH_SHEET_PATH::BuildSheetPathInfoFromSheetPathValue( const wxString& aPath, bool aFound )
  50. {
  51. if( aFound )
  52. return true;
  53. if( GetCount() == 0 )
  54. Push( g_RootSheet );
  55. if( aPath == Path() )
  56. return true;
  57. SCH_ITEM* schitem = LastDrawList();
  58. while( schitem && GetCount() < NB_MAX_SHEET )
  59. {
  60. if( schitem->Type() == SCH_SHEET_T )
  61. {
  62. SCH_SHEET* sheet = (SCH_SHEET*) schitem;
  63. Push( sheet );
  64. if( aPath == Path() )
  65. return true;
  66. if( BuildSheetPathInfoFromSheetPathValue( aPath ) )
  67. return true;
  68. Pop();
  69. }
  70. schitem = schitem->Next();
  71. }
  72. return false;
  73. }
  74. int SCH_SHEET_PATH::Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const
  75. {
  76. if( m_numSheets > aSheetPathToTest.m_numSheets )
  77. return 1;
  78. if( m_numSheets < aSheetPathToTest.m_numSheets )
  79. return -1;
  80. //otherwise, same number of sheets.
  81. for( unsigned i = 0; i<m_numSheets; i++ )
  82. {
  83. if( m_sheets[i]->GetTimeStamp() > aSheetPathToTest.m_sheets[i]->GetTimeStamp() )
  84. return 1;
  85. if( m_sheets[i]->GetTimeStamp() < aSheetPathToTest.m_sheets[i]->GetTimeStamp() )
  86. return -1;
  87. }
  88. return 0;
  89. }
  90. SCH_SHEET* SCH_SHEET_PATH::Last() const
  91. {
  92. if( m_numSheets )
  93. return m_sheets[m_numSheets - 1];
  94. return NULL;
  95. }
  96. SCH_SCREEN* SCH_SHEET_PATH::LastScreen() const
  97. {
  98. SCH_SHEET* lastSheet = Last();
  99. if( lastSheet )
  100. return lastSheet->GetScreen();
  101. return NULL;
  102. }
  103. SCH_ITEM* SCH_SHEET_PATH::LastDrawList() const
  104. {
  105. SCH_SHEET* lastSheet = Last();
  106. if( lastSheet && lastSheet->GetScreen() )
  107. return lastSheet->GetScreen()->GetDrawItems();
  108. return NULL;
  109. }
  110. SCH_ITEM* SCH_SHEET_PATH::FirstDrawList() const
  111. {
  112. SCH_ITEM* item = NULL;
  113. if( m_numSheets && m_sheets[0]->GetScreen() )
  114. item = m_sheets[0]->GetScreen()->GetDrawItems();
  115. /* @fixme - These lists really should be one of the boost pointer containers. This
  116. * is a brain dead hack to allow reverse iteration of EDA_ITEM linked
  117. * list.
  118. */
  119. SCH_ITEM* lastItem = NULL;
  120. while( item )
  121. {
  122. lastItem = item;
  123. item = item->Next();
  124. }
  125. return lastItem;
  126. }
  127. void SCH_SHEET_PATH::Push( SCH_SHEET* aSheet )
  128. {
  129. wxCHECK_RET( m_numSheets < DSLSZ,
  130. wxString::Format( _( "Schematic sheets can only be nested %d levels deep." ),
  131. DSLSZ ) );
  132. m_sheets[ m_numSheets ] = aSheet;
  133. m_numSheets++;
  134. }
  135. SCH_SHEET* SCH_SHEET_PATH::Pop()
  136. {
  137. if( m_numSheets > 0 )
  138. {
  139. m_numSheets--;
  140. return m_sheets[m_numSheets];
  141. }
  142. return NULL;
  143. }
  144. wxString SCH_SHEET_PATH::Path() const
  145. {
  146. wxString s, t;
  147. s = wxT( "/" ); // This is the root path
  148. // start at 1 to avoid the root sheet,
  149. // which does not need to be added to the path
  150. // it's timestamp changes anyway.
  151. for( unsigned i = 1; i < m_numSheets; i++ )
  152. {
  153. t.Printf( _( "%8.8lX/" ), (long unsigned) m_sheets[i]->GetTimeStamp() );
  154. s = s + t;
  155. }
  156. return s;
  157. }
  158. wxString SCH_SHEET_PATH::PathHumanReadable() const
  159. {
  160. wxString s;
  161. s = wxT( "/" );
  162. // start at 1 to avoid the root sheet, as above.
  163. for( unsigned i = 1; i< m_numSheets; i++ )
  164. {
  165. s = s + m_sheets[i]->GetName() + wxT( "/" );
  166. }
  167. return s;
  168. }
  169. void SCH_SHEET_PATH::UpdateAllScreenReferences()
  170. {
  171. EDA_ITEM* t = LastDrawList();
  172. while( t )
  173. {
  174. if( t->Type() == SCH_COMPONENT_T )
  175. {
  176. SCH_COMPONENT* component = (SCH_COMPONENT*) t;
  177. component->GetField( REFERENCE )->SetText( component->GetRef( this ) );
  178. component->UpdateUnit( component->GetUnitSelection( this ) );
  179. }
  180. t = t->Next();
  181. }
  182. }
  183. void SCH_SHEET_PATH::AnnotatePowerSymbols( PART_LIBS* aLibs, int* aReference )
  184. {
  185. int ref = 1;
  186. if( aReference )
  187. ref = *aReference;
  188. for( EDA_ITEM* item = LastDrawList(); item; item = item->Next() )
  189. {
  190. if( item->Type() != SCH_COMPONENT_T )
  191. continue;
  192. SCH_COMPONENT* component = (SCH_COMPONENT*) item;
  193. LIB_PART* part = aLibs->FindLibPart( component->GetPartName() );
  194. if( !part || !part->IsPower() )
  195. continue;
  196. wxString refstr = component->GetPrefix();
  197. //str will be "C?" or so after the ClearAnnotation call.
  198. while( refstr.Last() == '?' )
  199. refstr.RemoveLast();
  200. if( !refstr.StartsWith( wxT( "#" ) ) )
  201. refstr = wxT( "#" ) + refstr;
  202. refstr << wxT( "0" ) << ref;
  203. component->SetRef( this, refstr );
  204. ref++;
  205. }
  206. if( aReference )
  207. *aReference = ref;
  208. }
  209. void SCH_SHEET_PATH::GetComponents( PART_LIBS* aLibs, SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols )
  210. {
  211. // Search to sheet path number:
  212. int sheetnumber = 1; // 1 = root
  213. SCH_SHEET_LIST sheetList;
  214. for( SCH_SHEET_PATH* path = sheetList.GetFirst(); path; path = sheetList.GetNext(), sheetnumber++ )
  215. {
  216. if( Cmp( *path ) == 0 )
  217. break;
  218. }
  219. for( SCH_ITEM* item = LastDrawList(); item; item = item->Next() )
  220. {
  221. if( item->Type() == SCH_COMPONENT_T )
  222. {
  223. SCH_COMPONENT* component = (SCH_COMPONENT*) item;
  224. // Skip pseudo components, which have a reference starting with #. This mainly
  225. // affects power symbols.
  226. if( !aIncludePowerSymbols && component->GetRef( this )[0] == wxT( '#' ) )
  227. continue;
  228. LIB_PART* part = aLibs->FindLibPart( component->GetPartName() );
  229. if( part )
  230. {
  231. SCH_REFERENCE reference = SCH_REFERENCE( component, part, *this );
  232. reference.SetSheetNumber( sheetnumber );
  233. aReferences.AddItem( reference );
  234. }
  235. }
  236. }
  237. }
  238. void SCH_SHEET_PATH::GetMultiUnitComponents( PART_LIBS* aLibs, SCH_MULTI_UNIT_REFERENCE_MAP &aRefList,
  239. bool aIncludePowerSymbols )
  240. {
  241. // Find sheet path number
  242. int sheetnumber = 1; // 1 = root
  243. SCH_SHEET_LIST sheetList;
  244. for( SCH_SHEET_PATH* path = sheetList.GetFirst(); path; path = sheetList.GetNext(), sheetnumber++ )
  245. {
  246. if( Cmp( *path ) == 0 )
  247. break;
  248. }
  249. for( SCH_ITEM* item = LastDrawList(); item; item = item->Next() )
  250. {
  251. if( item->Type() != SCH_COMPONENT_T ) continue;
  252. SCH_COMPONENT* component = (SCH_COMPONENT*) item;
  253. // Skip pseudo components, which have a reference starting with #. This mainly
  254. // affects power symbols.
  255. if( !aIncludePowerSymbols && component->GetRef( this )[0] == wxT( '#' ) )
  256. continue;
  257. LIB_PART* part = aLibs->FindLibPart( component->GetPartName() );
  258. if( part && part->GetUnitCount() > 1 )
  259. {
  260. SCH_REFERENCE reference = SCH_REFERENCE( component, part, *this );
  261. reference.SetSheetNumber( sheetnumber );
  262. wxString reference_str = reference.GetRef();
  263. // Never lock unassigned references
  264. if( reference_str[reference_str.Len() - 1] == '?' ) continue;
  265. aRefList[reference_str].AddItem( reference );
  266. }
  267. }
  268. }
  269. SCH_ITEM* SCH_SHEET_PATH::FindNextItem( KICAD_T aType, SCH_ITEM* aLastItem, bool aWrap ) const
  270. {
  271. bool hasWrapped = false;
  272. bool firstItemFound = false;
  273. SCH_ITEM* drawItem = LastDrawList();
  274. while( drawItem )
  275. {
  276. if( drawItem->Type() == aType )
  277. {
  278. if( !aLastItem || firstItemFound )
  279. {
  280. return drawItem;
  281. }
  282. else if( !firstItemFound && drawItem == aLastItem )
  283. {
  284. firstItemFound = true;
  285. }
  286. }
  287. drawItem = drawItem->Next();
  288. if( !drawItem && aLastItem && aWrap && !hasWrapped )
  289. {
  290. hasWrapped = true;
  291. drawItem = LastDrawList();
  292. }
  293. }
  294. return NULL;
  295. }
  296. SCH_ITEM* SCH_SHEET_PATH::FindPreviousItem( KICAD_T aType, SCH_ITEM* aLastItem, bool aWrap ) const
  297. {
  298. bool hasWrapped = false;
  299. bool firstItemFound = false;
  300. SCH_ITEM* drawItem = FirstDrawList();
  301. while( drawItem )
  302. {
  303. if( drawItem->Type() == aType )
  304. {
  305. if( aLastItem == NULL || firstItemFound )
  306. {
  307. return drawItem;
  308. }
  309. else if( !firstItemFound && drawItem == aLastItem )
  310. {
  311. firstItemFound = true;
  312. }
  313. }
  314. drawItem = drawItem->Back();
  315. if( drawItem == NULL && aLastItem && aWrap && !hasWrapped )
  316. {
  317. hasWrapped = true;
  318. drawItem = FirstDrawList();
  319. }
  320. }
  321. return NULL;
  322. }
  323. bool SCH_SHEET_PATH::SetComponentFootprint( const wxString& aReference, const wxString& aFootPrint,
  324. bool aSetVisible )
  325. {
  326. SCH_SCREEN* screen = LastScreen();
  327. if( screen == NULL )
  328. return false;
  329. return screen->SetComponentFootprint( this, aReference, aFootPrint, aSetVisible );
  330. }
  331. SCH_SHEET_PATH& SCH_SHEET_PATH::operator=( const SCH_SHEET_PATH& d1 )
  332. {
  333. if( this == &d1 ) // Self assignment is bad!
  334. return *this;
  335. m_numSheets = d1.m_numSheets;
  336. unsigned i;
  337. for( i = 0; i < m_numSheets; i++ )
  338. m_sheets[i] = d1.m_sheets[i];
  339. for( ; i < DSLSZ; i++ )
  340. m_sheets[i] = 0;
  341. return *this;
  342. }
  343. bool SCH_SHEET_PATH::operator==( const SCH_SHEET_PATH& d1 ) const
  344. {
  345. if( m_numSheets != d1.m_numSheets )
  346. return false;
  347. for( unsigned i = 0; i < m_numSheets; i++ )
  348. {
  349. if( m_sheets[i] != d1.m_sheets[i] )
  350. return false;
  351. }
  352. return true;
  353. }
  354. bool SCH_SHEET_PATH::TestForRecursion( const wxString& aSrcFileName,
  355. const wxString& aDestFileName ) const
  356. {
  357. wxFileName rootFn = g_RootSheet->GetFileName();
  358. wxFileName srcFn = aSrcFileName;
  359. wxFileName destFn = aDestFileName;
  360. if( srcFn.IsRelative() )
  361. srcFn.MakeAbsolute( rootFn.GetPath() );
  362. if( destFn.IsRelative() )
  363. destFn.MakeAbsolute( rootFn.GetPath() );
  364. // The source and destination sheet file names cannot be the same.
  365. if( srcFn == destFn )
  366. return true;
  367. /// @todo Store sheet file names with full path, either relative to project path
  368. /// or absolute path. The current design always assumes subsheet files are
  369. /// located in the project folder which may or may not be desirable.
  370. unsigned i = 0;
  371. while( i < m_numSheets )
  372. {
  373. wxFileName cmpFn = m_sheets[i]->GetFileName();
  374. if( cmpFn.IsRelative() )
  375. cmpFn.MakeAbsolute( rootFn.GetPath() );
  376. // Test if the file name of the destination sheet is in anywhere in this sheet path.
  377. if( cmpFn == destFn )
  378. break;
  379. i++;
  380. }
  381. // The destination sheet file name was not found in the sheet path or the destination
  382. // sheet file name is the root sheet so no recursion is possible.
  383. if( i >= m_numSheets || i == 0 )
  384. return false;
  385. // Walk back up to the root sheet to see if the source file name is already a parent in
  386. // the sheet path. If so, recursion will occur.
  387. do
  388. {
  389. i -= 1;
  390. wxFileName cmpFn = m_sheets[i]->GetFileName();
  391. if( cmpFn.IsRelative() )
  392. cmpFn.MakeAbsolute( rootFn.GetPath() );
  393. if( cmpFn == srcFn )
  394. return true;
  395. } while( i != 0 );
  396. // The source sheet file name is not a parent of the destination sheet file name.
  397. return false;
  398. }
  399. int SCH_SHEET_PATH::FindSheet( const wxString& aFileName ) const
  400. {
  401. for( unsigned i = 0; i < m_numSheets; i++ )
  402. {
  403. if( m_sheets[i]->GetFileName().CmpNoCase( aFileName ) == 0 )
  404. return (int)i;
  405. }
  406. return SHEET_NOT_FOUND;
  407. }
  408. SCH_SHEET* SCH_SHEET_PATH::FindSheetByName( const wxString& aSheetName )
  409. {
  410. for( unsigned i = 0; i < m_numSheets; i++ )
  411. {
  412. if( m_sheets[i]->GetName().CmpNoCase( aSheetName ) == 0 )
  413. return m_sheets[i];
  414. }
  415. return NULL;
  416. }
  417. /********************************************************************/
  418. /* Class SCH_SHEET_LIST to handle the list of Sheets in a hierarchy */
  419. /********************************************************************/
  420. SCH_SHEET_LIST::SCH_SHEET_LIST( SCH_SHEET* aSheet )
  421. {
  422. m_index = 0;
  423. m_count = 0;
  424. m_list = NULL;
  425. m_isRootSheet = false;
  426. if( aSheet == NULL )
  427. aSheet = g_RootSheet;
  428. BuildSheetList( aSheet );
  429. }
  430. SCH_SHEET_PATH* SCH_SHEET_LIST::GetFirst()
  431. {
  432. m_index = 0;
  433. if( GetCount() > 0 )
  434. return &( m_list[0] );
  435. return NULL;
  436. }
  437. SCH_SHEET_PATH* SCH_SHEET_LIST::GetNext()
  438. {
  439. if( m_index < GetCount() )
  440. m_index++;
  441. return GetSheet( m_index );
  442. }
  443. SCH_SHEET_PATH* SCH_SHEET_LIST::GetLast()
  444. {
  445. if( GetCount() == 0 )
  446. return NULL;
  447. m_index = GetCount() - 1;
  448. return GetSheet( m_index );
  449. }
  450. SCH_SHEET_PATH* SCH_SHEET_LIST::GetPrevious()
  451. {
  452. if( m_index == 0 )
  453. return NULL;
  454. m_index -= 1;
  455. return GetSheet( m_index );
  456. }
  457. SCH_SHEET_PATH* SCH_SHEET_LIST::GetSheet( int aIndex ) const
  458. {
  459. if( aIndex < GetCount() )
  460. return &( m_list[aIndex] );
  461. return NULL;
  462. }
  463. SCH_SHEET_PATH* SCH_SHEET_LIST::GetSheetByPath( const wxString aPath, bool aHumanReadable )
  464. {
  465. SCH_SHEET_PATH* sheet = GetFirst();
  466. wxString sheetPath;
  467. while( sheet )
  468. {
  469. sheetPath = ( aHumanReadable ) ? sheet->PathHumanReadable() : sheet->Path();
  470. if( sheetPath == aPath )
  471. return sheet;
  472. sheet = GetNext();
  473. }
  474. return NULL;
  475. }
  476. void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet )
  477. {
  478. wxCHECK_RET( aSheet != NULL, wxT( "Cannot build sheet list from undefined sheet." ) );
  479. if( aSheet == g_RootSheet )
  480. m_isRootSheet = true;
  481. if( m_list == NULL )
  482. {
  483. int count = aSheet->CountSheets();
  484. m_count = count;
  485. m_index = 0;
  486. m_list = new SCH_SHEET_PATH[ count ];
  487. m_currList.Clear();
  488. }
  489. m_currList.Push( aSheet );
  490. m_list[m_index] = m_currList;
  491. m_index++;
  492. if( aSheet->GetScreen() )
  493. {
  494. EDA_ITEM* strct = m_currList.LastDrawList();
  495. while( strct )
  496. {
  497. if( strct->Type() == SCH_SHEET_T )
  498. {
  499. SCH_SHEET* sheet = (SCH_SHEET*) strct;
  500. BuildSheetList( sheet );
  501. }
  502. strct = strct->Next();
  503. }
  504. }
  505. m_currList.Pop();
  506. }
  507. bool SCH_SHEET_LIST::IsAutoSaveRequired()
  508. {
  509. for( SCH_SHEET_PATH* sheet = GetFirst(); sheet; sheet = GetNext() )
  510. {
  511. if( sheet->LastScreen() && sheet->LastScreen()->IsSave() )
  512. return true;
  513. }
  514. return false;
  515. }
  516. void SCH_SHEET_LIST::AnnotatePowerSymbols( PART_LIBS* aLibs )
  517. {
  518. int ref = 1;
  519. for( SCH_SHEET_PATH* path = GetFirst(); path; path = GetNext() )
  520. path->AnnotatePowerSymbols( aLibs, &ref );
  521. }
  522. void SCH_SHEET_LIST::GetComponents( PART_LIBS* aLibs, SCH_REFERENCE_LIST& aReferences,
  523. bool aIncludePowerSymbols )
  524. {
  525. for( SCH_SHEET_PATH* path = GetFirst(); path; path = GetNext() )
  526. path->GetComponents( aLibs, aReferences, aIncludePowerSymbols );
  527. }
  528. void SCH_SHEET_LIST::GetMultiUnitComponents( PART_LIBS* aLibs,
  529. SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, bool aIncludePowerSymbols )
  530. {
  531. for( SCH_SHEET_PATH* path = GetFirst(); path; path = GetNext() )
  532. {
  533. SCH_MULTI_UNIT_REFERENCE_MAP tempMap;
  534. path->GetMultiUnitComponents( aLibs, tempMap );
  535. BOOST_FOREACH( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair, tempMap )
  536. {
  537. // Merge this list into the main one
  538. unsigned n_refs = pair.second.GetCount();
  539. for( unsigned thisRef = 0; thisRef < n_refs; ++thisRef )
  540. {
  541. aRefList[pair.first].AddItem( pair.second[thisRef] );
  542. }
  543. }
  544. }
  545. }
  546. SCH_ITEM* SCH_SHEET_LIST::FindNextItem( KICAD_T aType, SCH_SHEET_PATH** aSheetFoundIn,
  547. SCH_ITEM* aLastItem, bool aWrap )
  548. {
  549. bool hasWrapped = false;
  550. bool firstItemFound = false;
  551. SCH_ITEM* drawItem = NULL;
  552. SCH_SHEET_PATH* sheet = GetFirst();
  553. while( sheet )
  554. {
  555. drawItem = sheet->LastDrawList();
  556. while( drawItem )
  557. {
  558. if( drawItem->Type() == aType )
  559. {
  560. if( aLastItem == NULL || firstItemFound )
  561. {
  562. if( aSheetFoundIn )
  563. *aSheetFoundIn = sheet;
  564. return drawItem;
  565. }
  566. else if( !firstItemFound && drawItem == aLastItem )
  567. {
  568. firstItemFound = true;
  569. }
  570. }
  571. drawItem = drawItem->Next();
  572. }
  573. sheet = GetNext();
  574. if( sheet == NULL && aLastItem && aWrap && !hasWrapped )
  575. {
  576. hasWrapped = true;
  577. sheet = GetFirst();
  578. }
  579. }
  580. return NULL;
  581. }
  582. SCH_ITEM* SCH_SHEET_LIST::FindPreviousItem( KICAD_T aType, SCH_SHEET_PATH** aSheetFoundIn,
  583. SCH_ITEM* aLastItem, bool aWrap )
  584. {
  585. bool hasWrapped = false;
  586. bool firstItemFound = false;
  587. SCH_ITEM* drawItem = NULL;
  588. SCH_SHEET_PATH* sheet = GetLast();
  589. while( sheet )
  590. {
  591. drawItem = sheet->FirstDrawList();
  592. while( drawItem )
  593. {
  594. if( drawItem->Type() == aType )
  595. {
  596. if( aLastItem == NULL || firstItemFound )
  597. {
  598. if( aSheetFoundIn )
  599. *aSheetFoundIn = sheet;
  600. return drawItem;
  601. }
  602. else if( !firstItemFound && drawItem == aLastItem )
  603. {
  604. firstItemFound = true;
  605. }
  606. }
  607. drawItem = drawItem->Back();
  608. }
  609. sheet = GetPrevious();
  610. if( sheet == NULL && aLastItem && aWrap && !hasWrapped )
  611. {
  612. hasWrapped = true;
  613. sheet = GetLast();
  614. }
  615. }
  616. return NULL;
  617. }
  618. bool SCH_SHEET_LIST::SetComponentFootprint( const wxString& aReference,
  619. const wxString& aFootPrint, bool aSetVisible )
  620. {
  621. bool found = false;
  622. for( SCH_SHEET_PATH* path = GetFirst(); path; path = GetNext() )
  623. found = path->SetComponentFootprint( aReference, aFootPrint, aSetVisible );
  624. return found;
  625. }
  626. bool SCH_SHEET_LIST::IsComplexHierarchy() const
  627. {
  628. wxString fileName;
  629. for( int i = 0; i < m_count; i++ )
  630. {
  631. fileName = m_list[i].Last()->GetFileName();
  632. for( int j = 0; j < m_count; j++ )
  633. {
  634. if( i == j )
  635. continue;
  636. if( fileName == m_list[j].Last()->GetFileName() )
  637. return true;
  638. }
  639. }
  640. return false;
  641. }
  642. bool SCH_SHEET_LIST::TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy,
  643. const wxString& aDestFileName ) const
  644. {
  645. wxFileName rootFn = g_RootSheet->GetFileName();
  646. wxFileName destFn = aDestFileName;
  647. if( destFn.IsRelative() )
  648. destFn.MakeAbsolute( rootFn.GetPath() );
  649. // Test each SCH_SHEET_PATH in this SCH_SHEET_LIST for potential recursion.
  650. for( int i = 0; i < m_count; i++ )
  651. {
  652. // Test each SCH_SHEET_PATH in the source sheet.
  653. for( int j = 0; j < aSrcSheetHierarchy.GetCount(); j++ )
  654. {
  655. SCH_SHEET_PATH* sheetPath = aSrcSheetHierarchy.GetSheet( j );
  656. for( unsigned k = 0; k < sheetPath->GetCount(); k++ )
  657. {
  658. if( m_list[i].TestForRecursion( sheetPath->GetSheet( k )->GetFileName(),
  659. aDestFileName ) )
  660. return true;
  661. }
  662. }
  663. }
  664. // The source sheet file can safely be added to the destination sheet file.
  665. return false;
  666. }
  667. SCH_SHEET* SCH_SHEET_LIST::FindSheetByName( const wxString& aSheetName )
  668. {
  669. for( int i = 0; i < m_count; i++ )
  670. {
  671. SCH_SHEET* sheet = m_list[i].FindSheetByName( aSheetName );
  672. if( sheet )
  673. return sheet;
  674. }
  675. return NULL;
  676. }