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.

1650 lines
42 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright (C) 2008-2011 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 class_libentry.cpp
  27. */
  28. #include <fctsys.h>
  29. #include <macros.h>
  30. #include <kicad_string.h>
  31. #include <class_drawpanel.h>
  32. #include <plot_common.h>
  33. #include <gr_basic.h>
  34. #include <class_sch_screen.h>
  35. #include <richio.h>
  36. #include <general.h>
  37. #include <protos.h>
  38. #include <template_fieldnames.h>
  39. #include <transform.h>
  40. #include <class_library.h>
  41. #include <class_libentry.h>
  42. #include <lib_pin.h>
  43. #include <lib_arc.h>
  44. #include <lib_bezier.h>
  45. #include <lib_circle.h>
  46. #include <lib_polyline.h>
  47. #include <lib_rectangle.h>
  48. #include <lib_text.h>
  49. #include <boost/foreach.hpp>
  50. // Set this to 1 to print debugging output in alias and component destructors to verify
  51. // objects get cleaned up properly.
  52. #if defined( TRACE_DESTRUCTOR )
  53. #undef TRACE_DESTRUCTOR
  54. #endif
  55. #define TRACE_DESTRUCTOR 0
  56. LIB_ALIAS::LIB_ALIAS( const wxString& aName, LIB_COMPONENT* aRootComponent ):
  57. EDA_ITEM( LIB_ALIAS_T )
  58. {
  59. root = aRootComponent;
  60. name = aName;
  61. }
  62. LIB_ALIAS::LIB_ALIAS( const LIB_ALIAS& aAlias, LIB_COMPONENT* aRootComponent ) :
  63. EDA_ITEM( aAlias )
  64. {
  65. name = aAlias.name;
  66. root = aRootComponent;
  67. description = aAlias.description;
  68. keyWords = aAlias.keyWords;
  69. docFileName = aAlias.docFileName;
  70. }
  71. LIB_ALIAS::~LIB_ALIAS()
  72. {
  73. #if TRACE_DESTRUCTOR
  74. wxLogDebug( wxT( "Destroying alias \"%s\" of component \"%s\" with alias list count %d." ),
  75. GetChars( name ), GetChars( root->GetName() ), root->m_aliases.size() );
  76. #endif
  77. }
  78. wxString LIB_ALIAS::GetLibraryName()
  79. {
  80. if( GetComponent() )
  81. return GetComponent()->GetLibraryName();
  82. return wxString( _( "none" ) );
  83. }
  84. bool LIB_ALIAS::IsRoot() const
  85. {
  86. return name.CmpNoCase( root->GetName() ) == 0;
  87. }
  88. CMP_LIBRARY* LIB_ALIAS::GetLibrary()
  89. {
  90. return root->GetLibrary();
  91. }
  92. bool LIB_ALIAS::SaveDoc( OUTPUTFORMATTER& aFormatter )
  93. {
  94. if( description.IsEmpty() && keyWords.IsEmpty() && docFileName.IsEmpty() )
  95. return true;
  96. try
  97. {
  98. aFormatter.Print( 0, "#\n$CMP %s\n", TO_UTF8( name ) );
  99. if( !description.IsEmpty() )
  100. aFormatter.Print( 0, "D %s\n", TO_UTF8( description ) );
  101. if( !keyWords.IsEmpty() )
  102. aFormatter.Print( 0, "K %s\n", TO_UTF8( keyWords ) );
  103. if( !docFileName.IsEmpty() )
  104. aFormatter.Print( 0, "F %s\n", TO_UTF8( docFileName ) );
  105. aFormatter.Print( 0, "$ENDCMP\n" );
  106. }
  107. catch( IO_ERROR ioe )
  108. {
  109. return false;
  110. }
  111. return true;
  112. }
  113. bool LIB_ALIAS::operator==( const wxChar* aName ) const
  114. {
  115. return name.CmpNoCase( aName ) == 0;
  116. }
  117. bool operator<( const LIB_ALIAS& aItem1, const LIB_ALIAS& aItem2 )
  118. {
  119. return aItem1.GetName().CmpNoCase( aItem2.GetName() ) < 0;
  120. }
  121. int LibraryEntryCompare( const LIB_ALIAS* aItem1, const LIB_ALIAS* aItem2 )
  122. {
  123. return aItem1->GetName().CmpNoCase( aItem2->GetName() );
  124. }
  125. LIB_COMPONENT::LIB_COMPONENT( const wxString& aName, CMP_LIBRARY* aLibrary ) :
  126. EDA_ITEM( LIB_COMPONENT_T )
  127. {
  128. m_name = aName;
  129. m_library = aLibrary;
  130. m_dateModified = 0;
  131. m_unitCount = 1;
  132. m_pinNameOffset = 40;
  133. m_options = ENTRY_NORMAL;
  134. m_unitsLocked = false;
  135. m_showPinNumbers = true;
  136. m_showPinNames = true;
  137. // Create the default alias if the name parameter is not empty.
  138. if( !aName.IsEmpty() )
  139. m_aliases.push_back( new LIB_ALIAS( aName, this ) );
  140. // Add the MANDATORY_FIELDS in RAM only. These are assumed to be present
  141. // when the field editors are invoked.
  142. LIB_FIELD* value = new LIB_FIELD( this, VALUE );
  143. value->m_Text = aName;
  144. drawings.push_back( value );
  145. drawings.push_back( new LIB_FIELD( this, REFERENCE ) );
  146. drawings.push_back( new LIB_FIELD( this, FOOTPRINT ) );
  147. drawings.push_back( new LIB_FIELD( this, DATASHEET ) );
  148. }
  149. LIB_COMPONENT::LIB_COMPONENT( LIB_COMPONENT& aComponent, CMP_LIBRARY* aLibrary ) :
  150. EDA_ITEM( aComponent )
  151. {
  152. LIB_ITEM* newItem;
  153. m_library = aLibrary;
  154. m_name = aComponent.m_name;
  155. m_FootprintList = aComponent.m_FootprintList;
  156. m_unitCount = aComponent.m_unitCount;
  157. m_unitsLocked = aComponent.m_unitsLocked;
  158. m_pinNameOffset = aComponent.m_pinNameOffset;
  159. m_showPinNumbers = aComponent.m_showPinNumbers;
  160. m_showPinNames = aComponent.m_showPinNames;
  161. m_dateModified = aComponent.m_dateModified;
  162. m_options = aComponent.m_options;
  163. BOOST_FOREACH( LIB_ITEM& oldItem, aComponent.GetDrawItemList() )
  164. {
  165. if( oldItem.IsNew() )
  166. continue;
  167. newItem = (LIB_ITEM*) oldItem.Clone();
  168. newItem->SetParent( this );
  169. drawings.push_back( newItem );
  170. }
  171. for( size_t i = 0; i < aComponent.m_aliases.size(); i++ )
  172. {
  173. LIB_ALIAS* alias = new LIB_ALIAS( *aComponent.m_aliases[i], this );
  174. m_aliases.push_back( alias );
  175. }
  176. }
  177. LIB_COMPONENT::~LIB_COMPONENT()
  178. {
  179. #if TRACE_DESTRUCTOR
  180. wxLogDebug( wxT( "Destroying component <%s> with alias list count of %d" ),
  181. GetChars( GetName() ), m_aliases.size() );
  182. #endif
  183. // If the component is being delete directly rather than trough the library, free all
  184. // of the memory allocated by the aliases.
  185. if( !m_aliases.empty() )
  186. {
  187. LIB_ALIAS* alias;
  188. while( !m_aliases.empty() )
  189. {
  190. alias = m_aliases.back();
  191. m_aliases.pop_back();
  192. delete alias;
  193. }
  194. }
  195. }
  196. wxString LIB_COMPONENT::GetLibraryName()
  197. {
  198. if( m_library != NULL )
  199. return m_library->GetName();
  200. return wxString( _( "none" ) );
  201. }
  202. wxString LIB_COMPONENT::ReturnSubReference( int aUnit )
  203. {
  204. wxString subRef;
  205. #if defined(KICAD_GOST)
  206. subRef.Printf( wxT(".%d" ), aUnit);
  207. #else
  208. subRef.Append( wxChar(aUnit + 'A' - 1) );
  209. #endif
  210. return subRef;
  211. }
  212. void LIB_COMPONENT::SetName( const wxString& aName )
  213. {
  214. m_name = aName;
  215. GetValueField().m_Text = aName;
  216. m_aliases[0]->SetName( aName );
  217. }
  218. void LIB_COMPONENT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDc, const wxPoint& aOffset, int aMulti,
  219. int aConvert, int aDrawMode, int aColor, const TRANSFORM& aTransform,
  220. bool aShowPinText, bool aDrawFields, bool aOnlySelected )
  221. {
  222. BASE_SCREEN* screen = aPanel->GetScreen();
  223. GRSetDrawMode( aDc, aDrawMode );
  224. /* draw background for filled items using background option
  225. * Solid lines will be drawn after the background
  226. * Note also, background is not drawn when:
  227. * printing in black and white
  228. * If the color is not the default color (aColor != -1 )
  229. */
  230. if( ! (screen->m_IsPrinting && GetGRForceBlackPenState()) && (aColor == -1) )
  231. {
  232. BOOST_FOREACH( LIB_ITEM& drawItem, drawings )
  233. {
  234. if( drawItem.m_Fill != FILLED_WITH_BG_BODYCOLOR )
  235. continue;
  236. if( aOnlySelected && !drawItem.IsSelected() )
  237. continue;
  238. // Do not draw an item while moving (the cursor handler does that)
  239. if( drawItem.m_Flags & IS_MOVED )
  240. continue;
  241. /* Do not draw items not attached to the current part */
  242. if( aMulti && drawItem.m_Unit && ( drawItem.m_Unit != aMulti ) )
  243. continue;
  244. if( aConvert && drawItem.m_Convert && ( drawItem.m_Convert != aConvert ) )
  245. continue;
  246. if( drawItem.Type() == LIB_FIELD_T )
  247. continue;
  248. if( drawItem.Type() == LIB_FIELD_T )
  249. {
  250. drawItem.Draw( aPanel, aDc, aOffset, aColor, aDrawMode, (void*) NULL, aTransform );
  251. }
  252. // Now, draw only the background for items with
  253. // m_Fill == FILLED_WITH_BG_BODYCOLOR:
  254. drawItem.Draw( aPanel, aDc, aOffset, aColor, aDrawMode, (void*) false, aTransform );
  255. }
  256. }
  257. BOOST_FOREACH( LIB_ITEM& drawItem, drawings )
  258. {
  259. if( aOnlySelected && !drawItem.IsSelected() )
  260. continue;
  261. // Do not draw an item while moving (the cursor handler does that)
  262. if( drawItem.m_Flags & IS_MOVED )
  263. continue;
  264. /* Do not draw items not attached to the current part */
  265. if( aMulti && drawItem.m_Unit && ( drawItem.m_Unit != aMulti ) )
  266. continue;
  267. if( aConvert && drawItem.m_Convert && ( drawItem.m_Convert != aConvert ) )
  268. continue;
  269. if( !aDrawFields && drawItem.Type() == LIB_FIELD_T )
  270. continue;
  271. if( drawItem.Type() == LIB_PIN_T )
  272. {
  273. drawItem.Draw( aPanel, aDc, aOffset, aColor, aDrawMode, (void*) aShowPinText,
  274. aTransform );
  275. }
  276. else if( drawItem.Type() == LIB_FIELD_T )
  277. {
  278. drawItem.Draw( aPanel, aDc, aOffset, aColor, aDrawMode, (void*) NULL, aTransform );
  279. }
  280. else
  281. {
  282. bool forceNoFill = drawItem.m_Fill == FILLED_WITH_BG_BODYCOLOR;
  283. drawItem.Draw( aPanel, aDc, aOffset, aColor, aDrawMode, (void*) forceNoFill,
  284. aTransform );
  285. }
  286. }
  287. /* Enable this to draw the anchor of the component. */
  288. #if 0
  289. int len = aDc->DeviceToLogicalXRel( 3 );
  290. GRLine( aPanel->GetClipBox(), aDc, aOffset.x, aOffset.y - len, aOffset.x,
  291. aOffset.y + len, 0, aColor );
  292. GRLine( aPanel->GetClipBox(), aDc, aOffset.x - len, aOffset.y, aOffset.x + len,
  293. aOffset.y, 0, aColor );
  294. #endif
  295. /* Enable this to draw the bounding box around the component to validate
  296. * the bounding box calculations. */
  297. #if 0
  298. EDA_RECT bBox = GetBoundingBox( aMulti, aConvert );
  299. GRRect( aPanel->GetClipBox(), aDc, bBox.GetOrigin().x, bBox.GetOrigin().y,
  300. bBox.GetEnd().x, bBox.GetEnd().y, 0, LIGHTMAGENTA );
  301. #endif
  302. }
  303. void LIB_COMPONENT::Plot( PLOTTER* aPlotter, int aUnit, int aConvert,
  304. const wxPoint& aOffset, const TRANSFORM& aTransform )
  305. {
  306. wxASSERT( aPlotter != NULL );
  307. BOOST_FOREACH( LIB_ITEM& item, drawings )
  308. {
  309. if( aUnit && item.m_Unit && ( item.m_Unit != aUnit ) )
  310. continue;
  311. if( aConvert && item.m_Convert && ( item.m_Convert != aConvert ) )
  312. continue;
  313. aPlotter->set_color( ReturnLayerColor( LAYER_DEVICE ) );
  314. bool fill = aPlotter->get_color_mode();
  315. item.Plot( aPlotter, aOffset, fill, aTransform );
  316. }
  317. }
  318. void LIB_COMPONENT::RemoveDrawItem( LIB_ITEM* aItem, EDA_DRAW_PANEL* aPanel, wxDC* aDc )
  319. {
  320. wxASSERT( aItem != NULL );
  321. // none of the MANDATOR_FIELDS may be removed in RAM, but they may be
  322. // omitted when saving to disk.
  323. if( aItem->Type() == LIB_FIELD_T )
  324. {
  325. LIB_FIELD* field = (LIB_FIELD*) aItem;
  326. if( field->GetId() < MANDATORY_FIELDS )
  327. {
  328. wxLogWarning( _( "An attempt was made to remove the %s field \
  329. from component %s in library %s." ),
  330. GetChars( field->GetName() ), GetChars( GetName() ),
  331. GetChars( GetLibraryName() ) );
  332. return;
  333. }
  334. }
  335. LIB_ITEMS::iterator i;
  336. for( i = drawings.begin(); i < drawings.end(); i++ )
  337. {
  338. if( *i == aItem )
  339. {
  340. if( aDc != NULL )
  341. aItem->Draw( aPanel, aDc, wxPoint( 0, 0 ), -1, g_XorMode, NULL, DefaultTransform );
  342. drawings.erase( i );
  343. SetModified();
  344. break;
  345. }
  346. }
  347. }
  348. void LIB_COMPONENT::AddDrawItem( LIB_ITEM* aItem )
  349. {
  350. wxASSERT( aItem != NULL );
  351. drawings.push_back( aItem );
  352. drawings.sort();
  353. }
  354. LIB_ITEM* LIB_COMPONENT::GetNextDrawItem( LIB_ITEM* aItem, KICAD_T aType )
  355. {
  356. /* Return the next draw object pointer.
  357. * If item is NULL return the first item of type in the list.
  358. */
  359. if( drawings.empty() )
  360. return NULL;
  361. if( aItem == NULL && aType == TYPE_NOT_INIT ) // type is unspecified
  362. return &drawings[0];
  363. // Search for last item
  364. size_t idx = 0;
  365. if( aItem )
  366. {
  367. for( ; idx < drawings.size(); idx++ )
  368. {
  369. if( aItem == &drawings[idx] )
  370. {
  371. idx++; // Prepare the next item search
  372. break;
  373. }
  374. }
  375. }
  376. // Search the next item
  377. for( ; idx < drawings.size(); idx++ )
  378. {
  379. if( aType == TYPE_NOT_INIT || drawings[ idx ].Type() == aType )
  380. return &drawings[ idx ];
  381. }
  382. return NULL;
  383. }
  384. void LIB_COMPONENT::GetPins( LIB_PINS& aList, int aUnit, int aConvert )
  385. {
  386. /* Notes:
  387. * when aUnit == 0: no unit filtering
  388. * when aConvert == 0: no convert (shape selection) filtering
  389. * when .m_Unit == 0, the body item is common to units
  390. * when .m_Convert == 0, the body item is common to shapes
  391. */
  392. BOOST_FOREACH( LIB_ITEM& item, drawings )
  393. {
  394. if( item.Type() != LIB_PIN_T ) // we search pins only
  395. continue;
  396. // Unit filtering:
  397. if( aUnit && item.m_Unit && ( item.m_Unit != aUnit ) )
  398. continue;
  399. // Shape filtering:
  400. if( aConvert && item.m_Convert && ( item.m_Convert != aConvert ) )
  401. continue;
  402. aList.push_back( (LIB_PIN*) &item );
  403. }
  404. }
  405. LIB_PIN* LIB_COMPONENT::GetPin( const wxString& aNumber, int aUnit, int aConvert )
  406. {
  407. wxString pNumber;
  408. LIB_PINS pinList;
  409. GetPins( pinList, aUnit, aConvert );
  410. for( size_t i = 0; i < pinList.size(); i++ )
  411. {
  412. wxASSERT( pinList[i]->Type() == LIB_PIN_T );
  413. pinList[i]->ReturnPinStringNum( pNumber );
  414. if( aNumber == pNumber )
  415. return pinList[i];
  416. }
  417. return NULL;
  418. }
  419. bool LIB_COMPONENT::Save( OUTPUTFORMATTER& aFormatter )
  420. {
  421. size_t i;
  422. LIB_FIELD& value = GetValueField();
  423. /* First line: it s a comment (component name for readers) */
  424. aFormatter.Print( 0, "#\n# %s\n#\n", TO_UTF8( value.m_Text ) );
  425. /* Save data */
  426. aFormatter.Print( 0, "DEF" );
  427. if( value.IsVisible() )
  428. {
  429. aFormatter.Print( 0, " %s", TO_UTF8( value.m_Text ) );
  430. }
  431. else
  432. {
  433. aFormatter.Print( 0, " ~%s", TO_UTF8( value.m_Text ) );
  434. }
  435. LIB_FIELD& reference = GetReferenceField();
  436. if( !reference.m_Text.IsEmpty() )
  437. {
  438. aFormatter.Print( 0, " %s", TO_UTF8( reference.m_Text ) );
  439. }
  440. else
  441. {
  442. aFormatter.Print( 0, " ~" );
  443. }
  444. aFormatter.Print( 0, " %d %d %c %c %d %c %c\n",
  445. 0, m_pinNameOffset,
  446. m_showPinNumbers ? 'Y' : 'N',
  447. m_showPinNames ? 'Y' : 'N',
  448. m_unitCount, m_unitsLocked ? 'L' : 'F',
  449. m_options == ENTRY_POWER ? 'P' : 'N' );
  450. if( !SaveDateAndTime( aFormatter ) )
  451. return false;
  452. LIB_FIELDS fields;
  453. GetFields( fields );
  454. // Fixed fields:
  455. // may have their own save policy so there is a separate loop for them.
  456. for( i = 0; i < MANDATORY_FIELDS; ++i )
  457. {
  458. if( !fields[i].m_Text.IsEmpty() )
  459. {
  460. if( !fields[i].Save( aFormatter ) )
  461. return false;
  462. }
  463. }
  464. // User defined fields:
  465. // may have their own save policy so there is a separate loop for them.
  466. int fieldId = MANDATORY_FIELDS; // really wish this would go away.
  467. for( i = MANDATORY_FIELDS; i < fields.size(); ++i )
  468. {
  469. // There is no need to save empty fields, i.e. no reason to preserve field
  470. // names now that fields names come in dynamically through the template
  471. // fieldnames.
  472. if( !fields[i].m_Text.IsEmpty() )
  473. {
  474. fields[i].SetId( fieldId++ );
  475. if( !fields[i].Save( aFormatter ) )
  476. return false;
  477. }
  478. }
  479. // Save the alias list: a line starting by "ALIAS". The first alias is the root
  480. // and has the same name as the component. In the old library file format this
  481. // alias does not get added to the alias list.
  482. if( m_aliases.size() > 1 )
  483. {
  484. aFormatter.Print( 0, "ALIAS" );
  485. for( i = 1; i < m_aliases.size(); i++ )
  486. {
  487. aFormatter.Print( 0, " %s", TO_UTF8( m_aliases[i]->GetName() ) );
  488. }
  489. aFormatter.Print( 0, "\n" );
  490. }
  491. /* Write the footprint filter list */
  492. if( m_FootprintList.GetCount() != 0 )
  493. {
  494. aFormatter.Print( 0, "$FPLIST\n" );
  495. for( i = 0; i < m_FootprintList.GetCount(); i++ )
  496. {
  497. aFormatter.Print( 0, " %s\n", TO_UTF8( m_FootprintList[i] ) );
  498. }
  499. aFormatter.Print( 0, "$ENDFPLIST\n" );
  500. }
  501. /* Save graphics items (including pins) */
  502. if( !drawings.empty() )
  503. {
  504. /* we sort the draw items, in order to have an edition more easy,
  505. * when a file editing "by hand" is made */
  506. drawings.sort();
  507. aFormatter.Print( 0, "DRAW\n" );
  508. BOOST_FOREACH( LIB_ITEM& item, drawings )
  509. {
  510. if( item.Type() == LIB_FIELD_T )
  511. continue;
  512. if( !item.Save( aFormatter ) )
  513. return false;
  514. }
  515. aFormatter.Print( 0, "ENDDRAW\n" );
  516. }
  517. aFormatter.Print( 0, "ENDDEF\n" );
  518. return true;
  519. }
  520. bool LIB_COMPONENT::Load( LINE_READER& aLineReader, wxString& aErrorMsg )
  521. {
  522. int unused;
  523. char* p;
  524. char* componentName;
  525. char* prefix = NULL;
  526. char* line;
  527. bool Res;
  528. wxString Msg;
  529. line = aLineReader.Line();
  530. p = strtok( line, " \t\r\n" );
  531. if( strcmp( p, "DEF" ) != 0 )
  532. {
  533. aErrorMsg.Printf( wxT( "DEF command expected in line %d, aborted." ),
  534. aLineReader.LineNumber() );
  535. return false;
  536. }
  537. /* Read DEF line: */
  538. char drawnum = 0;
  539. char drawname = 0;
  540. if( ( componentName = strtok( NULL, " \t\n" ) ) == NULL /* Part name: */
  541. || ( prefix = strtok( NULL, " \t\n" ) ) == NULL /* Prefix name: */
  542. || ( p = strtok( NULL, " \t\n" ) ) == NULL /* NumOfPins: */
  543. || sscanf( p, "%d", &unused ) != 1
  544. || ( p = strtok( NULL, " \t\n" ) ) == NULL /* TextInside: */
  545. || sscanf( p, "%d", &m_pinNameOffset ) != 1
  546. || ( p = strtok( NULL, " \t\n" ) ) == NULL /* DrawNums: */
  547. || sscanf( p, "%c", &drawnum ) != 1
  548. || ( p = strtok( NULL, " \t\n" ) ) == NULL /* DrawNums: */
  549. || sscanf( p, "%c", &drawname ) != 1
  550. || ( p = strtok( NULL, " \t\n" ) ) == NULL /* m_unitCount: */
  551. || sscanf( p, "%d", &m_unitCount ) != 1 )
  552. {
  553. aErrorMsg.Printf( wxT( "Wrong DEF format in line %d, skipped." ),
  554. aLineReader.LineNumber() );
  555. while( aLineReader.ReadLine() )
  556. {
  557. line = aLineReader.Line();
  558. p = strtok( line, " \t\n" );
  559. if( stricmp( p, "ENDDEF" ) == 0 )
  560. break;
  561. }
  562. return false;
  563. }
  564. // Ensure m_unitCount is >= 1 (could be read as 0 in old libraries)
  565. if( m_unitCount < 1 )
  566. m_unitCount = 1;
  567. m_showPinNumbers = ( drawnum == 'N' ) ? false : true;
  568. m_showPinNames = ( drawname == 'N' ) ? false : true;
  569. /* Copy part name and prefix. */
  570. LIB_FIELD& value = GetValueField();
  571. if( componentName[0] != '~' )
  572. {
  573. m_name = value.m_Text = FROM_UTF8( componentName );
  574. m_name = value.m_Text = m_name.MakeUpper();
  575. }
  576. else
  577. {
  578. m_name = value.m_Text = FROM_UTF8( &componentName[1] );
  579. value.m_Attributs |= TEXT_NO_VISIBLE;
  580. }
  581. // Add the root alias to the alias list.
  582. m_aliases.push_back( new LIB_ALIAS( m_name, this ) );
  583. LIB_FIELD& reference = GetReferenceField();
  584. if( strcmp( prefix, "~" ) == 0 )
  585. {
  586. reference.m_Text.Empty();
  587. reference.m_Attributs |= TEXT_NO_VISIBLE;
  588. }
  589. else
  590. {
  591. reference.m_Text = FROM_UTF8( prefix );
  592. }
  593. // Copy optional infos
  594. if( ( p = strtok( NULL, " \t\n" ) ) != NULL && *p == 'L' )
  595. m_unitsLocked = true;
  596. if( ( p = strtok( NULL, " \t\n" ) ) != NULL && *p == 'P' )
  597. m_options = ENTRY_POWER;
  598. // Read next lines, until "ENDDEF" is found
  599. while( aLineReader.ReadLine() )
  600. {
  601. line = aLineReader.Line();
  602. p = strtok( line, " \t\r\n" );
  603. /* This is the error flag ( if an error occurs, Res = false) */
  604. Res = true;
  605. if( *line == '#' ) // a comment
  606. continue;
  607. if( (*line == 'T') && (*(line + 1) == 'i') )
  608. Res = LoadDateAndTime( aLineReader );
  609. else if( *line == 'F' )
  610. Res = LoadField( aLineReader, Msg );
  611. else if( strcmp( p, "ENDDEF" ) == 0 ) // End of component description
  612. break;
  613. else if( strcmp( p, "DRAW" ) == 0 )
  614. Res = LoadDrawEntries( aLineReader, Msg );
  615. else if( strncmp( p, "ALIAS", 5 ) == 0 )
  616. {
  617. p = strtok( NULL, "\r\n" );
  618. Res = LoadAliases( p, aErrorMsg );
  619. }
  620. else if( strncmp( p, "$FPLIST", 5 ) == 0 )
  621. Res = LoadFootprints( aLineReader, Msg );
  622. /* End line or block analysis: test for an error */
  623. if( !Res )
  624. {
  625. if( Msg.IsEmpty() )
  626. aErrorMsg.Printf( wxT( "error occurred at line %d " ), aLineReader.LineNumber() );
  627. else
  628. aErrorMsg.Printf( wxT( "error <%s> occurred at line %d " ),
  629. GetChars( Msg ), aLineReader.LineNumber() );
  630. return false;
  631. }
  632. }
  633. /* If we are here, this part is O.k. - put it in: */
  634. drawings.sort();
  635. return true;
  636. }
  637. bool LIB_COMPONENT::LoadDrawEntries( LINE_READER& aLineReader, wxString& aErrorMsg )
  638. {
  639. char* line;
  640. LIB_ITEM* newEntry = NULL;
  641. while( true )
  642. {
  643. if( !aLineReader.ReadLine() )
  644. {
  645. aErrorMsg = wxT( "file ended prematurely loading component draw element" );
  646. return false;
  647. }
  648. line = aLineReader.Line();
  649. if( strncmp( line, "ENDDRAW", 7 ) == 0 )
  650. break;
  651. newEntry = NULL;
  652. switch( line[0] )
  653. {
  654. case 'A': /* Arc */
  655. newEntry = ( LIB_ITEM* ) new LIB_ARC( this );
  656. break;
  657. case 'C': /* Circle */
  658. newEntry = ( LIB_ITEM* ) new LIB_CIRCLE( this );
  659. break;
  660. case 'T': /* Text */
  661. newEntry = ( LIB_ITEM* ) new LIB_TEXT( this );
  662. break;
  663. case 'S': /* Square */
  664. newEntry = ( LIB_ITEM* ) new LIB_RECTANGLE( this );
  665. break;
  666. case 'X': /* Pin Description */
  667. newEntry = ( LIB_ITEM* ) new LIB_PIN( this );
  668. break;
  669. case 'P': /* Polyline */
  670. newEntry = ( LIB_ITEM* ) new LIB_POLYLINE( this );
  671. break;
  672. case 'B': /* Bezier Curves */
  673. newEntry = ( LIB_ITEM* ) new LIB_BEZIER( this );
  674. break;
  675. default:
  676. aErrorMsg.Printf( wxT( "undefined DRAW command %c" ), line[0] );
  677. return false;
  678. }
  679. if( !newEntry->Load( aLineReader, aErrorMsg ) )
  680. {
  681. aErrorMsg.Printf( wxT( "error <%s> in DRAW command %c" ),
  682. GetChars( aErrorMsg ), line[0] );
  683. SAFE_DELETE( newEntry );
  684. /* Flush till end of draw section */
  685. do
  686. {
  687. if( !aLineReader.ReadLine() )
  688. {
  689. aErrorMsg = wxT( "file ended prematurely while attempting \
  690. to flush to end of drawing section." );
  691. return false;
  692. }
  693. } while( strncmp( line, "ENDDRAW", 7 ) != 0 );
  694. return false;
  695. }
  696. else
  697. {
  698. drawings.push_back( newEntry );
  699. }
  700. }
  701. return true;
  702. }
  703. bool LIB_COMPONENT::LoadAliases( char* aLine, wxString& aErrorMsg )
  704. {
  705. char* text = strtok( aLine, " \t\r\n" );
  706. while( text )
  707. {
  708. m_aliases.push_back( new LIB_ALIAS( FROM_UTF8( text ), this ) );
  709. text = strtok( NULL, " \t\r\n" );
  710. }
  711. return true;
  712. }
  713. bool LIB_COMPONENT::LoadField( LINE_READER& aLineReader, wxString& aErrorMsg )
  714. {
  715. LIB_FIELD* field = new LIB_FIELD( this );
  716. if( !field->Load( aLineReader, aErrorMsg ) )
  717. {
  718. SAFE_DELETE( field );
  719. return false;
  720. }
  721. if( field->GetId() < MANDATORY_FIELDS )
  722. {
  723. LIB_FIELD* fixedField = GetField( field->GetId() );
  724. // this will fire only if somebody broke a constructor or editor.
  725. // MANDATORY_FIELDS are always present in ram resident components, no
  726. // exceptions, and they always have their names set, even fixed fields.
  727. wxASSERT( fixedField );
  728. *fixedField = *field;
  729. if( field->GetId() == VALUE )
  730. m_name = field->m_Text;
  731. SAFE_DELETE( field );
  732. }
  733. else
  734. {
  735. drawings.push_back( field );
  736. }
  737. return true;
  738. }
  739. bool LIB_COMPONENT::LoadFootprints( LINE_READER& aLineReader, wxString& aErrorMsg )
  740. {
  741. char* line;
  742. char* p;
  743. while( true )
  744. {
  745. if( !aLineReader.ReadLine() )
  746. {
  747. aErrorMsg = wxT( "file ended prematurely while loading footprints" );
  748. return false;
  749. }
  750. line = aLineReader.Line();
  751. p = strtok( line, " \t\r\n" );
  752. if( stricmp( p, "$ENDFPLIST" ) == 0 )
  753. break;
  754. m_FootprintList.Add( FROM_UTF8( p ) );
  755. }
  756. return true;
  757. }
  758. EDA_RECT LIB_COMPONENT::GetBoundingBox( int aUnit, int aConvert ) const
  759. {
  760. EDA_RECT bBox( wxPoint( 0, 0 ), wxSize( 0, 0 ) );
  761. BOOST_FOREACH( const LIB_ITEM& item, drawings )
  762. {
  763. if( ( item.m_Unit > 0 ) && ( ( m_unitCount > 1 ) && ( aUnit > 0 )
  764. && ( aUnit != item.m_Unit ) ) )
  765. continue;
  766. if( item.m_Convert > 0 && ( ( aConvert > 0 ) && ( aConvert != item.m_Convert ) ) )
  767. continue;
  768. if ( ( item.Type() == LIB_FIELD_T ) && !( ( LIB_FIELD& ) item ).IsVisible() )
  769. continue;
  770. bBox.Merge( item.GetBoundingBox() );
  771. }
  772. return bBox;
  773. }
  774. EDA_RECT LIB_COMPONENT::GetBodyBoundingBox( int aUnit, int aConvert ) const
  775. {
  776. EDA_RECT bBox( wxPoint( 0, 0 ), wxSize( 0, 0 ) );
  777. BOOST_FOREACH( const LIB_ITEM& item, drawings )
  778. {
  779. if( ( item.m_Unit > 0 ) && ( ( m_unitCount > 1 ) && ( aUnit > 0 )
  780. && ( aUnit != item.m_Unit ) ) )
  781. continue;
  782. if( item.m_Convert > 0 && ( ( aConvert > 0 ) && ( aConvert != item.m_Convert ) ) )
  783. continue;
  784. if ( item.Type() == LIB_FIELD_T )
  785. continue;
  786. bBox.Merge( item.GetBoundingBox() );
  787. }
  788. return bBox;
  789. }
  790. void LIB_COMPONENT::deleteAllFields()
  791. {
  792. LIB_ITEMS::iterator it;
  793. for( it = drawings.begin(); it!=drawings.end(); /* deleting */ )
  794. {
  795. if( it->Type() != LIB_FIELD_T )
  796. {
  797. ++it;
  798. continue;
  799. }
  800. // 'it' is not advanced, but should point to next in list after erase()
  801. it = drawings.erase( it );
  802. }
  803. }
  804. void LIB_COMPONENT::SetFields( const std::vector <LIB_FIELD>& aFields )
  805. {
  806. deleteAllFields();
  807. for( unsigned i=0; i<aFields.size(); ++i )
  808. {
  809. // drawings is a ptr_vector, new and copy an object on the heap.
  810. LIB_FIELD* field = new LIB_FIELD( aFields[i] );
  811. drawings.push_back( field );
  812. }
  813. // Reorder drawings: transparent polygons first, pins and text last.
  814. // so texts have priority on screen.
  815. drawings.sort();
  816. }
  817. void LIB_COMPONENT::GetFields( LIB_FIELDS& aList )
  818. {
  819. LIB_FIELD* field;
  820. // The only caller of this function is the library field editor, so it
  821. // establishes policy here.
  822. // Grab the MANDATORY_FIELDS first, in expected order given by
  823. // enum NumFieldType
  824. for( int id=0; id<MANDATORY_FIELDS; ++id )
  825. {
  826. field = GetField( id );
  827. // the MANDATORY_FIELDS are exactly that in RAM.
  828. wxASSERT( field );
  829. aList.push_back( *field );
  830. }
  831. // Now grab all the rest of fields.
  832. BOOST_FOREACH( LIB_ITEM& item, drawings )
  833. {
  834. if( item.Type() != LIB_FIELD_T )
  835. continue;
  836. field = ( LIB_FIELD* ) &item;
  837. if( (unsigned) field->GetId() < MANDATORY_FIELDS )
  838. continue; // was added above
  839. aList.push_back( *field );
  840. }
  841. }
  842. LIB_FIELD* LIB_COMPONENT::GetField( int aId )
  843. {
  844. BOOST_FOREACH( LIB_ITEM& item, drawings )
  845. {
  846. if( item.Type() != LIB_FIELD_T )
  847. continue;
  848. LIB_FIELD* field = ( LIB_FIELD* ) &item;
  849. if( field->GetId() == aId )
  850. return field;
  851. }
  852. return NULL;
  853. }
  854. LIB_FIELD* LIB_COMPONENT::FindField( const wxString& aFieldName )
  855. {
  856. BOOST_FOREACH( LIB_ITEM& item, drawings )
  857. {
  858. if( item.Type() != LIB_FIELD_T )
  859. continue;
  860. LIB_FIELD* field = ( LIB_FIELD* ) &item;
  861. if( field->GetName() == aFieldName )
  862. return field;
  863. }
  864. return NULL;
  865. }
  866. LIB_FIELD& LIB_COMPONENT::GetValueField()
  867. {
  868. LIB_FIELD* field = GetField( VALUE );
  869. wxASSERT( field != NULL );
  870. return *field;
  871. }
  872. LIB_FIELD& LIB_COMPONENT::GetReferenceField()
  873. {
  874. LIB_FIELD* field = GetField( REFERENCE );
  875. wxASSERT( field != NULL );
  876. return *field;
  877. }
  878. bool LIB_COMPONENT::SaveDateAndTime( OUTPUTFORMATTER& aFormatter )
  879. {
  880. int year, mon, day, hour, min, sec;
  881. if( m_dateModified == 0 )
  882. return true;
  883. sec = m_dateModified & 63;
  884. min = ( m_dateModified >> 6 ) & 63;
  885. hour = ( m_dateModified >> 12 ) & 31;
  886. day = ( m_dateModified >> 17 ) & 31;
  887. mon = ( m_dateModified >> 22 ) & 15;
  888. year = ( m_dateModified >> 26 ) + 1990;
  889. aFormatter.Print( 0, "Ti %d/%d/%d %d:%d:%d\n", year, mon, day, hour, min, sec );
  890. return true;
  891. }
  892. bool LIB_COMPONENT::LoadDateAndTime( char* aLine )
  893. {
  894. int year, mon, day, hour, min, sec;
  895. year = mon = day = hour = min = sec = 0;
  896. strtok( aLine, " \r\t\n" );
  897. strtok( NULL, " \r\t\n" );
  898. if( sscanf( aLine, "%d/%d/%d %d:%d:%d", &year, &mon, &day, &hour, &min, &sec ) != 6 )
  899. return false;
  900. m_dateModified = ( sec & 63 ) + ( ( min & 63 ) << 6 ) +
  901. ( ( hour & 31 ) << 12 ) + ( ( day & 31 ) << 17 ) +
  902. ( ( mon & 15 ) << 22 ) + ( ( year - 1990 ) << 26 );
  903. return true;
  904. }
  905. void LIB_COMPONENT::SetOffset( const wxPoint& aOffset )
  906. {
  907. BOOST_FOREACH( LIB_ITEM& item, drawings )
  908. {
  909. item.SetOffset( aOffset );
  910. }
  911. }
  912. void LIB_COMPONENT::RemoveDuplicateDrawItems()
  913. {
  914. drawings.unique();
  915. }
  916. bool LIB_COMPONENT::HasConversion() const
  917. {
  918. BOOST_FOREACH( const LIB_ITEM& item, drawings )
  919. {
  920. if( item.m_Convert > 1 )
  921. return true;
  922. }
  923. return false;
  924. }
  925. void LIB_COMPONENT::ClearStatus()
  926. {
  927. BOOST_FOREACH( LIB_ITEM& item, drawings )
  928. {
  929. item.m_Flags = 0;
  930. }
  931. }
  932. int LIB_COMPONENT::SelectItems( EDA_RECT& aRect, int aUnit, int aConvert, bool aEditPinByPin )
  933. {
  934. int itemCount = 0;
  935. BOOST_FOREACH( LIB_ITEM& item, drawings )
  936. {
  937. item.ClearFlags( SELECTED );
  938. if( ( item.m_Unit && item.m_Unit != aUnit )
  939. || ( item.m_Convert && item.m_Convert != aConvert ) )
  940. {
  941. if( item.Type() != LIB_PIN_T )
  942. continue;
  943. // Specific rules for pins.
  944. if( aEditPinByPin || m_unitsLocked
  945. || ( item.m_Convert && item.m_Convert != aConvert ) )
  946. continue;
  947. }
  948. if( item.Inside( aRect ) )
  949. {
  950. item.SetFlags( SELECTED );
  951. itemCount++;
  952. }
  953. }
  954. return itemCount;
  955. }
  956. void LIB_COMPONENT::MoveSelectedItems( const wxPoint& aOffset )
  957. {
  958. BOOST_FOREACH( LIB_ITEM& item, drawings )
  959. {
  960. if( !item.IsSelected() )
  961. continue;
  962. item.SetOffset( aOffset );
  963. item.m_Flags = 0;
  964. }
  965. drawings.sort();
  966. }
  967. void LIB_COMPONENT::ClearSelectedItems()
  968. {
  969. BOOST_FOREACH( LIB_ITEM& item, drawings )
  970. {
  971. item.m_Flags = 0;
  972. }
  973. }
  974. void LIB_COMPONENT::DeleteSelectedItems()
  975. {
  976. LIB_ITEMS::iterator item = drawings.begin();
  977. // We *do not* remove the 2 mandatory fields: reference and value
  978. // so skip them (do not remove) if they are flagged selected.
  979. // Skip also not visible items.
  980. // But I think fields must not be deleted by a block delete command or other global command
  981. // because they are not really graphic items
  982. while( item != drawings.end() )
  983. {
  984. if( item->Type() == LIB_FIELD_T )
  985. {
  986. #if 0 // Set to 1 to allows fields deletion on block delete or other global command
  987. LIB_FIELD& field = ( LIB_FIELD& ) *item;
  988. if( (field.GetId() == REFERENCE) || (field.m_FieldId == VALUE) ||
  989. (field.m_Attributs & TEXT_NO_VISIBLE) )
  990. #endif
  991. item->ClearFlags( SELECTED );
  992. }
  993. if( !item->IsSelected() )
  994. item++;
  995. else
  996. item = drawings.erase( item );
  997. }
  998. }
  999. void LIB_COMPONENT::CopySelectedItems( const wxPoint& aOffset )
  1000. {
  1001. /* *do not* use iterators here, because new items
  1002. * are added to drawings that is a boost::ptr_vector.
  1003. * When push_back elements in buffer,
  1004. * a memory reallocation can happen and will break pointers
  1005. */
  1006. unsigned icnt = drawings.size();
  1007. for( unsigned ii = 0; ii < icnt; ii++ )
  1008. {
  1009. LIB_ITEM& item = drawings[ii];
  1010. // We *do not* copy fields because they are unique for the whole component
  1011. // so skip them (do not duplicate) if they are flagged selected.
  1012. if( item.Type() == LIB_FIELD_T )
  1013. item.ClearFlags( SELECTED );
  1014. if( !item.IsSelected() )
  1015. continue;
  1016. item.ClearFlags( SELECTED );
  1017. LIB_ITEM* newItem = (LIB_ITEM*) item.Clone();
  1018. newItem->SetFlags( SELECTED );
  1019. drawings.push_back( newItem );
  1020. }
  1021. MoveSelectedItems( aOffset );
  1022. drawings.sort();
  1023. }
  1024. void LIB_COMPONENT::MirrorSelectedItemsH( const wxPoint& aCenter )
  1025. {
  1026. BOOST_FOREACH( LIB_ITEM& item, drawings )
  1027. {
  1028. if( !item.IsSelected() )
  1029. continue;
  1030. item.MirrorHorizontal( aCenter );
  1031. item.m_Flags = 0;
  1032. }
  1033. drawings.sort();
  1034. }
  1035. void LIB_COMPONENT::MirrorSelectedItemsV( const wxPoint& aCenter )
  1036. {
  1037. BOOST_FOREACH( LIB_ITEM& item, drawings )
  1038. {
  1039. if( !item.IsSelected() )
  1040. continue;
  1041. item.MirrorVertical( aCenter );
  1042. item.m_Flags = 0;
  1043. }
  1044. drawings.sort();
  1045. }
  1046. void LIB_COMPONENT::RotateSelectedItems( const wxPoint& aCenter )
  1047. {
  1048. BOOST_FOREACH( LIB_ITEM& item, drawings )
  1049. {
  1050. if( !item.IsSelected() )
  1051. continue;
  1052. item.Rotate( aCenter );
  1053. item.m_Flags = 0;
  1054. }
  1055. drawings.sort();
  1056. }
  1057. LIB_ITEM* LIB_COMPONENT::LocateDrawItem( int aUnit, int aConvert,
  1058. KICAD_T aType, const wxPoint& aPoint )
  1059. {
  1060. BOOST_FOREACH( LIB_ITEM& item, drawings )
  1061. {
  1062. if( ( aUnit && item.m_Unit && ( aUnit != item.m_Unit) )
  1063. || ( aConvert && item.m_Convert && ( aConvert != item.m_Convert ) )
  1064. || ( ( item.Type() != aType ) && ( aType != TYPE_NOT_INIT ) ) )
  1065. continue;
  1066. if( item.HitTest( aPoint ) )
  1067. return &item;
  1068. }
  1069. return NULL;
  1070. }
  1071. LIB_ITEM* LIB_COMPONENT::LocateDrawItem( int aUnit, int aConvert, KICAD_T aType,
  1072. const wxPoint& aPoint, const TRANSFORM& aTransform )
  1073. {
  1074. /* we use LocateDrawItem( int aUnit, int convert, KICAD_T type, const
  1075. * wxPoint& pt ) to search items.
  1076. * because this function uses DefaultTransform as orient/mirror matrix
  1077. * we temporary copy aTransform in DefaultTransform
  1078. */
  1079. LIB_ITEM* item;
  1080. TRANSFORM transform = DefaultTransform;
  1081. DefaultTransform = aTransform;
  1082. item = LocateDrawItem( aUnit, aConvert, aType, aPoint );
  1083. //Restore matrix
  1084. DefaultTransform = transform;
  1085. return item;
  1086. }
  1087. void LIB_COMPONENT::SetPartCount( int aCount )
  1088. {
  1089. if( m_unitCount == aCount )
  1090. return;
  1091. if( aCount < m_unitCount )
  1092. {
  1093. LIB_ITEMS::iterator i;
  1094. i = drawings.begin();
  1095. while( i != drawings.end() )
  1096. {
  1097. if( i->m_Unit > aCount )
  1098. i = drawings.erase( i );
  1099. else
  1100. i++;
  1101. }
  1102. }
  1103. else
  1104. {
  1105. int prevCount = m_unitCount;
  1106. // We cannot use an iterator here, because when adding items in vector
  1107. // the buffer can be reallocated, that change the previous value of
  1108. // .begin() and .end() iterators and invalidate others iterators
  1109. unsigned imax = drawings.size();
  1110. for( unsigned ii = 0; ii < imax; ii++ )
  1111. {
  1112. if( drawings[ii].m_Unit != 1 )
  1113. continue;
  1114. for( int j = prevCount + 1; j <= aCount; j++ )
  1115. {
  1116. LIB_ITEM* newItem = (LIB_ITEM*) drawings[ii].Clone();
  1117. newItem->m_Unit = j;
  1118. drawings.push_back( newItem );
  1119. }
  1120. }
  1121. drawings.sort();
  1122. }
  1123. m_unitCount = aCount;
  1124. }
  1125. void LIB_COMPONENT::SetConversion( bool aSetConvert )
  1126. {
  1127. if( aSetConvert == HasConversion() )
  1128. return;
  1129. // Duplicate items to create the converted shape
  1130. if( aSetConvert )
  1131. {
  1132. BOOST_FOREACH( LIB_ITEM& item, drawings )
  1133. {
  1134. /* Only pins are duplicated. */
  1135. if( item.Type() != LIB_PIN_T )
  1136. continue;
  1137. if( item.m_Convert == 1 )
  1138. {
  1139. LIB_ITEM* newItem = (LIB_ITEM*) item.Clone();
  1140. newItem->m_Convert = 2;
  1141. drawings.push_back( newItem );
  1142. }
  1143. }
  1144. }
  1145. else
  1146. {
  1147. // Delete converted shape items because the converted shape does
  1148. // not exist
  1149. LIB_ITEMS::iterator i = drawings.begin();
  1150. while( i != drawings.end() )
  1151. {
  1152. if( i->m_Convert > 1 )
  1153. i = drawings.erase( i );
  1154. else
  1155. i++;
  1156. }
  1157. }
  1158. }
  1159. wxArrayString LIB_COMPONENT::GetAliasNames( bool aIncludeRoot ) const
  1160. {
  1161. wxArrayString names;
  1162. LIB_ALIASES::const_iterator it;
  1163. for( it=m_aliases.begin(); it<m_aliases.end(); ++it )
  1164. {
  1165. if( !aIncludeRoot && (*it)->IsRoot() )
  1166. continue;
  1167. names.Add( (*it)->GetName() );
  1168. }
  1169. return names;
  1170. }
  1171. bool LIB_COMPONENT::HasAlias( const wxString& aName ) const
  1172. {
  1173. wxCHECK2_MSG( !aName.IsEmpty(), return false,
  1174. wxT( "Cannot get alias with an empty name, bad programmer." ) );
  1175. for( size_t i = 0; i < m_aliases.size(); i++ )
  1176. {
  1177. if( aName.CmpNoCase( m_aliases[i]->GetName() ) == 0 )
  1178. return true;
  1179. }
  1180. return false;
  1181. }
  1182. void LIB_COMPONENT::SetAliases( const wxArrayString& aAliasList )
  1183. {
  1184. wxCHECK_RET( m_library == NULL,
  1185. wxT( "Component aliases cannot be changed when they are owned by a library." ) );
  1186. if( aAliasList == GetAliasNames() )
  1187. return;
  1188. // Add names not existing in the current component alias list.
  1189. for( size_t i = 0; i < aAliasList.GetCount(); i++ )
  1190. {
  1191. if( HasAlias( aAliasList[ i ] ) )
  1192. continue;
  1193. m_aliases.push_back( new LIB_ALIAS( aAliasList[ i ], this ) );
  1194. }
  1195. /* Remove names in the current component that are not in the new alias list. */
  1196. LIB_ALIASES::iterator it;
  1197. for( it = m_aliases.begin(); it < m_aliases.end(); it++ )
  1198. {
  1199. int index = aAliasList.Index( (*it)->GetName(), false );
  1200. if( index != wxNOT_FOUND || (*it)->IsRoot() )
  1201. continue;
  1202. it = m_aliases.erase( it );
  1203. }
  1204. }
  1205. void LIB_COMPONENT::RemoveAlias( const wxString& aName )
  1206. {
  1207. wxCHECK_RET( m_library == NULL,
  1208. wxT( "Component aliases cannot be changed when they are owned by a library." ) );
  1209. wxCHECK_RET( !aName.IsEmpty(), wxT( "Cannot get alias with an empty name." ) );
  1210. LIB_ALIASES::iterator it;
  1211. for( it = m_aliases.begin(); it < m_aliases.end(); it++ )
  1212. {
  1213. if( aName.CmpNoCase( (*it)->GetName() ) == 0 )
  1214. {
  1215. m_aliases.erase( it );
  1216. break;
  1217. }
  1218. }
  1219. }
  1220. LIB_ALIAS* LIB_COMPONENT::RemoveAlias( LIB_ALIAS* aAlias )
  1221. {
  1222. wxCHECK_MSG( aAlias != NULL, NULL, wxT( "Cannot remove alias by NULL pointer." ) );
  1223. LIB_ALIAS* nextAlias = NULL;
  1224. LIB_ALIASES::iterator it = find( m_aliases.begin(), m_aliases.end(), aAlias );
  1225. if( it != m_aliases.end() )
  1226. {
  1227. bool rename = aAlias->IsRoot();
  1228. it = m_aliases.erase( it );
  1229. delete aAlias;
  1230. if( !m_aliases.empty() )
  1231. {
  1232. if( it == m_aliases.end() )
  1233. it = m_aliases.begin();
  1234. nextAlias = (*it);
  1235. if( rename )
  1236. SetName( nextAlias->GetName() );
  1237. }
  1238. }
  1239. return nextAlias;
  1240. }
  1241. void LIB_COMPONENT::RemoveAllAliases()
  1242. {
  1243. // Remove all of the aliases except the root alias.
  1244. while( m_aliases.size() > 1 )
  1245. m_aliases.pop_back();
  1246. }
  1247. LIB_ALIAS* LIB_COMPONENT::GetAlias( const wxString& aName )
  1248. {
  1249. wxCHECK2_MSG( !aName.IsEmpty(), return NULL,
  1250. wxT( "Cannot get alias with an empty name. Bad programmer!" ) );
  1251. for( size_t i = 0; i < m_aliases.size(); i++ )
  1252. {
  1253. if( aName.CmpNoCase( m_aliases[i]->GetName() ) == 0 )
  1254. return m_aliases[i];
  1255. }
  1256. return NULL;
  1257. }
  1258. LIB_ALIAS* LIB_COMPONENT::GetAlias( size_t aIndex )
  1259. {
  1260. wxCHECK2_MSG( aIndex < m_aliases.size(), return NULL,
  1261. wxT( "Illegal alias list index, bad programmer." ) );
  1262. return m_aliases[aIndex];
  1263. }
  1264. void LIB_COMPONENT::AddAlias( const wxString& aName )
  1265. {
  1266. wxCHECK_RET( !HasAlias( aName ),
  1267. wxT( "Component <" ) + GetName() + wxT( "> already has an alias <" ) +
  1268. aName + wxT( ">. Bad programmer." ) );
  1269. m_aliases.push_back( new LIB_ALIAS( aName, this ) );
  1270. }