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.

740 lines
17 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: sch_sheet_path.cpp
  3. // Purpose: member functions for SCH_SHEET_PATH
  4. // header = sch_sheet_path.h
  5. // Author: jean-pierre Charras
  6. // Modified by:
  7. // License: License GNU
  8. /////////////////////////////////////////////////////////////////////////////
  9. #include "fctsys.h"
  10. #include "common.h"
  11. #include "general.h"
  12. #include "dlist.h"
  13. #include "class_sch_screen.h"
  14. #include "sch_item_struct.h"
  15. #include "netlist.h"
  16. #include "class_library.h"
  17. #include "sch_sheet.h"
  18. #include "sch_sheet_path.h"
  19. #include "sch_component.h"
  20. #include "template_fieldnames.h"
  21. #include "dialogs/dialog_schematic_find.h"
  22. SCH_SHEET_PATH::SCH_SHEET_PATH()
  23. {
  24. for( int i = 0; i<DSLSZ; i++ )
  25. m_sheets[i] = NULL;
  26. m_numSheets = 0;
  27. }
  28. bool SCH_SHEET_PATH::BuildSheetPathInfoFromSheetPathValue( const wxString& aPath, bool aFound )
  29. {
  30. if( aFound )
  31. return true;
  32. if( GetSheetsCount() == 0 )
  33. Push( g_RootSheet );
  34. if( aPath == Path() )
  35. return true;
  36. SCH_ITEM* schitem = LastDrawList();
  37. while( schitem && GetSheetsCount() < NB_MAX_SHEET )
  38. {
  39. if( schitem->Type() == SCH_SHEET_T )
  40. {
  41. SCH_SHEET* sheet = (SCH_SHEET*) schitem;
  42. Push( sheet );
  43. if( aPath == Path() )
  44. return true;
  45. if( BuildSheetPathInfoFromSheetPathValue( aPath ) )
  46. return true;
  47. Pop();
  48. }
  49. schitem = schitem->Next();
  50. }
  51. return false;
  52. }
  53. int SCH_SHEET_PATH::Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const
  54. {
  55. if( m_numSheets > aSheetPathToTest.m_numSheets )
  56. return 1;
  57. if( m_numSheets < aSheetPathToTest.m_numSheets )
  58. return -1;
  59. //otherwise, same number of sheets.
  60. for( unsigned i = 0; i<m_numSheets; i++ )
  61. {
  62. if( m_sheets[i]->m_TimeStamp > aSheetPathToTest.m_sheets[i]->m_TimeStamp )
  63. return 1;
  64. if( m_sheets[i]->m_TimeStamp < aSheetPathToTest.m_sheets[i]->m_TimeStamp )
  65. return -1;
  66. }
  67. return 0;
  68. }
  69. SCH_SHEET* SCH_SHEET_PATH::Last()
  70. {
  71. if( m_numSheets )
  72. return m_sheets[m_numSheets - 1];
  73. return NULL;
  74. }
  75. SCH_SCREEN* SCH_SHEET_PATH::LastScreen()
  76. {
  77. SCH_SHEET* lastSheet = Last();
  78. if( lastSheet )
  79. return lastSheet->GetScreen();
  80. return NULL;
  81. }
  82. SCH_ITEM* SCH_SHEET_PATH::LastDrawList()
  83. {
  84. SCH_SHEET* lastSheet = Last();
  85. if( lastSheet && lastSheet->GetScreen() )
  86. return lastSheet->GetScreen()->GetDrawItems();
  87. return NULL;
  88. }
  89. SCH_ITEM* SCH_SHEET_PATH::FirstDrawList()
  90. {
  91. SCH_ITEM* item = NULL;
  92. if( m_numSheets && m_sheets[0]->GetScreen() )
  93. item = m_sheets[0]->GetScreen()->GetDrawItems();
  94. /* @fixme - These lists really should be one of the boost pointer containers. This
  95. * is a brain dead hack to allow reverse iteration of EDA_ITEM linked
  96. * list.
  97. */
  98. SCH_ITEM* lastItem = NULL;
  99. while( item != NULL )
  100. {
  101. lastItem = item;
  102. item = item->Next();
  103. }
  104. return lastItem;
  105. }
  106. void SCH_SHEET_PATH::Push( SCH_SHEET* aSheet )
  107. {
  108. wxCHECK_RET( m_numSheets < DSLSZ,
  109. wxString::Format( _( "Schematic sheets can only be nested %d levels deep." ),
  110. DSLSZ ) );
  111. m_sheets[ m_numSheets ] = aSheet;
  112. m_numSheets++;
  113. }
  114. SCH_SHEET* SCH_SHEET_PATH::Pop()
  115. {
  116. if( m_numSheets > 0 )
  117. {
  118. m_numSheets--;
  119. return m_sheets[m_numSheets];
  120. }
  121. return NULL;
  122. }
  123. wxString SCH_SHEET_PATH::Path()
  124. {
  125. wxString s, t;
  126. s = wxT( "/" ); // This is the root path
  127. // start at 1 to avoid the root sheet,
  128. // which does not need to be added to the path
  129. // it's timestamp changes anyway.
  130. for( unsigned i = 1; i < m_numSheets; i++ )
  131. {
  132. t.Printf( _( "%8.8lX/" ), m_sheets[i]->m_TimeStamp );
  133. s = s + t;
  134. }
  135. return s;
  136. }
  137. wxString SCH_SHEET_PATH::PathHumanReadable() const
  138. {
  139. wxString s, t;
  140. s = wxT( "/" );
  141. // start at 1 to avoid the root sheet, as above.
  142. for( unsigned i = 1; i< m_numSheets; i++ )
  143. {
  144. s = s + m_sheets[i]->m_SheetName + wxT( "/" );
  145. }
  146. return s;
  147. }
  148. void SCH_SHEET_PATH::UpdateAllScreenReferences()
  149. {
  150. EDA_ITEM* t = LastDrawList();
  151. while( t )
  152. {
  153. if( t->Type() == SCH_COMPONENT_T )
  154. {
  155. SCH_COMPONENT* component = (SCH_COMPONENT*) t;
  156. component->GetField( REFERENCE )->m_Text = component->GetRef( this );
  157. component->SetUnit( component->GetUnitSelection( this ) );
  158. }
  159. t = t->Next();
  160. }
  161. }
  162. void SCH_SHEET_PATH::AnnotatePowerSymbols( int* aReference )
  163. {
  164. int ref = 1;
  165. if( aReference != NULL )
  166. ref = *aReference;
  167. for( EDA_ITEM* item = LastDrawList(); item != NULL; item = item->Next() )
  168. {
  169. if( item->Type() != SCH_COMPONENT_T )
  170. continue;
  171. SCH_COMPONENT* component = (SCH_COMPONENT*) item;
  172. LIB_COMPONENT* entry = CMP_LIBRARY::FindLibraryComponent( component->GetLibName() );
  173. if( ( entry == NULL ) || !entry->IsPower() )
  174. continue;
  175. wxString refstr = component->GetPrefix();
  176. //str will be "C?" or so after the ClearAnnotation call.
  177. while( refstr.Last() == '?' )
  178. refstr.RemoveLast();
  179. if( !refstr.StartsWith( wxT( "#" ) ) )
  180. refstr = wxT( "#" ) + refstr;
  181. refstr << wxT( "0" ) << ref;
  182. component->SetRef( this, refstr );
  183. ref++;
  184. }
  185. if( aReference != NULL )
  186. *aReference = ref;
  187. }
  188. void SCH_SHEET_PATH::GetComponents( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols )
  189. {
  190. // Search to sheet path number:
  191. int sheetnumber = 1; // 1 = root
  192. SCH_SHEET_LIST sheetList;
  193. for( SCH_SHEET_PATH* path = sheetList.GetFirst(); path != NULL;
  194. path = sheetList.GetNext(), sheetnumber++ )
  195. {
  196. if( Cmp(*path) == 0 )
  197. break;
  198. }
  199. for( SCH_ITEM* item = LastDrawList(); item != NULL; item = item->Next() )
  200. {
  201. if( item->Type() == SCH_COMPONENT_T )
  202. {
  203. SCH_COMPONENT* component = (SCH_COMPONENT*) item;
  204. // Skip pseudo components, which have a reference starting with #. This mainly
  205. // effects power symbols.
  206. if( !aIncludePowerSymbols && component->GetRef( this )[0] == wxT( '#' ) )
  207. continue;
  208. LIB_COMPONENT* entry = CMP_LIBRARY::FindLibraryComponent( component->GetLibName() );
  209. if( entry == NULL )
  210. continue;
  211. SCH_REFERENCE reference = SCH_REFERENCE( component, entry, *this );
  212. reference.SetSheetNumber( sheetnumber );
  213. aReferences.AddItem( reference );
  214. }
  215. }
  216. }
  217. SCH_ITEM* SCH_SHEET_PATH::FindNextItem( KICAD_T aType, SCH_ITEM* aLastItem, bool aWrap )
  218. {
  219. bool hasWrapped = false;
  220. bool firstItemFound = false;
  221. SCH_ITEM* drawItem = LastDrawList();
  222. while( drawItem != NULL )
  223. {
  224. if( drawItem->Type() == aType )
  225. {
  226. if( aLastItem == NULL || firstItemFound )
  227. {
  228. return drawItem;
  229. }
  230. else if( !firstItemFound && drawItem == aLastItem )
  231. {
  232. firstItemFound = true;
  233. }
  234. }
  235. drawItem = drawItem->Next();
  236. if( drawItem == NULL && aLastItem && aWrap && !hasWrapped )
  237. {
  238. hasWrapped = true;
  239. drawItem = LastDrawList();
  240. }
  241. }
  242. return NULL;
  243. }
  244. SCH_ITEM* SCH_SHEET_PATH::FindPreviousItem( KICAD_T aType, SCH_ITEM* aLastItem, bool aWrap )
  245. {
  246. bool hasWrapped = false;
  247. bool firstItemFound = false;
  248. SCH_ITEM* drawItem = FirstDrawList();
  249. while( drawItem != NULL )
  250. {
  251. if( drawItem->Type() == aType )
  252. {
  253. if( aLastItem == NULL || firstItemFound )
  254. {
  255. return drawItem;
  256. }
  257. else if( !firstItemFound && drawItem == aLastItem )
  258. {
  259. firstItemFound = true;
  260. }
  261. }
  262. drawItem = drawItem->Back();
  263. if( drawItem == NULL && aLastItem && aWrap && !hasWrapped )
  264. {
  265. hasWrapped = true;
  266. drawItem = FirstDrawList();
  267. }
  268. }
  269. return NULL;
  270. }
  271. SCH_ITEM* SCH_SHEET_PATH::MatchNextItem( wxFindReplaceData& aSearchData,
  272. SCH_ITEM* aLastItem,
  273. wxPoint* aFindLocation )
  274. {
  275. bool hasWrapped = false;
  276. bool firstItemFound = false;
  277. bool wrap = ( aSearchData.GetFlags() & FR_SEARCH_WRAP ) != 0;
  278. SCH_ITEM* drawItem = LastDrawList();
  279. while( drawItem != NULL )
  280. {
  281. if( aLastItem && !firstItemFound )
  282. {
  283. firstItemFound = ( drawItem == aLastItem );
  284. }
  285. else
  286. {
  287. if( drawItem->Matches( aSearchData, this, aFindLocation ) )
  288. return drawItem;
  289. }
  290. drawItem = drawItem->Next();
  291. if( drawItem == NULL && aLastItem && firstItemFound && wrap && !hasWrapped )
  292. {
  293. hasWrapped = true;
  294. drawItem = LastDrawList();
  295. }
  296. }
  297. return NULL;
  298. }
  299. bool SCH_SHEET_PATH::SetComponentFootprint( const wxString& aReference, const wxString& aFootPrint,
  300. bool aSetVisible )
  301. {
  302. SCH_SCREEN* screen = LastScreen();
  303. if( screen == NULL )
  304. return false;
  305. return screen->SetComponentFootprint( this, aReference, aFootPrint, aSetVisible );
  306. }
  307. SCH_SHEET_PATH& SCH_SHEET_PATH::operator=( const SCH_SHEET_PATH& d1 )
  308. {
  309. if( this == &d1 ) // Self assignment is bad!
  310. return *this;
  311. m_numSheets = d1.m_numSheets;
  312. unsigned i;
  313. for( i = 0; i < m_numSheets; i++ )
  314. m_sheets[i] = d1.m_sheets[i];
  315. for( ; i < DSLSZ; i++ )
  316. m_sheets[i] = 0;
  317. return *this;
  318. }
  319. bool SCH_SHEET_PATH::operator==( const SCH_SHEET_PATH& d1 ) const
  320. {
  321. if( m_numSheets != d1.m_numSheets )
  322. return false;
  323. for( unsigned i = 0; i < m_numSheets; i++ )
  324. {
  325. if( m_sheets[i] != d1.m_sheets[i] )
  326. return false;
  327. }
  328. return true;
  329. }
  330. /********************************************************************/
  331. /* Class SCH_SHEET_LIST to handle the list of Sheets in a hierarchy */
  332. /********************************************************************/
  333. SCH_SHEET_LIST::SCH_SHEET_LIST( SCH_SHEET* aSheet )
  334. {
  335. m_index = 0;
  336. m_count = 0;
  337. m_List = NULL;
  338. if( aSheet == NULL )
  339. aSheet = g_RootSheet;
  340. BuildSheetList( aSheet );
  341. }
  342. SCH_SHEET_PATH* SCH_SHEET_LIST::GetFirst()
  343. {
  344. m_index = 0;
  345. if( GetCount() > 0 )
  346. return &( m_List[0] );
  347. return NULL;
  348. }
  349. SCH_SHEET_PATH* SCH_SHEET_LIST::GetNext()
  350. {
  351. if( m_index < GetCount() )
  352. m_index++;
  353. return GetSheet( m_index );
  354. }
  355. SCH_SHEET_PATH* SCH_SHEET_LIST::GetLast()
  356. {
  357. if( GetCount() == 0 )
  358. return NULL;
  359. m_index = GetCount() - 1;
  360. return GetSheet( m_index );
  361. }
  362. SCH_SHEET_PATH* SCH_SHEET_LIST::GetPrevious()
  363. {
  364. if( m_index == 0 )
  365. return NULL;
  366. m_index -= 1;
  367. return GetSheet( m_index );
  368. }
  369. SCH_SHEET_PATH* SCH_SHEET_LIST::GetSheet( int aIndex )
  370. {
  371. if( aIndex < GetCount() )
  372. return &( m_List[aIndex] );
  373. return NULL;
  374. }
  375. void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet )
  376. {
  377. if( m_List == NULL )
  378. {
  379. int count = aSheet->CountSheets();
  380. m_count = count;
  381. m_index = 0;
  382. count *= sizeof(SCH_SHEET_PATH);
  383. /* @bug - MyZMalloc() can return a NULL pointer if there is not enough
  384. * memory. This code continues on it's merry way with out
  385. * checking to see if the memory was actually allocated.
  386. */
  387. m_List = (SCH_SHEET_PATH*) MyZMalloc( count );
  388. m_currList.Clear();
  389. }
  390. m_currList.Push( aSheet );
  391. m_List[m_index] = m_currList;
  392. m_index++;
  393. if( aSheet->GetScreen() != NULL )
  394. {
  395. EDA_ITEM* strct = m_currList.LastDrawList();
  396. while( strct )
  397. {
  398. if( strct->Type() == SCH_SHEET_T )
  399. {
  400. SCH_SHEET* sheet = (SCH_SHEET*) strct;
  401. BuildSheetList( sheet );
  402. }
  403. strct = strct->Next();
  404. }
  405. }
  406. m_currList.Pop();
  407. }
  408. bool SCH_SHEET_LIST::IsModified()
  409. {
  410. for( SCH_SHEET_PATH* sheet = GetFirst(); sheet != NULL; sheet = GetNext() )
  411. {
  412. if( sheet->LastScreen() && sheet->LastScreen()->IsModify() )
  413. return true;
  414. }
  415. return false;
  416. }
  417. void SCH_SHEET_LIST::ClearModifyStatus()
  418. {
  419. for( SCH_SHEET_PATH* sheet = GetFirst(); sheet != NULL; sheet = GetNext() )
  420. {
  421. if( sheet->LastScreen() )
  422. sheet->LastScreen()->ClrModify();
  423. }
  424. }
  425. void SCH_SHEET_LIST::AnnotatePowerSymbols()
  426. {
  427. int ref = 1;
  428. for( SCH_SHEET_PATH* path = GetFirst(); path != NULL; path = GetNext() )
  429. path->AnnotatePowerSymbols( &ref );
  430. }
  431. void SCH_SHEET_LIST::GetComponents( SCH_REFERENCE_LIST& aReferences,
  432. bool aIncludePowerSymbols )
  433. {
  434. for( SCH_SHEET_PATH* path = GetFirst(); path != NULL; path = GetNext() )
  435. path->GetComponents( aReferences, aIncludePowerSymbols );
  436. }
  437. SCH_ITEM* SCH_SHEET_LIST::FindNextItem( KICAD_T aType, SCH_SHEET_PATH** aSheetFoundIn,
  438. SCH_ITEM* aLastItem, bool aWrap )
  439. {
  440. bool hasWrapped = false;
  441. bool firstItemFound = false;
  442. SCH_ITEM* drawItem = NULL;
  443. SCH_SHEET_PATH* sheet = GetFirst();
  444. while( sheet != NULL )
  445. {
  446. drawItem = sheet->LastDrawList();
  447. while( drawItem != NULL )
  448. {
  449. if( drawItem->Type() == aType )
  450. {
  451. if( aLastItem == NULL || firstItemFound )
  452. {
  453. if( aSheetFoundIn )
  454. *aSheetFoundIn = sheet;
  455. return drawItem;
  456. }
  457. else if( !firstItemFound && drawItem == aLastItem )
  458. {
  459. firstItemFound = true;
  460. }
  461. }
  462. drawItem = drawItem->Next();
  463. }
  464. sheet = GetNext();
  465. if( sheet == NULL && aLastItem && aWrap && !hasWrapped )
  466. {
  467. hasWrapped = true;
  468. sheet = GetFirst();
  469. }
  470. }
  471. return NULL;
  472. }
  473. SCH_ITEM* SCH_SHEET_LIST::FindPreviousItem( KICAD_T aType, SCH_SHEET_PATH** aSheetFoundIn,
  474. SCH_ITEM* aLastItem, bool aWrap )
  475. {
  476. bool hasWrapped = false;
  477. bool firstItemFound = false;
  478. SCH_ITEM* drawItem = NULL;
  479. SCH_SHEET_PATH* sheet = GetLast();
  480. while( sheet != NULL )
  481. {
  482. drawItem = sheet->FirstDrawList();
  483. while( drawItem != NULL )
  484. {
  485. if( drawItem->Type() == aType )
  486. {
  487. if( aLastItem == NULL || firstItemFound )
  488. {
  489. if( aSheetFoundIn )
  490. *aSheetFoundIn = sheet;
  491. return drawItem;
  492. }
  493. else if( !firstItemFound && drawItem == aLastItem )
  494. {
  495. firstItemFound = true;
  496. }
  497. }
  498. drawItem = drawItem->Back();
  499. }
  500. sheet = GetPrevious();
  501. if( sheet == NULL && aLastItem && aWrap && !hasWrapped )
  502. {
  503. hasWrapped = true;
  504. sheet = GetLast();
  505. }
  506. }
  507. return NULL;
  508. }
  509. SCH_ITEM* SCH_SHEET_LIST::MatchNextItem( wxFindReplaceData& aSearchData,
  510. SCH_SHEET_PATH** aSheetFoundIn,
  511. SCH_ITEM* aLastItem,
  512. wxPoint* aFindLocation )
  513. {
  514. bool hasWrapped = false;
  515. bool firstItemFound = false;
  516. bool wrap = ( aSearchData.GetFlags() & FR_SEARCH_WRAP ) != 0;
  517. SCH_ITEM* drawItem = NULL;
  518. SCH_SHEET_PATH* sheet = GetFirst();
  519. while( sheet != NULL )
  520. {
  521. drawItem = sheet->LastDrawList();
  522. while( drawItem != NULL )
  523. {
  524. if( aLastItem && !firstItemFound )
  525. {
  526. firstItemFound = ( drawItem == aLastItem );
  527. }
  528. else
  529. {
  530. if( drawItem->Matches( aSearchData, sheet, aFindLocation ) )
  531. {
  532. if( aSheetFoundIn )
  533. *aSheetFoundIn = sheet;
  534. return drawItem;
  535. }
  536. }
  537. drawItem = drawItem->Next();
  538. }
  539. sheet = GetNext();
  540. if( sheet == NULL && aLastItem && firstItemFound && wrap && !hasWrapped )
  541. {
  542. hasWrapped = true;
  543. sheet = GetFirst();
  544. }
  545. }
  546. return NULL;
  547. }
  548. bool SCH_SHEET_LIST::SetComponentFootprint( const wxString& aReference,
  549. const wxString& aFootPrint, bool aSetVisible )
  550. {
  551. bool found = false;
  552. for( SCH_SHEET_PATH* path = GetFirst(); path != NULL; path = GetNext() )
  553. found = path->SetComponentFootprint( aReference, aFootPrint, aSetVisible );
  554. return found;
  555. }