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.

564 lines
14 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
  5. * Copyright (C) 2004-2011 KiCad Developers, see change_log.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /**
  25. * @file sch_collectors.cpp
  26. */
  27. #include <macros.h>
  28. #include <sch_sheet_path.h>
  29. #include <transform.h>
  30. #include <sch_collectors.h>
  31. #include <sch_component.h>
  32. #include <sch_line.h>
  33. #include <sch_bus_entry.h>
  34. const KICAD_T SCH_COLLECTOR::AllItems[] = {
  35. SCH_MARKER_T,
  36. SCH_JUNCTION_T,
  37. SCH_NO_CONNECT_T,
  38. SCH_BUS_BUS_ENTRY_T,
  39. SCH_BUS_WIRE_ENTRY_T,
  40. SCH_LINE_T,
  41. SCH_BITMAP_T,
  42. SCH_TEXT_T,
  43. SCH_LABEL_T,
  44. SCH_GLOBAL_LABEL_T,
  45. SCH_HIERARCHICAL_LABEL_T,
  46. SCH_FIELD_T,
  47. SCH_COMPONENT_T,
  48. LIB_PIN_T,
  49. SCH_SHEET_PIN_T,
  50. SCH_SHEET_T,
  51. EOT
  52. };
  53. const KICAD_T SCH_COLLECTOR::AllItemsButPins[] = {
  54. SCH_MARKER_T,
  55. SCH_JUNCTION_T,
  56. SCH_NO_CONNECT_T,
  57. SCH_BUS_BUS_ENTRY_T,
  58. SCH_BUS_WIRE_ENTRY_T,
  59. SCH_LINE_T,
  60. SCH_BITMAP_T,
  61. SCH_TEXT_T,
  62. SCH_LABEL_T,
  63. SCH_GLOBAL_LABEL_T,
  64. SCH_HIERARCHICAL_LABEL_T,
  65. SCH_FIELD_T,
  66. SCH_COMPONENT_T,
  67. SCH_SHEET_PIN_T,
  68. SCH_SHEET_T,
  69. EOT
  70. };
  71. const KICAD_T SCH_COLLECTOR::EditableItems[] = {
  72. SCH_TEXT_T,
  73. SCH_LABEL_T,
  74. SCH_GLOBAL_LABEL_T,
  75. SCH_HIERARCHICAL_LABEL_T,
  76. SCH_FIELD_T,
  77. SCH_COMPONENT_T,
  78. SCH_SHEET_PIN_T,
  79. SCH_SHEET_T,
  80. SCH_BITMAP_T,
  81. EOT
  82. };
  83. const KICAD_T SCH_COLLECTOR::CmpFieldValueOnly[] = {
  84. SCH_FIELD_LOCATE_VALUE_T,
  85. EOT
  86. };
  87. const KICAD_T SCH_COLLECTOR::CmpFieldReferenceOnly[] = {
  88. SCH_FIELD_LOCATE_REFERENCE_T,
  89. EOT
  90. };
  91. const KICAD_T SCH_COLLECTOR::CmpFieldFootprintOnly[] = {
  92. SCH_FIELD_LOCATE_FOOTPRINT_T,
  93. EOT
  94. };
  95. const KICAD_T SCH_COLLECTOR::MovableItems[] = {
  96. SCH_MARKER_T,
  97. SCH_JUNCTION_T,
  98. SCH_NO_CONNECT_T,
  99. SCH_BUS_BUS_ENTRY_T,
  100. SCH_BUS_WIRE_ENTRY_T,
  101. // SCH_LINE_T,
  102. SCH_BITMAP_T,
  103. SCH_TEXT_T,
  104. SCH_LABEL_T,
  105. SCH_GLOBAL_LABEL_T,
  106. SCH_HIERARCHICAL_LABEL_T,
  107. SCH_FIELD_T,
  108. SCH_COMPONENT_T,
  109. SCH_SHEET_PIN_T,
  110. SCH_SHEET_T,
  111. EOT
  112. };
  113. const KICAD_T SCH_COLLECTOR::DraggableItems[] = {
  114. SCH_JUNCTION_T,
  115. SCH_BUS_BUS_ENTRY_T,
  116. SCH_BUS_WIRE_ENTRY_T,
  117. SCH_LINE_T,
  118. SCH_LABEL_T,
  119. SCH_GLOBAL_LABEL_T,
  120. SCH_HIERARCHICAL_LABEL_T,
  121. SCH_COMPONENT_T,
  122. SCH_SHEET_T,
  123. EOT
  124. };
  125. const KICAD_T SCH_COLLECTOR::RotatableItems[] = {
  126. SCH_TEXT_T,
  127. SCH_LABEL_T,
  128. SCH_GLOBAL_LABEL_T,
  129. SCH_HIERARCHICAL_LABEL_T,
  130. SCH_FIELD_T,
  131. SCH_COMPONENT_T,
  132. SCH_SHEET_T,
  133. SCH_BITMAP_T,
  134. EOT
  135. };
  136. const KICAD_T SCH_COLLECTOR::ParentItems[] = {
  137. SCH_MARKER_T,
  138. SCH_JUNCTION_T,
  139. SCH_NO_CONNECT_T,
  140. SCH_BUS_BUS_ENTRY_T,
  141. SCH_BUS_WIRE_ENTRY_T,
  142. SCH_LINE_T,
  143. SCH_TEXT_T,
  144. SCH_LABEL_T,
  145. SCH_GLOBAL_LABEL_T,
  146. SCH_HIERARCHICAL_LABEL_T,
  147. SCH_COMPONENT_T,
  148. SCH_SHEET_PIN_T,
  149. SCH_SHEET_T,
  150. SCH_BITMAP_T,
  151. EOT
  152. };
  153. const KICAD_T SCH_COLLECTOR::ComponentsOnly[] = {
  154. SCH_COMPONENT_T,
  155. EOT
  156. };
  157. const KICAD_T SCH_COLLECTOR::SheetsOnly[] = {
  158. SCH_SHEET_T,
  159. EOT
  160. };
  161. const KICAD_T SCH_COLLECTOR::SheetsAndSheetLabels[] = {
  162. SCH_SHEET_PIN_T,
  163. SCH_SHEET_T,
  164. EOT
  165. };
  166. const KICAD_T SCH_COLLECTOR::OrientableItems[] = {
  167. SCH_COMPONENT_T,
  168. SCH_BITMAP_T,
  169. EOT
  170. };
  171. SEARCH_RESULT SCH_COLLECTOR::Inspect( EDA_ITEM* aItem, const void* aTestData )
  172. {
  173. if( aItem->Type() != LIB_PIN_T && !aItem->HitTest( m_RefPos ) )
  174. return SEARCH_CONTINUE;
  175. // Pins have special hit testing requirements that are relative to their parent
  176. // SCH_COMPONENT item.
  177. if( aItem->Type() == LIB_PIN_T )
  178. {
  179. wxCHECK_MSG( aTestData && ( (EDA_ITEM*) aTestData )->Type() == SCH_COMPONENT_T,
  180. SEARCH_CONTINUE, wxT( "Cannot inspect invalid data. Bad programmer!" ) );
  181. // Pin hit testing is relative to the components position and orientation in the
  182. // schematic. The hit test position must be converted to library coordinates.
  183. SCH_COMPONENT* component = (SCH_COMPONENT*) aTestData;
  184. TRANSFORM transform = component->GetTransform().InverseTransform();
  185. wxPoint position = transform.TransformCoordinate( m_RefPos - component->GetPosition() );
  186. position.y *= -1; // Y axis polarity in schematic is inverted from library.
  187. if( !aItem->HitTest( position ) )
  188. return SEARCH_CONTINUE;
  189. }
  190. Append( aItem );
  191. return SEARCH_CONTINUE;
  192. }
  193. void SCH_COLLECTOR::Collect( SCH_ITEM* aItem, const KICAD_T aFilterList[],
  194. const wxPoint& aPosition )
  195. {
  196. Empty(); // empty the collection just in case
  197. SetScanTypes( aFilterList );
  198. // remember where the snapshot was taken from and pass refPos to the Inspect() function.
  199. SetRefPos( aPosition );
  200. EDA_ITEM::IterateForward( aItem, this, NULL, m_ScanTypes );
  201. }
  202. bool SCH_COLLECTOR::IsCorner() const
  203. {
  204. if( GetCount() != 2 )
  205. return false;
  206. bool is_busentry0 = dynamic_cast<SCH_BUS_ENTRY_BASE*>( m_List[0] );
  207. bool is_busentry1 = dynamic_cast<SCH_BUS_ENTRY_BASE*>( m_List[1] );
  208. if( (m_List[0]->Type() == SCH_LINE_T) && (m_List[1]->Type() == SCH_LINE_T) )
  209. return true;
  210. if( (m_List[0]->Type() == SCH_LINE_T) && is_busentry1 )
  211. return true;
  212. if( is_busentry0 && (m_List[1]->Type() == SCH_LINE_T) )
  213. return true;
  214. return false;
  215. }
  216. bool SCH_COLLECTOR::IsNode( bool aIncludePins ) const
  217. {
  218. for( size_t i = 0; i < m_List.size(); i++ )
  219. {
  220. SCH_ITEM* item = (SCH_ITEM*) m_List[ i ];
  221. KICAD_T type = item->Type();
  222. if( type == SCH_JUNCTION_T )
  223. continue;
  224. if( type == SCH_LINE_T )
  225. {
  226. if( item->GetLayer() != LAYER_WIRE )
  227. return false;
  228. continue;
  229. }
  230. if( type == LIB_PIN_T )
  231. {
  232. if( !aIncludePins )
  233. return false;
  234. continue;
  235. }
  236. // Any other item types indicate that this collection is not a node.
  237. return false;
  238. }
  239. return true;
  240. }
  241. bool SCH_COLLECTOR::IsDraggableJunction() const
  242. {
  243. int wireEndCount = 0;
  244. int wireMidPoint = 0;
  245. int junctionCount = 0;
  246. for( size_t i = 0; i < m_List.size(); i++ )
  247. {
  248. SCH_ITEM* item = (SCH_ITEM*) m_List[ i ];
  249. KICAD_T type = item->Type();
  250. if( type == SCH_JUNCTION_T )
  251. {
  252. junctionCount++;
  253. continue;
  254. }
  255. if( type == SCH_LINE_T )
  256. {
  257. if( item->GetLayer() != LAYER_WIRE )
  258. return false;
  259. SCH_LINE* line = (SCH_LINE*) item;
  260. if( line->IsEndPoint( m_RefPos ) )
  261. wireEndCount++;
  262. else
  263. wireMidPoint++;
  264. continue;
  265. }
  266. // Any other item types indicate that this collection is not a draggable junction.
  267. return false;
  268. }
  269. return (wireEndCount >= 3) || ((wireEndCount >= 1) && (wireMidPoint == 1))
  270. || ((wireMidPoint >= 2) && (junctionCount == 1));
  271. }
  272. bool SCH_FIND_COLLECTOR::PassedEnd() const
  273. {
  274. bool retv = false;
  275. wxUint32 flags = m_findReplaceData.GetFlags();
  276. if( GetCount() == 0 )
  277. return true;
  278. if( !(flags & FR_SEARCH_WRAP) || (flags & FR_SEARCH_REPLACE) )
  279. {
  280. if( flags & wxFR_DOWN )
  281. {
  282. if( m_foundIndex >= GetCount() )
  283. retv = true;
  284. }
  285. else
  286. {
  287. if( m_foundIndex < 0 )
  288. retv = true;
  289. }
  290. }
  291. return retv;
  292. }
  293. #if defined(DEBUG)
  294. void SCH_FIND_COLLECTOR::dump()
  295. {
  296. int tmp = m_foundIndex;
  297. wxLogTrace( traceFindReplace, wxT( "%d items found to replace %s with %s." ),
  298. GetCount(), GetChars( m_findReplaceData.GetFindString() ),
  299. GetChars( m_findReplaceData.GetReplaceString() ) );
  300. for( m_foundIndex = 0; m_foundIndex < GetCount(); m_foundIndex++ )
  301. wxLogTrace( traceFindReplace, wxT( " " ) + GetText() );
  302. m_foundIndex = tmp;
  303. }
  304. #endif
  305. void SCH_FIND_COLLECTOR::UpdateIndex()
  306. {
  307. wxUint32 flags = m_findReplaceData.GetFlags();
  308. if( flags & wxFR_DOWN )
  309. {
  310. if( m_foundIndex < GetCount() )
  311. m_foundIndex += 1;
  312. if( (m_foundIndex >= GetCount()) && (flags & FR_SEARCH_WRAP) )
  313. m_foundIndex = 0;
  314. }
  315. else
  316. {
  317. if( m_foundIndex >= 0 )
  318. m_foundIndex -= 1;
  319. if( (m_foundIndex < 0) && (flags & FR_SEARCH_WRAP) )
  320. m_foundIndex = GetCount() - 1;
  321. }
  322. }
  323. SCH_FIND_COLLECTOR_DATA SCH_FIND_COLLECTOR::GetFindData( int aIndex )
  324. {
  325. wxCHECK_MSG( (unsigned) aIndex < m_data.size(), SCH_FIND_COLLECTOR_DATA(),
  326. wxT( "Attempt to get find data outside of list boundary." ) );
  327. return m_data[ aIndex ];
  328. }
  329. wxString SCH_FIND_COLLECTOR::GetText()
  330. {
  331. wxCHECK_MSG( (GetCount() != 0) && IsValidIndex( m_foundIndex ), wxEmptyString,
  332. wxT( "Cannot get found item at invalid index." ) );
  333. SCH_FIND_COLLECTOR_DATA data = m_data[ m_foundIndex ];
  334. EDA_ITEM* foundItem = m_List[ m_foundIndex ];
  335. wxCHECK_MSG( foundItem != NULL, wxEmptyString, wxT( "Invalid found item pointer." ) );
  336. wxString msg;
  337. if( data.GetParent() )
  338. {
  339. msg.Printf( _( "Child item %s of parent item %s found in sheet %s" ),
  340. GetChars( foundItem->GetSelectMenuText() ),
  341. GetChars( data.GetParent()->GetSelectMenuText() ),
  342. GetChars( data.GetSheetPath() ) );
  343. }
  344. else
  345. {
  346. msg.Printf( _( "Item %s found in sheet %s" ),
  347. GetChars( foundItem->GetSelectMenuText() ),
  348. GetChars( data.GetSheetPath() ) );
  349. }
  350. return msg;
  351. }
  352. EDA_ITEM* SCH_FIND_COLLECTOR::GetItem( SCH_FIND_COLLECTOR_DATA& aData )
  353. {
  354. if( PassedEnd() )
  355. return NULL;
  356. aData = m_data[ m_foundIndex ];
  357. return m_List[ m_foundIndex ];
  358. }
  359. bool SCH_FIND_COLLECTOR::ReplaceItem( SCH_SHEET_PATH* aSheetPath )
  360. {
  361. if( PassedEnd() )
  362. return false;
  363. wxCHECK_MSG( IsValidIndex( m_foundIndex ), false,
  364. wxT( "Invalid replace list index in SCH_FIND_COLLECTOR." ) );
  365. EDA_ITEM* item = m_List[ m_foundIndex ];
  366. bool replaced = item->Replace( m_findReplaceData, aSheetPath );
  367. if( replaced )
  368. m_forceSearch = true;
  369. return replaced;
  370. }
  371. SEARCH_RESULT SCH_FIND_COLLECTOR::Inspect( EDA_ITEM* aItem, const void* aTestData )
  372. {
  373. wxPoint position;
  374. if( aItem->Matches( m_findReplaceData, m_sheetPath, &position ) )
  375. {
  376. if( aItem->Type() == LIB_PIN_T )
  377. {
  378. wxCHECK_MSG( aTestData && ( (EDA_ITEM*) aTestData )->Type() == SCH_COMPONENT_T,
  379. SEARCH_CONTINUE, wxT( "Cannot inspect invalid data. Bad programmer!" ) );
  380. // Pin positions are relative to their parent component's position and
  381. // orientation in the schematic. The pin's position must be converted
  382. // schematic coordinates.
  383. SCH_COMPONENT* component = (SCH_COMPONENT*) aTestData;
  384. TRANSFORM transform = component->GetTransform();
  385. position.y = -position.y;
  386. position = transform.TransformCoordinate( position ) + component->GetPosition();
  387. }
  388. Append( aItem );
  389. m_data.push_back( SCH_FIND_COLLECTOR_DATA( position, m_sheetPath->PathHumanReadable(),
  390. (SCH_ITEM*) aTestData ) );
  391. }
  392. return SEARCH_CONTINUE;
  393. }
  394. void SCH_FIND_COLLECTOR::Collect( SCH_FIND_REPLACE_DATA& aFindReplaceData,
  395. SCH_SHEET_PATH* aSheetPath )
  396. {
  397. if( !IsSearchRequired( aFindReplaceData ) && !m_List.empty() && !m_forceSearch )
  398. return;
  399. m_findReplaceData = aFindReplaceData;
  400. Empty(); // empty the collection just in case
  401. m_data.clear();
  402. m_foundIndex = 0;
  403. m_forceSearch = false;
  404. if( aSheetPath )
  405. {
  406. m_sheetPath = aSheetPath;
  407. EDA_ITEM::IterateForward( aSheetPath->LastDrawList(), this, NULL, m_ScanTypes );
  408. }
  409. else
  410. {
  411. SCH_SHEET_LIST schematic;
  412. m_sheetPath = schematic.GetFirst();
  413. while( m_sheetPath != NULL )
  414. {
  415. EDA_ITEM::IterateForward( m_sheetPath->LastDrawList(), this, NULL, m_ScanTypes );
  416. m_sheetPath = schematic.GetNext();
  417. }
  418. }
  419. #if defined(DEBUG)
  420. dump();
  421. #endif
  422. if( m_List.size() != m_data.size() )
  423. {
  424. wxFAIL_MSG( wxT( "List size mismatch." ) );
  425. m_List.clear();
  426. m_data.clear();
  427. }
  428. }
  429. SEARCH_RESULT SCH_TYPE_COLLECTOR::Inspect( EDA_ITEM* aItem, const void* aTestData )
  430. {
  431. // The Vist() function only visits the testItem if its type was in the
  432. // the scanList, so therefore we can collect anything given to us here.
  433. Append( aItem );
  434. return SEARCH_CONTINUE;
  435. }
  436. void SCH_TYPE_COLLECTOR::Collect( SCH_ITEM* aItem, const KICAD_T aFilterList[] )
  437. {
  438. Empty(); // empty the collection
  439. SetScanTypes( aFilterList );
  440. EDA_ITEM::IterateForward( aItem, this, NULL, m_ScanTypes );
  441. }