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.

1777 lines
46 KiB

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