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.

858 lines
28 KiB

18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
  1. /**************************************/
  2. /* annotate.cpp: component annotation */
  3. /**************************************/
  4. #include "fctsys.h"
  5. #include "common.h"
  6. #include "program.h"
  7. #include "libcmp.h"
  8. #include "netlist.h"
  9. #include "protos.h"
  10. /* Local Functions*/
  11. static int ListeComposants( CmpListStruct* BaseListeCmp,
  12. DrawSheetPath* sheet );
  13. static void BreakReference( CmpListStruct* BaseListeCmp, int NbOfCmp );
  14. static void ReAnnotateComponents( CmpListStruct* BaseListeCmp, int NbOfCmp );
  15. static void ComputeReferenceNumber( CmpListStruct* BaseListeCmp, int NbOfCmp );
  16. int GetLastReferenceNumber( CmpListStruct* Objet,
  17. CmpListStruct* BaseListeCmp,
  18. int NbOfCmp );
  19. static int ExistUnit( CmpListStruct* Objet, int Unit,
  20. CmpListStruct* BaseListeCmp, int NbOfCmp );
  21. /******************************************************/
  22. void WinEDA_SchematicFrame::UpdateSheetNumberAndDate()
  23. /******************************************************/
  24. /* Set a sheet number, the sheet count for sheets in the whole schematic
  25. * and update the date in all screens
  26. */
  27. {
  28. wxString date = GenDate();
  29. EDA_ScreenList s_list;
  30. // Set the date
  31. for ( SCH_SCREEN * screen = s_list.GetFirst(); screen != NULL; screen = s_list.GetNext() )
  32. screen->m_Date = date;
  33. // Set sheet counts
  34. SetSheetNumberAndCount();
  35. }
  36. /*****************************************************************************
  37. * Used to annotate the power symbols, before testing erc or computing
  38. * netlist when a component reannotation is not necessary
  39. *
  40. * In order to avoid conflicts the reference number starts with a 0. A
  41. * PWR with id 12 is named PWR12 in global annotation and PWR012 by the
  42. * Power annotation.
  43. ****************************************************************************/
  44. void ReAnnotatePowerSymbolsOnly( void )
  45. {
  46. /* Build the screen list (screen, not sheet) */
  47. EDA_SheetList SheetList( NULL );
  48. DrawSheetPath* sheet;
  49. int CmpNumber = 1;
  50. for( sheet = SheetList.GetFirst();
  51. sheet != NULL;
  52. sheet = SheetList.GetNext() )
  53. {
  54. EDA_BaseStruct* DrawList = sheet->LastDrawList();
  55. for( ; DrawList != NULL; DrawList = DrawList->Pnext )
  56. {
  57. if( DrawList->Type() != TYPE_SCH_COMPONENT )
  58. continue;
  59. SCH_COMPONENT* DrawLibItem =
  60. (SCH_COMPONENT*) DrawList;
  61. EDA_LibComponentStruct* Entry =
  62. FindLibPart(
  63. DrawLibItem->m_ChipName.GetData(), wxEmptyString,
  64. FIND_ROOT );
  65. if( (Entry == NULL) || (Entry->m_Options != ENTRY_POWER) )
  66. continue;
  67. //DrawLibItem->ClearAnnotation(sheet); this clears all annotation :(
  68. wxString refstr = DrawLibItem->m_PrefixString;
  69. //str will be "C?" or so after the ClearAnnotation call.
  70. while( refstr.Last() == '?' )
  71. refstr.RemoveLast();
  72. if( !refstr.StartsWith( wxT( "#" ) ) )
  73. refstr = wxT( "#" ) + refstr;
  74. refstr << wxT( "0" ) << CmpNumber;
  75. DrawLibItem->SetRef( sheet, refstr );
  76. CmpNumber++;
  77. }
  78. }
  79. }
  80. /* qsort function to annotate items by their position.
  81. * Components are sorted
  82. * by reference
  83. * if same reference: by sheet
  84. * if same sheet, by X pos
  85. * if same X pos, by Y pos
  86. * if same Y pos, by time stamp
  87. */
  88. int AnnotateBy_X_Position( const void* o1, const void* o2 )
  89. {
  90. CmpListStruct* item1 = (CmpListStruct*) o1;
  91. CmpListStruct* item2 = (CmpListStruct*) o2;
  92. int ii = strnicmp( item1->m_TextRef, item2->m_TextRef, 32 );
  93. if( ii == 0 )
  94. ii = item1->m_SheetList.Cmp( item2->m_SheetList );
  95. if( ii == 0 )
  96. ii = item1->m_Pos.x - item2->m_Pos.x;
  97. if( ii == 0 )
  98. ii = item1->m_Pos.y - item2->m_Pos.y;
  99. if( ii == 0 )
  100. ii = item1->m_TimeStamp - item2->m_TimeStamp;
  101. return ii;
  102. }
  103. /* qsort function to annotate items by their position.
  104. * Components are sorted
  105. * by reference
  106. * if same reference: by sheet
  107. * if same sheet, by Y pos
  108. * if same Y pos, by X pos
  109. * if same X pos, by time stamp
  110. */
  111. int AnnotateBy_Y_Position( const void* o1, const void* o2 )
  112. {
  113. CmpListStruct* item1 = (CmpListStruct*) o1;
  114. CmpListStruct* item2 = (CmpListStruct*) o2;
  115. int ii = strnicmp( item1->m_TextRef, item2->m_TextRef, 32 );
  116. if( ii == 0 )
  117. ii = item1->m_SheetList.Cmp( item2->m_SheetList );
  118. if( ii == 0 )
  119. ii = item1->m_Pos.y - item2->m_Pos.y;
  120. if( ii == 0 )
  121. ii = item1->m_Pos.x - item2->m_Pos.x;
  122. if( ii == 0 )
  123. ii = item1->m_TimeStamp - item2->m_TimeStamp;
  124. return ii;
  125. }
  126. /*****************************************************************************
  127. * qsort function to annotate items by value
  128. * Components are sorted
  129. * by reference
  130. * if same reference: by value
  131. * if same value: by unit number
  132. * if same unit number, by sheet
  133. * if same sheet, by time stamp
  134. *****************************************************************************/
  135. int AnnotateByValue( const void* o1, const void* o2 )
  136. {
  137. CmpListStruct* item1 = (CmpListStruct*) o1;
  138. CmpListStruct* item2 = (CmpListStruct*) o2;
  139. int ii = strnicmp( item1->m_TextRef, item2->m_TextRef, 32 );
  140. if( ii == 0 )
  141. ii = strnicmp( item1->m_TextValue, item2->m_TextValue, 32 );
  142. if( ii == 0 )
  143. ii = item1->m_Unit - item2->m_Unit;
  144. if( ii == 0 )
  145. ii = item1->m_SheetList.Cmp( item2->m_SheetList );
  146. if( ii == 0 )
  147. ii = item1->m_Pos.x - item2->m_Pos.x;
  148. if( ii == 0 )
  149. ii = item1->m_Pos.y - item2->m_Pos.y;
  150. if( ii == 0 )
  151. ii = item1->m_TimeStamp - item2->m_TimeStamp;
  152. return ii;
  153. }
  154. /**************************************************************************************/
  155. void WinEDA_SchematicFrame::DeleteAnnotation( bool aCurrentSheetOnly, bool aRedraw )
  156. /**************************************************************************************/
  157. /** Function DeleteAnnotation
  158. * Remove current component annotations
  159. * @param aCurrentSheetOnly : if false: remove all annotations, else remove annotation relative to the current sheet only
  160. * @param aRedraw : true to refresh display
  161. */
  162. {
  163. EDA_BaseStruct* strct;
  164. SCH_SCREEN* screen;
  165. EDA_ScreenList ScreenList;
  166. screen = ScreenList.GetFirst();
  167. if( aCurrentSheetOnly )
  168. screen = GetScreen();
  169. if( screen == NULL )
  170. return;
  171. while( screen )
  172. {
  173. strct = screen->EEDrawList;
  174. for( ; strct; strct = strct->Pnext )
  175. {
  176. if( strct->Type() == TYPE_SCH_COMPONENT )
  177. {
  178. if( aCurrentSheetOnly )
  179. ( (SCH_COMPONENT*) strct )->ClearAnnotation( m_CurrentSheet );
  180. else
  181. ( (SCH_COMPONENT*) strct )->ClearAnnotation( NULL );
  182. }
  183. }
  184. screen->SetModify();
  185. if( aCurrentSheetOnly )
  186. break;
  187. screen = ScreenList.GetNext();
  188. }
  189. //update the References
  190. m_CurrentSheet->UpdateAllScreenReferences();
  191. if( aRedraw )
  192. DrawPanel->Refresh( true );
  193. }
  194. /*****************************************************************************
  195. * AnnotateComponents:
  196. *
  197. * Compute the annotation of the components for the whole project, or the
  198. * current sheet only. All the components or the new ones only will be
  199. * annotated.
  200. * @param parent = Schematic frame
  201. * @param annotateSchematic : true = entire schematic annotation, false = current scheet only
  202. * @param sortOption : 0 = annotate by sorting X position,
  203. * 1 = annotate by sorting Y position,
  204. * 2 = annotate by sorting value
  205. * @param resetAnnotation : true = remove previous annotation false = anotate new components only
  206. *****************************************************************************/
  207. void AnnotateComponents( WinEDA_SchematicFrame* parent,
  208. bool annotateSchematic,
  209. int sortOption,
  210. bool resetAnnotation )
  211. {
  212. int ii, NbOfCmp;
  213. DrawSheetPath* sheet;
  214. CmpListStruct* BaseListeCmp;
  215. wxBusyCursor dummy;
  216. /* If it is an annotation for all the components, reset previous
  217. * annotation: */
  218. if( resetAnnotation )
  219. parent->DeleteAnnotation( !annotateSchematic, false );
  220. /* Build the sheet list */
  221. EDA_SheetList SheetList( g_RootSheet );
  222. /* Update the sheet number, sheet count and date */
  223. parent->UpdateSheetNumberAndDate();
  224. /* First pass: Component counting */
  225. ii = 0;
  226. sheet = parent->GetSheet();
  227. if( annotateSchematic )
  228. {
  229. NbOfCmp = 0;
  230. for( sheet = SheetList.GetFirst();
  231. sheet != NULL;
  232. sheet = SheetList.GetNext() )
  233. NbOfCmp += ListeComposants( NULL, sheet );
  234. }
  235. else
  236. NbOfCmp = ListeComposants( NULL, sheet );
  237. if( NbOfCmp == 0 )
  238. return;
  239. BaseListeCmp = (CmpListStruct*) MyZMalloc( NbOfCmp * sizeof(CmpListStruct) );
  240. /* Second pass : Init data tables */
  241. if( annotateSchematic )
  242. {
  243. ii = 0;
  244. for( sheet = SheetList.GetFirst();
  245. sheet != NULL;
  246. sheet = SheetList.GetNext() )
  247. ii += ListeComposants( BaseListeCmp + ii, sheet );
  248. }
  249. else
  250. ii = ListeComposants( BaseListeCmp, sheet );
  251. if( ii != NbOfCmp )
  252. DisplayError( parent, wxT( "Internal error in AnnotateComponents()" ) );
  253. /* Break full components reference in name (prefix) and number:
  254. * example: IC1 become IC, and 1 */
  255. BreakReference( BaseListeCmp, NbOfCmp );
  256. switch( sortOption )
  257. {
  258. case 0:
  259. qsort( BaseListeCmp, NbOfCmp, sizeof(CmpListStruct),
  260. ( int( * ) ( const void*, const void* ) )AnnotateBy_X_Position );
  261. break;
  262. case 1:
  263. qsort( BaseListeCmp, NbOfCmp, sizeof(CmpListStruct),
  264. ( int( * ) ( const void*, const void* ) )AnnotateBy_Y_Position );
  265. break;
  266. case 2:
  267. qsort( BaseListeCmp, NbOfCmp, sizeof(CmpListStruct),
  268. ( int( * ) ( const void*, const void* ) )AnnotateByValue );
  269. break;
  270. }
  271. /* Recalculate reference numbers */
  272. ComputeReferenceNumber( BaseListeCmp, NbOfCmp );
  273. ReAnnotateComponents( BaseListeCmp, NbOfCmp );
  274. MyFree( BaseListeCmp );
  275. BaseListeCmp = NULL;
  276. /* Final control */
  277. CheckAnnotate( parent, !annotateSchematic );
  278. parent->DrawPanel->Refresh( true );
  279. }
  280. /*****************************************************************************
  281. * if BaseListeCmp == NULL : count components
  282. * else update data table BaseListeCmp
  283. *****************************************************************************/
  284. int ListeComposants( CmpListStruct* BaseListeCmp, DrawSheetPath* sheet )
  285. {
  286. int NbrCmp = 0;
  287. EDA_BaseStruct* DrawList = sheet->LastDrawList();
  288. SCH_COMPONENT* DrawLibItem;
  289. EDA_LibComponentStruct* Entry;
  290. for( ; DrawList; DrawList = DrawList->Pnext )
  291. {
  292. if( DrawList->Type() == TYPE_SCH_COMPONENT )
  293. {
  294. DrawLibItem = (SCH_COMPONENT*) DrawList;
  295. Entry = FindLibPart( DrawLibItem->m_ChipName.GetData(),
  296. wxEmptyString,
  297. FIND_ROOT );
  298. if( Entry == NULL )
  299. continue;
  300. if( BaseListeCmp == NULL ) /* Items counting only */
  301. {
  302. NbrCmp++;
  303. continue;
  304. }
  305. BaseListeCmp[NbrCmp].m_Cmp = DrawLibItem;
  306. BaseListeCmp[NbrCmp].m_NbParts = Entry->m_UnitCount;
  307. BaseListeCmp[NbrCmp].m_Unit = DrawLibItem->GetUnitSelection( sheet ); // DrawLibItem->m_Multi;
  308. BaseListeCmp[NbrCmp].m_PartsLocked = Entry->m_UnitSelectionLocked;
  309. BaseListeCmp[NbrCmp].m_SheetList = *sheet;
  310. BaseListeCmp[NbrCmp].m_IsNew = FALSE;
  311. BaseListeCmp[NbrCmp].m_Pos = DrawLibItem->m_Pos;
  312. BaseListeCmp[NbrCmp].m_TimeStamp = DrawLibItem->m_TimeStamp;
  313. if( DrawLibItem->GetRef( sheet ).IsEmpty() )
  314. DrawLibItem->SetRef( sheet, wxT( "DefRef?" ) );
  315. strncpy( BaseListeCmp[NbrCmp].m_TextRef,
  316. CONV_TO_UTF8( DrawLibItem->GetRef( sheet ) ), 32 );
  317. BaseListeCmp[NbrCmp].m_NumRef = -1;
  318. if( DrawLibItem->m_Field[VALUE].m_Text.IsEmpty() )
  319. DrawLibItem->m_Field[VALUE].m_Text = wxT( "~" );
  320. strncpy( BaseListeCmp[NbrCmp].m_TextValue,
  321. CONV_TO_UTF8( DrawLibItem->m_Field[VALUE].m_Text ), 32 );
  322. NbrCmp++;
  323. }
  324. }
  325. return NbrCmp;
  326. }
  327. /*****************************************************************************
  328. * Update the reference component for the schematic project (or the current
  329. * sheet)
  330. *****************************************************************************/
  331. static void ReAnnotateComponents( CmpListStruct* BaseListeCmp, int NbOfCmp )
  332. {
  333. int ii;
  334. char* Text;
  335. SCH_COMPONENT* DrawLibItem;
  336. /* Reattribution des numeros */
  337. for( ii = 0; ii < NbOfCmp; ii++ )
  338. {
  339. Text = BaseListeCmp[ii].m_TextRef;
  340. DrawLibItem = BaseListeCmp[ii].m_Cmp;
  341. if( BaseListeCmp[ii].m_NumRef < 0 )
  342. strcat( Text, "?" );
  343. else
  344. sprintf( Text + strlen( Text ), "%d", BaseListeCmp[ii].m_NumRef );
  345. DrawLibItem->SetRef( &(BaseListeCmp[ii].m_SheetList),
  346. CONV_FROM_UTF8( Text ) );
  347. DrawLibItem->m_Multi = BaseListeCmp[ii].m_Unit;
  348. DrawLibItem->SetUnitSelection( &(BaseListeCmp[ii].m_SheetList), DrawLibItem->m_Multi );
  349. }
  350. }
  351. /*****************************************************************************
  352. * Split component reference designators into a name (prefix) and number.
  353. * Example: IC1 becomes IC and 1 in the .m_NumRef member.
  354. * For multi part per package components not already annotated, set .m_Unit
  355. * to a max value (0x7FFFFFFF).
  356. *
  357. * @param BaseListeCmp = list of component
  358. * @param NbOfCmp = item count in the list
  359. *****************************************************************************/
  360. void BreakReference( CmpListStruct* BaseListeCmp, int NbOfCmp )
  361. {
  362. int ii, ll;
  363. char* Text;
  364. for( ii = 0; ii < NbOfCmp; ii++ )
  365. {
  366. BaseListeCmp[ii].m_NumRef = -1;
  367. Text = BaseListeCmp[ii].m_TextRef;
  368. ll = strlen( Text ) - 1;
  369. if( Text[ll] == '?' )
  370. {
  371. BaseListeCmp[ii].m_IsNew = true;
  372. if( !BaseListeCmp[ii].m_PartsLocked )
  373. BaseListeCmp[ii].m_Unit = 0x7FFFFFFF;
  374. Text[ll] = 0;
  375. continue;
  376. }
  377. if( isdigit( Text[ll] ) == 0 )
  378. {
  379. BaseListeCmp[ii].m_IsNew = true;
  380. if( !BaseListeCmp[ii].m_PartsLocked )
  381. BaseListeCmp[ii].m_Unit = 0x7FFFFFFF;
  382. continue;
  383. }
  384. while( ll >= 0 )
  385. {
  386. if( (Text[ll] <= ' ' ) || isdigit( Text[ll] ) )
  387. ll--;
  388. else
  389. {
  390. if( isdigit( Text[ll + 1] ) )
  391. BaseListeCmp[ii].m_NumRef = atoi( &Text[ll + 1] );
  392. Text[ll + 1] = 0;
  393. break;
  394. }
  395. }
  396. }
  397. }
  398. /*****************************************************************************
  399. * Compute the reference number for components without reference number
  400. * Compute .m_NumRef member
  401. *****************************************************************************/
  402. static void ComputeReferenceNumber( CmpListStruct* BaseListeCmp, int NbOfCmp )
  403. {
  404. int ii, jj, LastReferenceNumber, NumberOfUnits, Unit;
  405. const char* Text, * RefText, * ValText;
  406. CmpListStruct* ObjRef, * ObjToTest;
  407. /* Components with an invisible reference (power...) always are
  408. * re-annotated */
  409. for( ii = 0; ii < NbOfCmp; ii++ )
  410. {
  411. Text = BaseListeCmp[ii].m_TextRef;
  412. if( *Text == '#' )
  413. {
  414. BaseListeCmp[ii].m_IsNew = true;
  415. BaseListeCmp[ii].m_NumRef = 0;
  416. }
  417. }
  418. ValText = RefText = ""; LastReferenceNumber = 1;
  419. for( ii = 0; ii < NbOfCmp; ii++ )
  420. {
  421. ObjRef = &BaseListeCmp[ii];
  422. if( BaseListeCmp[ii].m_Flag )
  423. continue;
  424. Text = BaseListeCmp[ii].m_TextRef;
  425. if( strnicmp( RefText, Text, 32 ) != 0 ) /* Nouveau Identificateur */
  426. {
  427. RefText = BaseListeCmp[ii].m_TextRef;
  428. LastReferenceNumber = GetLastReferenceNumber( BaseListeCmp + ii,
  429. BaseListeCmp,
  430. NbOfCmp );
  431. }
  432. /* Annotation of one part per package components (trivial case)*/
  433. if( BaseListeCmp[ii].m_NbParts <= 1 )
  434. {
  435. if( BaseListeCmp[ii].m_IsNew )
  436. {
  437. LastReferenceNumber++;
  438. BaseListeCmp[ii].m_NumRef = LastReferenceNumber;
  439. }
  440. BaseListeCmp[ii].m_Unit = 1;
  441. BaseListeCmp[ii].m_Flag = 1;
  442. BaseListeCmp[ii].m_IsNew = FALSE;
  443. continue;
  444. }
  445. /* Annotation of multi-part components ( n parts per package )
  446. * (complex case) */
  447. ValText = BaseListeCmp[ii].m_TextValue;
  448. NumberOfUnits = BaseListeCmp[ii].m_NbParts;
  449. if( BaseListeCmp[ii].m_IsNew )
  450. {
  451. LastReferenceNumber++;
  452. BaseListeCmp[ii].m_NumRef = LastReferenceNumber;
  453. if( !BaseListeCmp[ii].m_PartsLocked )
  454. BaseListeCmp[ii].m_Unit = 1;
  455. BaseListeCmp[ii].m_Flag = 1;
  456. }
  457. for( Unit = 1; Unit <= NumberOfUnits; Unit++ )
  458. {
  459. if( BaseListeCmp[ii].m_Unit == Unit )
  460. continue;
  461. jj = ExistUnit( BaseListeCmp + ii, Unit, BaseListeCmp, NbOfCmp );
  462. if( jj >= 0 )
  463. continue; /* Unit exists for this reference */
  464. /* Search a component to annotate ( same prefix, same value) */
  465. for( jj = ii + 1; jj < NbOfCmp; jj++ )
  466. {
  467. ObjToTest = &BaseListeCmp[jj];
  468. if( BaseListeCmp[jj].m_Flag )
  469. continue;
  470. Text = BaseListeCmp[jj].m_TextRef;
  471. if( strnicmp( RefText, Text, 32 ) != 0 )
  472. continue; // references are different
  473. Text = BaseListeCmp[jj].m_TextValue;
  474. if( strnicmp( ValText, Text, 32 ) != 0 )
  475. continue; // values are different
  476. if( !BaseListeCmp[jj].m_IsNew )
  477. {
  478. continue;
  479. }
  480. /* Component without reference number found, annotate it if
  481. * possible */
  482. if( !BaseListeCmp[jj].m_PartsLocked
  483. || (BaseListeCmp[jj].m_Unit == Unit) )
  484. {
  485. BaseListeCmp[jj].m_NumRef = BaseListeCmp[ii].m_NumRef;
  486. BaseListeCmp[jj].m_Unit = Unit;
  487. BaseListeCmp[jj].m_Flag = 1;
  488. BaseListeCmp[jj].m_IsNew = FALSE;
  489. break;
  490. }
  491. }
  492. }
  493. }
  494. }
  495. /*****************************************************************************
  496. * Search the last used (greatest) reference number in the component list
  497. * for the prefix reference given by Objet
  498. * The component list must be sorted.
  499. *
  500. * @param Objet = reference item ( Objet->m_TextRef is the search pattern)
  501. * @param BaseListeCmp = list of items
  502. * @param NbOfCmp = items count in list of items
  503. *****************************************************************************/
  504. int GetLastReferenceNumber( CmpListStruct* Objet,
  505. CmpListStruct* BaseListeCmp,
  506. int NbOfCmp )
  507. {
  508. CmpListStruct* LastObjet = BaseListeCmp + NbOfCmp;
  509. int LastNumber = 0;
  510. const char* RefText;
  511. RefText = Objet->m_TextRef;
  512. for( ; Objet < LastObjet; Objet++ )
  513. {
  514. /* Nouveau Identificateur */
  515. if( strnicmp( RefText, Objet->m_TextRef, 32 ) != 0 )
  516. break;
  517. if( LastNumber < Objet->m_NumRef )
  518. LastNumber = Objet->m_NumRef;
  519. }
  520. return LastNumber;
  521. }
  522. /*****************************************************************************
  523. * Search in the sorted list of components, for a given componen,t an other component
  524. * with the same reference and a given part unit.
  525. * Mainly used to manage multiple parts per package components
  526. * @param Objet = the given CmpListStruct* item to test
  527. * @param Unit = the given unit number to search
  528. * @param BaseListeCmp = list of items to examine
  529. * @param NbOfCmp = size of list
  530. * @return index in BaseListeCmp if found or -1 if not found
  531. *****************************************************************************/
  532. static int ExistUnit( CmpListStruct* Objet, int Unit,
  533. CmpListStruct* BaseListeCmp, int NbOfCmp )
  534. {
  535. CmpListStruct* EndList = BaseListeCmp + NbOfCmp;
  536. char* RefText, * ValText;
  537. int NumRef, ii;
  538. CmpListStruct* ItemToTest;
  539. RefText = Objet->m_TextRef;
  540. ValText = Objet->m_TextValue;
  541. NumRef = Objet->m_NumRef;
  542. for( ItemToTest = BaseListeCmp, ii = 0;
  543. ItemToTest < EndList;
  544. ItemToTest++, ii++ )
  545. {
  546. if( Objet == ItemToTest ) // Do not compare with itself !
  547. continue;
  548. if( ItemToTest->m_IsNew ) // Not already with an updated reference
  549. continue;
  550. if( ItemToTest->m_NumRef != NumRef ) // Not the same reference number (like 35 in R35)
  551. continue;
  552. if( strnicmp( RefText, ItemToTest->m_TextRef, 32 ) != 0 ) // Not the same reference prefix
  553. continue;
  554. if( ItemToTest->m_Unit == Unit ) // A part with the same reference and the given unit is found
  555. {
  556. return ii;
  557. }
  558. }
  559. return -1;
  560. }
  561. /*****************************************************************************
  562. *
  563. * Function CheckAnnotate
  564. * @return component count ( which are not annotated or have the same
  565. * reference (duplicates))
  566. * @param oneSheetOnly : true = search is made only in the current sheet
  567. * false = search in whole hierarchy (usual search).
  568. *
  569. *****************************************************************************/
  570. int CheckAnnotate( WinEDA_SchematicFrame* frame, bool oneSheetOnly )
  571. {
  572. int ii, error, NbOfCmp;
  573. DrawSheetPath* sheet;
  574. CmpListStruct* ListeCmp = NULL;
  575. wxString Buff;
  576. wxString msg, cmpref;
  577. /* build the screen list */
  578. EDA_SheetList SheetList( NULL );
  579. g_RootSheet->m_AssociatedScreen->SetModify();
  580. ii = 0;
  581. /* first pass : count composents */
  582. if( !oneSheetOnly )
  583. {
  584. NbOfCmp = 0;
  585. for( sheet = SheetList.GetFirst();
  586. sheet != NULL;
  587. sheet = SheetList.GetNext() )
  588. NbOfCmp += ListeComposants( NULL, sheet );
  589. }
  590. else
  591. NbOfCmp = ListeComposants( NULL, frame->GetSheet() );
  592. if( NbOfCmp == 0 )
  593. {
  594. return 0;
  595. }
  596. /* Second pass : create the list of components */
  597. ListeCmp = (CmpListStruct*) MyZMalloc( NbOfCmp * sizeof(CmpListStruct) );
  598. if( !oneSheetOnly )
  599. {
  600. ii = 0;
  601. for( sheet = SheetList.GetFirst();
  602. sheet != NULL;
  603. sheet = SheetList.GetNext() )
  604. ii += ListeComposants( ListeCmp + ii, sheet );
  605. }
  606. else
  607. ListeComposants( ListeCmp, frame->GetSheet() );
  608. qsort( ListeCmp, NbOfCmp, sizeof(CmpListStruct), AnnotateByValue );
  609. /* Break full components reference in name (prefix) and number: example:
  610. * IC1 become IC, and 1 */
  611. BreakReference( ListeCmp, NbOfCmp );
  612. /* count not yet annotated items */
  613. error = 0;
  614. for( ii = 0; ii < NbOfCmp - 1; ii++ )
  615. {
  616. msg.Empty();
  617. Buff.Empty();
  618. if( ListeCmp[ii].m_IsNew )
  619. {
  620. if( ListeCmp[ii].m_NumRef >= 0 )
  621. Buff << ListeCmp[ii].m_NumRef;
  622. else
  623. Buff = wxT( "?" );
  624. cmpref = CONV_FROM_UTF8( ListeCmp[ii].m_TextRef );
  625. msg.Printf( _( "item not annotated: %s%s" ),
  626. cmpref.GetData(), Buff.GetData() );
  627. if( (ListeCmp[ii].m_Unit > 0) && (ListeCmp[ii].m_Unit < 0x7FFFFFFF) )
  628. {
  629. Buff.Printf( _( "( unit %d)" ), ListeCmp[ii].m_Unit );
  630. msg << Buff;
  631. }
  632. DisplayError( NULL, msg );
  633. error++;
  634. break;
  635. }
  636. // Annotate error
  637. if( MAX( ListeCmp[ii].m_NbParts, 1 ) < ListeCmp[ii].m_Unit )
  638. {
  639. if( ListeCmp[ii].m_NumRef >= 0 )
  640. Buff << ListeCmp[ii].m_NumRef;
  641. else
  642. Buff = wxT( "?" );
  643. cmpref = CONV_FROM_UTF8( ListeCmp[ii].m_TextRef );
  644. msg.Printf( _( "Error item %s%s" ), cmpref.GetData(),
  645. Buff.GetData() );
  646. Buff.Printf( _( " unit %d and no more than %d parts" ),
  647. ListeCmp[ii].m_Unit, ListeCmp[ii].m_NbParts );
  648. msg << Buff;
  649. DisplayError( frame, msg );
  650. error++;
  651. break;
  652. }
  653. }
  654. if( error )
  655. return error;
  656. // count the duplicated elements (if all are annotated)
  657. for( ii = 0; (ii < NbOfCmp - 1) && (error < 4); ii++ )
  658. {
  659. msg.Empty();
  660. Buff.Empty();
  661. if( (stricmp( ListeCmp[ii].m_TextRef,
  662. ListeCmp[ii + 1].m_TextRef ) != 0)
  663. || ( ListeCmp[ii].m_NumRef != ListeCmp[ii + 1].m_NumRef ) )
  664. continue;
  665. /* Same reference found */
  666. /* If same unit, error ! */
  667. if( ListeCmp[ii].m_Unit == ListeCmp[ii + 1].m_Unit )
  668. {
  669. if( ListeCmp[ii].m_NumRef >= 0 )
  670. Buff << ListeCmp[ii].m_NumRef;
  671. else
  672. Buff = wxT( "?" );
  673. cmpref = CONV_FROM_UTF8( ListeCmp[ii].m_TextRef );
  674. msg.Printf( _( "Multiple item %s%s" ),
  675. cmpref.GetData(), Buff.GetData() );
  676. if( (ListeCmp[ii].m_Unit > 0) && (ListeCmp[ii].m_Unit < 0x7FFFFFFF) )
  677. {
  678. Buff.Printf( _( " (unit %d)" ), ListeCmp[ii].m_Unit );
  679. msg << Buff;
  680. }
  681. DisplayError( frame, msg );
  682. error++;
  683. continue;
  684. }
  685. /* Test error if units are different but number of parts per package
  686. * too hight (ex U3 ( 1 part) and we find U3B the is an error) */
  687. if( ListeCmp[ii].m_NbParts != ListeCmp[ii + 1].m_NbParts )
  688. {
  689. if( ListeCmp[ii].m_NumRef >= 0 )
  690. Buff << ListeCmp[ii].m_NumRef;
  691. else
  692. Buff = wxT( "?" );
  693. cmpref = CONV_FROM_UTF8( ListeCmp[ii].m_TextRef );
  694. msg.Printf( _( "Multiple item %s%s" ),
  695. cmpref.GetData(), Buff.GetData() );
  696. if( (ListeCmp[ii].m_Unit > 0) && (ListeCmp[ii].m_Unit < 0x7FFFFFFF) )
  697. {
  698. Buff.Printf( _( " (unit %d)" ), ListeCmp[ii].m_Unit );
  699. msg << Buff;
  700. }
  701. DisplayError( frame, msg );
  702. error++;
  703. }
  704. /* Error if values are different between units, for the same reference */
  705. if( stricmp( ListeCmp[ii].m_TextValue,
  706. ListeCmp[ii + 1].m_TextValue ) != 0 )
  707. {
  708. wxString nextcmpref, cmpvalue, nextcmpvalue;
  709. cmpref = CONV_FROM_UTF8( ListeCmp[ii].m_TextRef );
  710. nextcmpref = CONV_FROM_UTF8( ListeCmp[ii + 1].m_TextRef );
  711. cmpvalue = CONV_FROM_UTF8( ListeCmp[ii].m_TextValue );
  712. nextcmpvalue = CONV_FROM_UTF8( ListeCmp[ii + 1].m_TextValue );
  713. msg.Printf( _( "Diff values for %s%d%c (%s) and %s%d%c (%s)" ),
  714. cmpref.GetData(),
  715. ListeCmp[ii].m_NumRef,
  716. ListeCmp[ii].m_Unit + 'A' - 1,
  717. cmpvalue.GetData(), nextcmpref.GetData(),
  718. ListeCmp[ii + 1].m_NumRef,
  719. ListeCmp[ii + 1].m_Unit + 'A' - 1,
  720. nextcmpvalue.GetData() );
  721. DisplayError( frame, msg );
  722. error++;
  723. }
  724. }
  725. MyFree( ListeCmp );
  726. return error;
  727. }