KiCad PCB EDA Suite
component_references_lister.cpp
Go to the documentation of this file.
1 
6 /*
7  * This program source code file is part of KiCad, a free EDA CAD application.
8  *
9  * Copyright (C) 1992-2018 jean-pierre Charras <jp.charras at wanadoo.fr>
10  * Copyright (C) 1992-2011 Wayne Stambaugh <stambaughw@verizon.net>
11  * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, you may find one here:
25  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
26  * or you may search the http://www.gnu.org website for the version 2 license,
27  * or you may write to the Free Software Foundation, Inc.,
28  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
29  */
30 
31 
32 #include <wx/regex.h>
33 #include <algorithm>
34 #include <vector>
35 #include <unordered_set>
36 
37 #include <fctsys.h>
38 #include <kicad_string.h>
39 #include <sch_edit_frame.h>
40 #include <sch_reference_list.h>
41 #include <sch_component.h>
42 #include <reporter.h>
43 
44 
45 //#define USE_OLD_ALGO
46 
47 
48 void SCH_REFERENCE_LIST::RemoveItem( unsigned int aIndex )
49 {
50  if( aIndex < componentFlatList.size() )
51  componentFlatList.erase( componentFlatList.begin() + aIndex );
52 }
53 
54 
56  const SCH_REFERENCE& item2 )
57 {
58  int ii = item1.CompareRef( item2 );
59 
60  if( ii == 0 )
61  ii = item1.m_SheetNum - item2.m_SheetNum;
62  if( ii == 0 )
63  ii = item1.m_CmpPos.x - item2.m_CmpPos.x;
64  if( ii == 0 )
65  ii = item1.m_CmpPos.y - item2.m_CmpPos.y;
66  if( ii == 0 )
67  ii = item1.m_TimeStamp - item2.m_TimeStamp;
68 
69  return ii < 0;
70 }
71 
73  const SCH_REFERENCE& item2 )
74 {
75  int ii = item1.CompareRef( item2 );
76 
77  if( ii == 0 )
78  ii = item1.m_SheetNum - item2.m_SheetNum;
79  if( ii == 0 )
80  ii = item1.m_CmpPos.y - item2.m_CmpPos.y;
81  if( ii == 0 )
82  ii = item1.m_CmpPos.x - item2.m_CmpPos.x;
83  if( ii == 0 )
84  ii = item1.m_TimeStamp - item2.m_TimeStamp;
85 
86  return ii < 0;
87 }
88 
89 
91  const SCH_REFERENCE& item2 )
92 {
93  int ii = item1.CompareRef( item2 );
94  if( ii == 0 )
95  ii = item1.CompareValue( item2 );
96  if( ii == 0 )
97  ii = item1.m_Unit - item2.m_Unit;
98  if( ii == 0 )
99  ii = item1.m_SheetNum - item2.m_SheetNum;
100  if( ii == 0 )
101  ii = item1.m_CmpPos.x - item2.m_CmpPos.x;
102  if( ii == 0 )
103  ii = item1.m_CmpPos.y - item2.m_CmpPos.y;
104  if( ii == 0 )
105  ii = item1.m_TimeStamp - item2.m_TimeStamp;
106 
107  return ii < 0;
108 }
109 
110 
112  const SCH_REFERENCE& item2 )
113 {
114  int ii;
115 
116  ii = RefDesStringCompare( item1.GetRef(), item2.GetRef() );
117 
118  if( ii == 0 )
119  {
120  ii = item1.m_RootCmp->GetField( VALUE )->GetText().CmpNoCase( item2.m_RootCmp->GetField( VALUE )->GetText() );
121  }
122 
123  if( ii == 0 )
124  {
125  ii = item1.m_Unit - item2.m_Unit;
126  }
127 
128  return ii < 0;
129 }
130 
131 
133  const SCH_REFERENCE& item2 )
134 {
135  int ii = item1.m_SheetPath.Cmp( item2.m_SheetPath );
136 
137  if( ii == 0 )
138  ii = item1.m_TimeStamp - item2.m_TimeStamp;
139 
140  return ii < 0;
141 }
142 
143 int SCH_REFERENCE_LIST::FindUnit( size_t aIndex, int aUnit )
144 {
145  int NumRef;
146 
147  NumRef = componentFlatList[aIndex].m_NumRef;
148 
149  for( size_t ii = 0; ii < componentFlatList.size(); ii++ )
150  {
151  if( ( aIndex == ii )
152  || ( componentFlatList[ii].m_IsNew )
153  || ( componentFlatList[ii].m_NumRef != NumRef )
154  || ( componentFlatList[aIndex].CompareRef( componentFlatList[ii] ) != 0 ) )
155  continue;
156 
157  if( componentFlatList[ii].m_Unit == aUnit )
158  return (int) ii;
159  }
160 
161  return -1;
162 }
163 
164 
166 {
167  SCH_COMPONENT* libItem;
168  wxString oldName;
169  wxString currName;
170 
171  // The component list **MUST** be sorted by reference and by unit number
172  // in order to find all parts of a component
174 
175  for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
176  {
177 
178  libItem = componentFlatList[ii].m_RootCmp;
179  if( libItem == NULL )
180  continue;
181 
182  currName = componentFlatList[ii].GetRef();
183 
184  if( !oldName.IsEmpty() )
185  {
186  if( oldName == currName ) // currName is a subpart of oldName: remove it
187  {
188  componentFlatList.erase( componentFlatList.begin() + ii );
189  ii--;
190  }
191  }
192 
193  oldName = currName;
194  }
195 }
196 
197 
198 void SCH_REFERENCE_LIST::GetRefsInUse( int aIndex, std::vector< int >& aIdList, int aMinRefId )
199 {
200  aIdList.clear();
201 
202  for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
203  {
204  if( ( componentFlatList[aIndex].CompareRef( componentFlatList[ii] ) == 0 )
205  && ( componentFlatList[ii].m_NumRef >= aMinRefId ) )
206  aIdList.push_back( componentFlatList[ii].m_NumRef );
207  }
208 
209  sort( aIdList.begin(), aIdList.end() );
210 
211  // Ensure each reference number appears only once. If there are components with
212  // multiple parts per package the same number will be stored for each part.
213  std::vector< int >::iterator it = unique( aIdList.begin(), aIdList.end() );
214 
215  // Using the C++ unique algorithm only moves the duplicate entries to the end of
216  // of the array. This removes the duplicate entries from the array.
217  aIdList.resize( it - aIdList.begin() );
218 }
219 
220 
221 int SCH_REFERENCE_LIST::GetLastReference( int aIndex, int aMinValue )
222 {
223  int lastNumber = aMinValue;
224 
225  for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
226  {
227  // search only for the current reference prefix:
228  if( componentFlatList[aIndex].CompareRef( componentFlatList[ii] ) != 0 )
229  continue;
230 
231  // update max value for the current reference prefix
232  if( lastNumber < componentFlatList[ii].m_NumRef )
233  lastNumber = componentFlatList[ii].m_NumRef;
234  }
235 
236  return lastNumber;
237 }
238 
239 
240 int SCH_REFERENCE_LIST::CreateFirstFreeRefId( std::vector<int>& aIdList, int aFirstValue )
241 {
242  int expectedId = aFirstValue;
243 
244  // We search for expected Id a value >= aFirstValue.
245  // Skip existing Id < aFirstValue
246  unsigned ii = 0;
247 
248  for( ; ii < aIdList.size(); ii++ )
249  {
250  if( expectedId <= aIdList[ii] )
251  break;
252  }
253 
254  // Ids are sorted by increasing value, from aFirstValue
255  // So we search from aFirstValue the first not used value, i.e. the first hole in list.
256  for( ; ii < aIdList.size(); ii++ )
257  {
258  if( expectedId != aIdList[ii] ) // This id is not yet used.
259  {
260  // Insert this free Id, in order to keep list sorted
261  aIdList.insert( aIdList.begin() + ii, expectedId );
262  return expectedId;
263  }
264 
265  expectedId++;
266  }
267 
268  // All existing Id are tested, and all values are found in use.
269  // So Create a new one.
270  aIdList.push_back( expectedId );
271  return expectedId;
272 }
273 
274 
275 // A helper function to build a full reference string of a SCH_REFERENCE item
276 wxString buildFullReference( const SCH_REFERENCE& aItem, int aUnitNumber = -1 )
277 {
278  wxString fullref;
279  fullref = aItem.GetRef() + aItem.GetRefNumber();
280 
281  if( aUnitNumber < 0 )
282  fullref << ".." << aItem.GetUnit();
283  else
284  fullref << ".." << aUnitNumber;
285 
286  return fullref;
287 }
288 
289 
290 void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
291  SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap )
292 {
293  if ( componentFlatList.size() == 0 )
294  return;
295 
296  int LastReferenceNumber = 0;
297  int NumberOfUnits, Unit;
298 
299  /* calculate index of the first component with the same reference prefix
300  * than the current component. All components having the same reference
301  * prefix will receive a reference number with consecutive values:
302  * IC .. will be set to IC4, IC4, IC5 ...
303  */
304  unsigned first = 0;
305 
306  // calculate the last used number for this reference prefix:
307 #ifdef USE_OLD_ALGO
308  int minRefId = 0;
309 
310  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
311  if( aUseSheetNum )
312  minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId;
313 
314  LastReferenceNumber = GetLastReference( first, minRefId );
315 #else
316  int minRefId;
317 
318  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
319  if( aUseSheetNum )
320  minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId + 1;
321  else
322  minRefId = aStartNumber + 1;
323 
324  // For multi units components, when "keep order of multi unit" option is selected,
325  // store the list of already used full references.
326  // The algorithm try to allocate the new reference to components having the same
327  // old reference.
328  // This algo works fine as long as the previous annotation has no duplicates.
329  // But when a hierarchy is reannotated with this option, the previous anotation can
330  // have duplicate references, and obviously we must fix these duplicate.
331  // therefore do not try to allocate a full reference more than once when trying
332  // to keep this order of multi units.
333  // inUseRefs keep trace of previously allocated references
334  std::unordered_set<wxString> inUseRefs;
335 
336  // This is the list of all Id already in use for a given reference prefix.
337  // Will be refilled for each new reference prefix.
338  std::vector<int>idList;
339  GetRefsInUse( first, idList, minRefId );
340 #endif
341  for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
342  {
343  if( componentFlatList[ii].m_Flag )
344  continue;
345 
346  // Check whether this component is in aLockedUnitMap.
347  SCH_REFERENCE_LIST* lockedList = NULL;
348  for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
349  {
350  unsigned n_refs = pair.second.GetCount();
351 
352  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
353  {
354  SCH_REFERENCE &thisRef = pair.second[thisRefI];
355 
356  if( thisRef.IsSameInstance( componentFlatList[ii] ) )
357  {
358  lockedList = &pair.second;
359  break;
360  }
361  }
362  if( lockedList != NULL ) break;
363  }
364 
365  if( ( componentFlatList[first].CompareRef( componentFlatList[ii] ) != 0 )
366  || ( aUseSheetNum && ( componentFlatList[first].m_SheetNum != componentFlatList[ii].m_SheetNum ) ) )
367  {
368  // New reference found: we need a new ref number for this reference
369  first = ii;
370 #ifdef USE_OLD_ALGO
371  minRefId = 0;
372 
373  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
374  if( aUseSheetNum )
375  minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId;
376 
377  LastReferenceNumber = GetLastReference( ii, minRefId );
378 
379 #else
380  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
381  if( aUseSheetNum )
382  minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId + 1;
383  else
384  minRefId = aStartNumber + 1;
385 
386  GetRefsInUse( first, idList, minRefId );
387 #endif
388  }
389 
390  // Annotation of one part per package components (trivial case).
391  if( componentFlatList[ii].GetLibPart()->GetUnitCount() <= 1 )
392  {
393  if( componentFlatList[ii].m_IsNew )
394  {
395 #ifdef USE_OLD_ALGO
396  LastReferenceNumber++;
397 #else
398  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
399 #endif
400  componentFlatList[ii].m_NumRef = LastReferenceNumber;
401  }
402 
403  componentFlatList[ii].m_Unit = 1;
404  componentFlatList[ii].m_Flag = 1;
405  componentFlatList[ii].m_IsNew = false;
406  continue;
407  }
408 
409  // Annotation of multi-unit parts ( n units per part ) (complex case)
410  NumberOfUnits = componentFlatList[ii].GetLibPart()->GetUnitCount();
411 
412  if( componentFlatList[ii].m_IsNew )
413  {
414 #ifdef USE_OLD_ALGO
415  LastReferenceNumber++;
416 #else
417  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
418 #endif
419  componentFlatList[ii].m_NumRef = LastReferenceNumber;
420 
421  if( !componentFlatList[ii].IsUnitsLocked() )
422  componentFlatList[ii].m_Unit = 1;
423 
424  componentFlatList[ii].m_Flag = 1;
425  }
426 
427  // If this component is in aLockedUnitMap, copy the annotation to all
428  // components that are not it
429  if( lockedList != NULL )
430  {
431  unsigned n_refs = lockedList->GetCount();
432 
433  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
434  {
435  SCH_REFERENCE &thisRef = (*lockedList)[thisRefI];
436 
437  if( thisRef.IsSameInstance( componentFlatList[ii] ) )
438  {
439  // This is the component we're currently annotating. Hold the unit!
440  componentFlatList[ii].m_Unit = thisRef.m_Unit;
441  // lock this new full reference
442  inUseRefs.insert( buildFullReference( componentFlatList[ii] ) );
443  }
444 
445  if( thisRef.CompareValue( componentFlatList[ii] ) != 0 )
446  continue;
447 
448  if( thisRef.CompareLibName( componentFlatList[ii] ) != 0 )
449  continue;
450 
451  // Find the matching component
452  for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
453  {
454  if( ! thisRef.IsSameInstance( componentFlatList[jj] ) )
455  continue;
456 
457  wxString ref_candidate = buildFullReference( componentFlatList[ii], thisRef.m_Unit );
458 
459  // propagate the new reference and unit selection to the "old" component,
460  // if this new full reference is not already used (can happens when initial
461  // multiunits components have duplicate references)
462  if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
463  {
464  componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
465  componentFlatList[jj].m_Unit = thisRef.m_Unit;
466  componentFlatList[jj].m_IsNew = false;
467  componentFlatList[jj].m_Flag = 1;
468  // lock this new full reference
469  inUseRefs.insert( ref_candidate );
470  break;
471  }
472  }
473  }
474  }
475  else
476  {
477  /* search for others units of this component.
478  * we search for others parts that have the same value and the same
479  * reference prefix (ref without ref number)
480  */
481  for( Unit = 1; Unit <= NumberOfUnits; Unit++ )
482  {
483  if( componentFlatList[ii].m_Unit == Unit )
484  continue;
485 
486  int found = FindUnit( ii, Unit );
487 
488  if( found >= 0 )
489  continue; // this unit exists for this reference (unit already annotated)
490 
491  // Search a component to annotate ( same prefix, same value, not annotated)
492  for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
493  {
494  if( componentFlatList[jj].m_Flag ) // already tested
495  continue;
496 
497  if( componentFlatList[ii].CompareRef( componentFlatList[jj] ) != 0 )
498  continue;
499 
500  if( componentFlatList[jj].CompareValue( componentFlatList[ii] ) != 0 )
501  continue;
502 
503  if( componentFlatList[jj].CompareLibName( componentFlatList[ii] ) != 0 )
504  continue;
505 
506  if( !componentFlatList[jj].m_IsNew )
507  continue;
508 
509  // Component without reference number found, annotate it if possible
510  if( !componentFlatList[jj].IsUnitsLocked()
511  || ( componentFlatList[jj].m_Unit == Unit ) )
512  {
513  componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
514  componentFlatList[jj].m_Unit = Unit;
515  componentFlatList[jj].m_Flag = 1;
516  componentFlatList[jj].m_IsNew = false;
517  break;
518  }
519  }
520  }
521  }
522  }
523 }
524 
525 
527 {
528  int error = 0;
529  wxString tmp;
530  wxString msg;
531 
533 
534  // Spiit reference designators into name (prefix) and number: IC1 becomes IC, and 1.
535  SplitReferences();
536 
537  // count not yet annotated items or annotation error.
538  for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
539  {
540  msg.Empty();
541  tmp.Empty();
542 
543  if( componentFlatList[ii].m_IsNew ) // Not yet annotated
544  {
545  if( componentFlatList[ii].m_NumRef >= 0 )
546  tmp << componentFlatList[ii].m_NumRef;
547  else
548  tmp = wxT( "?" );
549 
550 
551  if( ( componentFlatList[ii].m_Unit > 0 )
552  && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) )
553  {
554  msg.Printf( _( "Item not annotated: %s%s (unit %d)\n" ),
555  GetChars( componentFlatList[ii].GetRef() ),
556  GetChars( tmp ),
557  componentFlatList[ii].m_Unit );
558  }
559  else
560  {
561  msg.Printf( _( "Item not annotated: %s%s\n" ),
562  GetChars( componentFlatList[ii].GetRef() ),
563  GetChars( tmp ) );
564  }
565 
566  aReporter.Report( msg, REPORTER::RPT_WARNING );
567  error++;
568  break;
569  }
570 
571  // Error if unit number selected does not exist ( greater than the number of
572  // parts in the component ). This can happen if a component has changed in a
573  // library after a previous annotation.
574  if( std::max( componentFlatList[ii].GetLibPart()->GetUnitCount(), 1 )
575  < componentFlatList[ii].m_Unit )
576  {
577  if( componentFlatList[ii].m_NumRef >= 0 )
578  tmp << componentFlatList[ii].m_NumRef;
579  else
580  tmp = wxT( "?" );
581 
582  msg.Printf( _( "Error: symbol %s%s unit %d and symbol has only %d units defined\n" ),
583  GetChars( componentFlatList[ii].GetRef() ),
584  GetChars( tmp ),
585  componentFlatList[ii].m_Unit,
586  componentFlatList[ii].GetLibPart()->GetUnitCount() );
587 
588  aReporter.Report( msg, REPORTER::RPT_ERROR );
589  error++;
590  break;
591  }
592  }
593 
594  if( error )
595  return error;
596 
597  // count the duplicated elements (if all are annotated)
598  int imax = componentFlatList.size() - 1;
599 
600  for( int ii = 0; (ii < imax) && (error < 4); ii++ )
601  {
602  msg.Empty();
603  tmp.Empty();
604 
605  if( ( componentFlatList[ii].CompareRef( componentFlatList[ii + 1] ) != 0 )
606  || ( componentFlatList[ii].m_NumRef != componentFlatList[ii + 1].m_NumRef ) )
607  continue;
608 
609  // Same reference found. If same unit, error!
610  if( componentFlatList[ii].m_Unit == componentFlatList[ii + 1].m_Unit )
611  {
612  if( componentFlatList[ii].m_NumRef >= 0 )
613  tmp << componentFlatList[ii].m_NumRef;
614  else
615  tmp = wxT( "?" );
616 
617  if( ( componentFlatList[ii].m_Unit > 0 )
618  && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) )
619  {
620  msg.Printf( _( "Multiple item %s%s (unit %d)\n" ),
621  GetChars( componentFlatList[ii].GetRef() ),
622  GetChars( tmp ),
623  componentFlatList[ii].m_Unit );
624  }
625  else
626  {
627  msg.Printf( _( "Multiple item %s%s\n" ),
628  GetChars( componentFlatList[ii].GetRef() ),
629  GetChars( tmp ) );
630  }
631 
632  aReporter.Report( msg, REPORTER::RPT_ERROR );
633  error++;
634  continue;
635  }
636 
637  /* Test error if units are different but number of parts per package
638  * too high (ex U3 ( 1 part) and we find U3B this is an error) */
639  if( componentFlatList[ii].GetLibPart()->GetUnitCount()
640  != componentFlatList[ii + 1].GetLibPart()->GetUnitCount() )
641  {
642  if( componentFlatList[ii].m_NumRef >= 0 )
643  tmp << componentFlatList[ii].m_NumRef;
644  else
645  tmp = wxT( "?" );
646 
647  if( ( componentFlatList[ii].m_Unit > 0 )
648  && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) )
649  {
650  msg.Printf( _( "Multiple item %s%s (unit %d)\n" ),
651  GetChars( componentFlatList[ii].GetRef() ),
652  GetChars( tmp ),
653  componentFlatList[ii].m_Unit );
654  }
655  else
656  {
657  msg.Printf( _( "Multiple item %s%s\n" ),
658  GetChars( componentFlatList[ii].GetRef() ),
659  GetChars( tmp ) );
660  }
661 
662  aReporter.Report( msg, REPORTER::RPT_ERROR );
663  error++;
664  }
665 
666  // Error if values are different between units, for the same reference
667  int next = ii + 1;
668 
669  if( componentFlatList[ii].CompareValue( componentFlatList[next] ) != 0 )
670  {
671  msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
672  GetChars( componentFlatList[ii].GetRef() ),
673  componentFlatList[ii].m_NumRef,
675  componentFlatList[ii].m_Unit ) ),
676  GetChars( componentFlatList[ii].m_Value->GetText() ),
677  GetChars( componentFlatList[next].GetRef() ),
678  componentFlatList[next].m_NumRef,
680  componentFlatList[next].m_Unit ) ),
681  GetChars( componentFlatList[next].m_Value->GetText() ) );
682 
683  aReporter.Report( msg, REPORTER::RPT_ERROR );
684  error++;
685  }
686  }
687 
688  // count the duplicated time stamps
689  SortByTimeStamp();
690 
691  for( int ii = 0; ( ii < imax ) && ( error < 4 ); ii++ )
692  {
693  if( ( componentFlatList[ii].m_TimeStamp != componentFlatList[ii + 1].m_TimeStamp )
694  || ( componentFlatList[ii].GetSheetPath() != componentFlatList[ii + 1].GetSheetPath() ) )
695  continue;
696 
697  // Same time stamp found.
698  wxString full_path;
699 
700  full_path.Printf( wxT( "%s%8.8X" ),
701  GetChars( componentFlatList[ii].GetSheetPath().Path() ),
702  componentFlatList[ii].m_TimeStamp );
703 
704  msg.Printf( _( "Duplicate time stamp (%s) for %s%d and %s%d" ),
705  GetChars( full_path ),
706  GetChars( componentFlatList[ii].GetRef() ), componentFlatList[ii].m_NumRef,
707  GetChars( componentFlatList[ii + 1].GetRef() ),
708  componentFlatList[ii + 1].m_NumRef );
709 
710  aReporter.Report( msg, REPORTER::RPT_WARNING );
711  error++;
712  }
713 
714  return error;
715 }
716 
717 
719  SCH_SHEET_PATH& aSheetPath )
720 {
721  wxASSERT( aComponent != NULL && aLibPart != NULL );
722 
723  m_RootCmp = aComponent;
724  m_Entry = aLibPart;
725  m_Unit = aComponent->GetUnitSelection( &aSheetPath );
726  m_SheetPath = aSheetPath;
727  m_IsNew = false;
728  m_Flag = 0;
729  m_TimeStamp = aComponent->GetTimeStamp();
730  m_CmpPos = aComponent->GetPosition();
731  m_SheetNum = 0;
732 
733  if( aComponent->GetRef( &aSheetPath ).IsEmpty() )
734  aComponent->SetRef( &aSheetPath, wxT( "DefRef?" ) );
735 
736  wxString ref = aComponent->GetRef( &aSheetPath );
737  SetRef( ref );
738 
739  m_NumRef = -1;
740 
741  if( aComponent->GetField( VALUE )->GetText().IsEmpty() )
742  aComponent->GetField( VALUE )->SetText( wxT( "~" ) );
743 
744  m_Value = aComponent->GetField( VALUE );
745 }
746 
747 
749 {
750  if( m_NumRef < 0 )
751  m_Ref += '?';
752  else
753  {
754  m_Ref = TO_UTF8( GetRef() << GetRefNumber() );
755  }
756 
757  m_RootCmp->SetRef( &m_SheetPath, FROM_UTF8( m_Ref.c_str() ) );
758  m_RootCmp->SetUnit( m_Unit );
759  m_RootCmp->SetUnitSelection( &m_SheetPath, m_Unit );
760 }
761 
762 
764 {
765  std::string refText = GetRefStr();
766 
767  m_NumRef = -1;
768 
769  int ll = refText.length() - 1;
770 
771  if( refText[ll] == '?' )
772  {
773  m_IsNew = true;
774 
775  if( !IsUnitsLocked() )
776  m_Unit = 0x7FFFFFFF;
777 
778  refText.erase( ll ); // delete last char
779 
780  SetRefStr( refText );
781  }
782  else if( isdigit( refText[ll] ) == 0 )
783  {
784  m_IsNew = true;
785 
786  if( !IsUnitsLocked() )
787  m_Unit = 0x7FFFFFFF;
788  }
789  else
790  {
791  while( ll >= 0 )
792  {
793  if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) )
794  ll--;
795  else
796  {
797  if( isdigit( refText[ll + 1] ) )
798  {
799  // null terminated C string into cp
800  const char* cp = refText.c_str() + ll + 1;
801 
802  m_NumRef = atoi( cp );
803  }
804 
805  refText.erase( ll+1 ); // delete from ll+1 to end
806  break;
807  }
808  }
809 
810  SetRefStr( refText );
811  }
812 }
813 
814 
815 wxString SCH_REFERENCE_LIST::Shorthand( std::vector<SCH_REFERENCE> aList )
816 {
817  wxString retVal;
818 
819  std::sort( aList.begin(), aList.end(),
820  []( const SCH_REFERENCE& lhs, const SCH_REFERENCE& rhs ) -> bool
821  {
822  wxString lhRef( lhs.GetRef() << lhs.GetRefNumber() );
823  wxString rhRef( rhs.GetRef() << rhs.GetRefNumber() );
824  return RefDesStringCompare( lhRef, rhRef ) < 0;
825  } );
826 
827  size_t i = 0;
828 
829  while( i < aList.size() )
830  {
831  wxString ref = aList[ i ].GetRef();
832 
833  size_t j = i;
834 
835  while( j + 1 < aList.size() && aList[ j + 1 ].GetRef() == ref )
836  j = j + 1;
837 
838  if( !retVal.IsEmpty() )
839  retVal << wxT( ", " );
840 
841  if( j == i )
842  {
843  retVal << ref << aList[ i ].GetRefNumber();
844  }
845  else if( j == i + 1 )
846  {
847  retVal << ref << aList[ i ].GetRefNumber();
848  retVal << wxT( ", " );
849  retVal << ref << aList[ j ].GetRefNumber();
850  }
851  else
852  {
853  retVal << ref << aList[ i ].GetRefNumber();
854  retVal << wxT( " - " );
855  retVal << ref << aList[ j ].GetRefNumber();
856  }
857 
858  i = j + 1;
859  }
860 
861  return retVal;
862 }
CITER next(CITER it)
Definition: ptree.cpp:130
wxPoint m_CmpPos
The physical position of the component in schematic used to annotate by X or Y position.
int CompareLibName(const SCH_REFERENCE &item) const
int RefDesStringCompare(const wxString &strFWord, const wxString &strSWord)
Function RefDesStringCompare acts just like the strcmp function but treats numbers within the string ...
Definition: string.cpp:466
static bool sortByTimeStamp(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
std::vector< SCH_REFERENCE > componentFlatList
void RemoveSubComponentsFromList()
Function RemoveSubComponentsFromList Remove sub components from the list, when multiples parts per pa...
int CompareValue(const SCH_REFERENCE &item) const
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
void RemoveItem(unsigned int aIndex)
Function RemoveItem removes an item from the list of references.
void Split()
Function Split attempts to split the reference designator into a name (U) and number (1)...
int GetUnitSelection(SCH_SHEET_PATH *aSheet)
static wxString Shorthand(std::vector< SCH_REFERENCE > aList)
Function Shorthand Returns a shorthand string representing all the references in the list...
int m_SheetNum
The sheet number for the reference.
bool IsSameInstance(const SCH_REFERENCE &other) const
Function IsSameInstance returns whether this reference refers to the same component instance (compone...
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
int GetUnit() const
void SortByRefAndValue()
Function SortByRefAndValue sorts the list of references by value.
Class SCH_REFERENCE_LIST is used to create a flattened list of components because in a complex hierar...
void GetRefsInUse(int aIndex, std::vector< int > &aIdList, int aMinRefId)
Function GetRefsInUse adds all the reference designator numbers greater than aMinRefId to aIdList ski...
int m_Unit
The unit number for components with multiple parts per package.
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
void SortByTimeStamp()
Function SortComponentsByTimeStamp sort the flat list by Time Stamp.
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
int CompareRef(const SCH_REFERENCE &item) const
wxString buildFullReference(const SCH_REFERENCE &aItem, int aUnitNumber=-1)
SCH_COMPONENT * m_RootCmp
The component associated the reference object.
static bool sortByRefAndValue(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:128
void Annotate()
Function Annotate updates the annotation of the component according the the current object state...
Define a library symbol object.
void Annotate(bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap)
Function Annotate set the reference designators in the list that have not been annotated.
int FindUnit(size_t aIndex, int aUnit)
searches the sorted list of components for a another component with the same reference and a given pa...
static bool sortByYPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
Class SCH_SHEET_PATH.
const wxString GetRef(const SCH_SHEET_PATH *aSheet)
Return the reference for the given sheet path.
static bool sortByReferenceOnly(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Type SCH_MULTI_UNIT_REFERENCE_MAP is used to create a map of reference designators for multi-unit par...
timestamp_t m_TimeStamp
The time stamp for the reference.
YYCODETYPE lhs
SCH_SHEET_PATH m_SheetPath
The sheet path for this reference.
wxString GetRef() const
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
Definition the SCH_COMPONENT class for Eeschema.
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
#define max(a, b)
Definition: auxiliary.h:86
void SortByReferenceOnly()
Function SortByReferenceOnly sorts the list of references by reference.
void SplitReferences()
Function SplitReferences attempts to split all reference designators into a name (U) and number (1)...
size_t i
Definition: json11.cpp:597
static wxString SubReference(int aUnit, bool aAddSeparator=true)
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
wxPoint GetPosition() const override
Function GetPosition.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
int Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Function Cmp Compare if this is the same sheet path as aSheetPathToTest.
int CreateFirstFreeRefId(std::vector< int > &aIdList, int aFirstValue)
Function CreateFirstFreeRefId searches for the first free reference number in aListId of reference nu...
int GetLastReference(int aIndex, int aMinValue)
Function GetLastReference returns the last used (greatest) reference number in the reference list for...
int CheckAnnotation(REPORTER &aReporter)
Function CheckAnnotation check for annotations errors.
unsigned GetCount()
Function GetCount.
wxString GetRefNumber() const
#define VALUE
Class SCH_REFERENCE is used as a helper to define a component&#39;s reference designator in a schematic...
timestamp_t GetTimeStamp() const
Definition: base_struct.h:204
static bool sortByXPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
virtual void SetText(const wxString &aText)
Definition: eda_text.h:139