KiCad PCB EDA Suite
component_references_lister.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 1992-2018 jean-pierre Charras <jp.charras at wanadoo.fr>
5  * Copyright (C) 1992-2011 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.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 
31 #include <sch_reference_list.h>
32 
33 #include <wx/regex.h>
34 #include <algorithm>
35 #include <vector>
36 #include <unordered_set>
37 
38 #include <refdes_utils.h>
39 #include <erc_settings.h>
40 #include <sch_symbol.h>
41 #include <sch_edit_frame.h>
42 
43 
44 void SCH_REFERENCE_LIST::RemoveItem( unsigned int aIndex )
45 {
46  if( aIndex < flatList.size() )
47  flatList.erase( flatList.begin() + aIndex );
48 }
49 
50 
52 {
53  int ii = item1.CompareRef( item2 );
54 
55  if( ii == 0 )
56  ii = item1.m_sheetNum - item2.m_sheetNum;
57 
58  if( ii == 0 )
59  ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
60 
61  if( ii == 0 )
62  ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
63 
64  if( ii == 0 )
65  return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
66  else
67  return ii < 0;
68 }
69 
70 
72 {
73  int ii = item1.CompareRef( item2 );
74 
75  if( ii == 0 )
76  ii = item1.m_sheetNum - item2.m_sheetNum;
77 
78  if( ii == 0 )
79  ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
80 
81  if( ii == 0 )
82  ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
83 
84  if( ii == 0 )
85  return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
86  else
87  return ii < 0;
88 }
89 
90 
92  const SCH_REFERENCE& item2 )
93 {
94  int ii = item1.CompareRef( item2 );
95 
96  if( ii == 0 )
97  ii = item1.CompareValue( item2 );
98 
99  if( ii == 0 )
100  ii = item1.m_unit - item2.m_unit;
101 
102  if( ii == 0 )
103  ii = item1.m_sheetNum - item2.m_sheetNum;
104 
105  if( ii == 0 )
106  ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
107 
108  if( ii == 0 )
109  ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
110 
111  if( ii == 0 )
112  return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
113  else
114  return ii < 0;
115 }
116 
117 
119  const SCH_REFERENCE& item2 )
120 {
121  int ii = UTIL::RefDesStringCompare( item1.GetRef(), item2.GetRef() );
122 
123  if( ii == 0 )
124  ii = item1.m_unit - item2.m_unit;
125 
126  if( ii == 0 )
127  return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
128  else
129  return ii < 0;
130 }
131 
132 
134  const SCH_REFERENCE& item2 )
135 {
136  int ii = item1.m_sheetPath.Cmp( item2.m_sheetPath );
137 
138  if( ii == 0 )
139  return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
140  else
141  return ii < 0;
142 }
143 
144 
145 int SCH_REFERENCE_LIST::FindUnit( size_t aIndex, int aUnit )
146 {
147  int NumRef;
148 
149  NumRef = flatList[aIndex].m_numRef;
150 
151  for( size_t ii = 0; ii < flatList.size(); ii++ )
152  {
153  if( ( aIndex == ii )
154  || ( flatList[ii].m_isNew )
155  || ( flatList[ii].m_numRef != NumRef )
156  || ( flatList[aIndex].CompareRef( flatList[ii] ) != 0 ) )
157  continue;
158 
159  if( flatList[ii].m_unit == aUnit )
160  return (int) ii;
161  }
162 
163  return -1;
164 }
165 
166 
167 int SCH_REFERENCE_LIST::FindRefByPath( const wxString& aPath ) const
168 {
169  for( size_t i = 0; i < flatList.size(); ++i )
170  {
171  if( flatList[i].GetPath() == aPath )
172  return i;
173  }
174 
175  return -1;
176 }
177 
178 
179 int SCH_REFERENCE_LIST::FindRef( const wxString& aRef ) const
180 {
181  for( size_t i = 0; i < flatList.size(); ++i )
182  {
183  if( flatList[i].GetRef() == aRef )
184  return i;
185  }
186 
187  return -1;
188 }
189 
190 
191 void SCH_REFERENCE_LIST::GetRefsInUse( int aIndex, std::vector< int >& aIdList, int aMinRefId )
192 {
193  aIdList.clear();
194 
195  for( SCH_REFERENCE& ref : flatList )
196  {
197  if( flatList[aIndex].CompareRef( ref ) == 0 && ref.m_numRef >= aMinRefId )
198  aIdList.push_back( ref.m_numRef );
199  }
200 
201  sort( aIdList.begin(), aIdList.end() );
202 
203  // Ensure each reference number appears only once. If there are components with
204  // multiple parts per package the same number will be stored for each part.
205  std::vector< int >::iterator it = unique( aIdList.begin(), aIdList.end() );
206 
207  // Using the C++ unique algorithm only moves the duplicate entries to the end of
208  // of the array. This removes the duplicate entries from the array.
209  aIdList.resize( it - aIdList.begin() );
210 }
211 
212 
213 int SCH_REFERENCE_LIST::GetLastReference( int aIndex, int aMinValue )
214 {
215  int lastNumber = aMinValue;
216 
217  for( SCH_REFERENCE& ref : flatList )
218  {
219  // search only for the current reference prefix:
220  if( flatList[aIndex].CompareRef( ref ) != 0 )
221  continue;
222 
223  // update max value for the current reference prefix
224  if( lastNumber < ref.m_numRef )
225  lastNumber = ref.m_numRef;
226  }
227 
228  return lastNumber;
229 }
230 
231 
232 int SCH_REFERENCE_LIST::CreateFirstFreeRefId( std::vector<int>& aIdList, int aFirstValue )
233 {
234  int expectedId = aFirstValue;
235 
236  // We search for expected Id a value >= aFirstValue.
237  // Skip existing Id < aFirstValue
238  unsigned ii = 0;
239 
240  for( ; ii < aIdList.size(); ii++ )
241  {
242  if( expectedId <= aIdList[ii] )
243  break;
244  }
245 
246  // Ids are sorted by increasing value, from aFirstValue
247  // So we search from aFirstValue the first not used value, i.e. the first hole in list.
248  for( ; ii < aIdList.size(); ii++ )
249  {
250  if( expectedId != aIdList[ii] ) // This id is not yet used.
251  {
252  // Insert this free Id, in order to keep list sorted
253  aIdList.insert( aIdList.begin() + ii, expectedId );
254  return expectedId;
255  }
256 
257  expectedId++;
258  }
259 
260  // All existing Id are tested, and all values are found in use.
261  // So Create a new one.
262  aIdList.push_back( expectedId );
263  return expectedId;
264 }
265 
266 
267 // A helper function to build a full reference string of a SCH_REFERENCE item
268 wxString buildFullReference( const SCH_REFERENCE& aItem, int aUnitNumber = -1 )
269 {
270  wxString fullref;
271  fullref = aItem.GetRef() + aItem.GetRefNumber();
272 
273  if( aUnitNumber < 0 )
274  fullref << ".." << aItem.GetUnit();
275  else
276  fullref << ".." << aUnitNumber;
277 
278  return fullref;
279 }
280 
281 
282 void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
283  SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap )
284 {
285  if ( flatList.size() == 0 )
286  return;
287 
288  int LastReferenceNumber = 0;
289  int NumberOfUnits, Unit;
290 
291  /* calculate index of the first component with the same reference prefix
292  * than the current component. All components having the same reference
293  * prefix will receive a reference number with consecutive values:
294  * IC .. will be set to IC4, IC4, IC5 ...
295  */
296  unsigned first = 0;
297 
298  // calculate the last used number for this reference prefix:
299  int minRefId;
300 
301  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
302  if( aUseSheetNum )
303  minRefId = flatList[first].m_sheetNum * aSheetIntervalId + 1;
304  else
305  minRefId = aStartNumber + 1;
306 
307  // For multi units components, when "keep order of multi unit" option is selected,
308  // store the list of already used full references.
309  // The algorithm try to allocate the new reference to components having the same
310  // old reference.
311  // This algo works fine as long as the previous annotation has no duplicates.
312  // But when a hierarchy is reannotated with this option, the previous anotation can
313  // have duplicate references, and obviously we must fix these duplicate.
314  // therefore do not try to allocate a full reference more than once when trying
315  // to keep this order of multi units.
316  // inUseRefs keep trace of previously allocated references
317  std::unordered_set<wxString> inUseRefs;
318 
319  // This is the list of all Id already in use for a given reference prefix.
320  // Will be refilled for each new reference prefix.
321  std::vector<int>idList;
322  GetRefsInUse( first, idList, minRefId );
323 
324  for( unsigned ii = 0; ii < flatList.size(); ii++ )
325  {
326  auto& ref_unit = flatList[ii];
327 
328  if( ref_unit.m_flag )
329  continue;
330 
331  // Check whether this component is in aLockedUnitMap.
332  SCH_REFERENCE_LIST* lockedList = NULL;
333  for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
334  {
335  unsigned n_refs = pair.second.GetCount();
336 
337  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
338  {
339  SCH_REFERENCE &thisRef = pair.second[thisRefI];
340 
341  if( thisRef.IsSameInstance( ref_unit ) )
342  {
343  lockedList = &pair.second;
344  break;
345  }
346  }
347  if( lockedList != NULL ) break;
348  }
349 
350  if( ( flatList[first].CompareRef( ref_unit ) != 0 )
351  || ( aUseSheetNum && ( flatList[first].m_sheetNum != ref_unit.m_sheetNum ) ) )
352  {
353  // New reference found: we need a new ref number for this reference
354  first = ii;
355 
356  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
357  if( aUseSheetNum )
358  minRefId = ref_unit.m_sheetNum * aSheetIntervalId + 1;
359  else
360  minRefId = aStartNumber + 1;
361 
362  GetRefsInUse( first, idList, minRefId );
363  }
364 
365  // Annotation of one part per package components (trivial case).
366  if( ref_unit.GetLibPart()->GetUnitCount() <= 1 )
367  {
368  if( ref_unit.m_isNew )
369  {
370  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
371  ref_unit.m_numRef = LastReferenceNumber;
372  }
373 
374  ref_unit.m_unit = 1;
375  ref_unit.m_flag = 1;
376  ref_unit.m_isNew = false;
377  continue;
378  }
379 
380  // Annotation of multi-unit parts ( n units per part ) (complex case)
381  NumberOfUnits = ref_unit.GetLibPart()->GetUnitCount();
382 
383  if( ref_unit.m_isNew )
384  {
385  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
386  ref_unit.m_numRef = LastReferenceNumber;
387 
388  if( !ref_unit.IsUnitsLocked() )
389  ref_unit.m_unit = 1;
390 
391  ref_unit.m_flag = 1;
392  }
393 
394  // If this component is in aLockedUnitMap, copy the annotation to all
395  // components that are not it
396  if( lockedList != NULL )
397  {
398  unsigned n_refs = lockedList->GetCount();
399 
400  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
401  {
402  SCH_REFERENCE &thisRef = (*lockedList)[thisRefI];
403 
404  if( thisRef.IsSameInstance( ref_unit ) )
405  {
406  // This is the component we're currently annotating. Hold the unit!
407  ref_unit.m_unit = thisRef.m_unit;
408  // lock this new full reference
409  inUseRefs.insert( buildFullReference( ref_unit ) );
410  }
411 
412  if( thisRef.CompareValue( ref_unit ) != 0 )
413  continue;
414 
415  if( thisRef.CompareLibName( ref_unit ) != 0 )
416  continue;
417 
418  // Find the matching component
419  for( unsigned jj = ii + 1; jj < flatList.size(); jj++ )
420  {
421  if( ! thisRef.IsSameInstance( flatList[jj] ) )
422  continue;
423 
424  wxString ref_candidate = buildFullReference( ref_unit, thisRef.m_unit );
425 
426  // propagate the new reference and unit selection to the "old" component,
427  // if this new full reference is not already used (can happens when initial
428  // multiunits components have duplicate references)
429  if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
430  {
431  flatList[jj].m_numRef = ref_unit.m_numRef;
432  flatList[jj].m_unit = thisRef.m_unit;
433  flatList[jj].m_isNew = false;
434  flatList[jj].m_flag = 1;
435  // lock this new full reference
436  inUseRefs.insert( ref_candidate );
437  break;
438  }
439  }
440  }
441  }
442  else
443  {
444  /* search for others units of this component.
445  * we search for others parts that have the same value and the same
446  * reference prefix (ref without ref number)
447  */
448  for( Unit = 1; Unit <= NumberOfUnits; Unit++ )
449  {
450  if( ref_unit.m_unit == Unit )
451  continue;
452 
453  int found = FindUnit( ii, Unit );
454 
455  if( found >= 0 )
456  continue; // this unit exists for this reference (unit already annotated)
457 
458  // Search a component to annotate ( same prefix, same value, not annotated)
459  for( unsigned jj = ii + 1; jj < flatList.size(); jj++ )
460  {
461  auto& cmp_unit = flatList[jj];
462 
463  if( cmp_unit.m_flag ) // already tested
464  continue;
465 
466  if( cmp_unit.CompareRef( ref_unit ) != 0 )
467  continue;
468 
469  if( cmp_unit.CompareValue( ref_unit ) != 0 )
470  continue;
471 
472  if( cmp_unit.CompareLibName( ref_unit ) != 0 )
473  continue;
474 
475  if( aUseSheetNum &&
476  cmp_unit.GetSheetPath().Cmp( ref_unit.GetSheetPath() ) != 0 )
477  continue;
478 
479  if( !cmp_unit.m_isNew )
480  continue;
481 
482  // Component without reference number found, annotate it if possible
483  if( !cmp_unit.IsUnitsLocked()
484  || ( cmp_unit.m_unit == Unit ) )
485  {
486  cmp_unit.m_numRef = ref_unit.m_numRef;
487  cmp_unit.m_unit = Unit;
488  cmp_unit.m_flag = 1;
489  cmp_unit.m_isNew = false;
490  break;
491  }
492  }
493  }
494  }
495  }
496 }
497 
499 {
500  int error = 0;
501  wxString tmp;
502  wxString msg;
503 
505 
506  // Spiit reference designators into name (prefix) and number: IC1 becomes IC, and 1.
507  SplitReferences();
508 
509  // count not yet annotated items or annotation error.
510  for( unsigned ii = 0; ii < flatList.size(); ii++ )
511  {
512  msg.Empty();
513  tmp.Empty();
514 
515  if( flatList[ii].m_isNew ) // Not yet annotated
516  {
517  if( flatList[ii].m_numRef >= 0 )
518  tmp << flatList[ii].m_numRef;
519  else
520  tmp = wxT( "?" );
521 
522 
523  if( ( flatList[ii].m_unit > 0 ) && ( flatList[ii].m_unit < 0x7FFFFFFF ) )
524  {
525  msg.Printf( _( "Item not annotated: %s%s (unit %d)\n" ),
526  flatList[ii].GetRef(),
527  tmp,
528  flatList[ii].m_unit );
529  }
530  else
531  {
532  msg.Printf( _( "Item not annotated: %s%s\n" ),
533  flatList[ii].GetRef(),
534  tmp );
535  }
536 
537  aHandler( ERCE_UNANNOTATED, msg, &flatList[ii], nullptr );
538  error++;
539  break;
540  }
541 
542  // Error if unit number selected does not exist (greater than the number of units in
543  // the component). This can happen if a component has changed in a library after a
544  // previous annotation.
545  if( std::max( flatList[ii].GetLibPart()->GetUnitCount(), 1 ) < flatList[ii].m_unit )
546  {
547  if( flatList[ii].m_numRef >= 0 )
548  tmp << flatList[ii].m_numRef;
549  else
550  tmp = wxT( "?" );
551 
552  msg.Printf( _( "Error: symbol %s%s%s (unit %d) exceeds units defined (%d)\n" ),
553  flatList[ii].GetRef(),
554  tmp,
555  LIB_PART::SubReference( flatList[ii].m_unit ),
556  flatList[ii].m_unit,
557  flatList[ii].GetLibPart()->GetUnitCount() );
558 
559  aHandler( ERCE_EXTRA_UNITS, msg, &flatList[ii], nullptr );
560  error++;
561  break;
562  }
563  }
564 
565  // count the duplicated elements (if all are annotated)
566  int imax = flatList.size() - 1;
567 
568  for( int ii = 0; ii < imax; ii++ )
569  {
570  msg.Empty();
571  tmp.Empty();
572 
573  if( ( flatList[ii].CompareRef( flatList[ii + 1] ) != 0 )
574  || ( flatList[ii].m_numRef != flatList[ ii + 1].m_numRef ) )
575  {
576  continue;
577  }
578 
579  // Same reference found. If same unit, error!
580  if( flatList[ii].m_unit == flatList[ ii + 1].m_unit )
581  {
582  if( flatList[ii].m_numRef >= 0 )
583  tmp << flatList[ii].m_numRef;
584  else
585  tmp = wxT( "?" );
586 
587  if( ( flatList[ii].m_unit > 0 ) && ( flatList[ii].m_unit < 0x7FFFFFFF ) )
588  {
589  msg.Printf( _( "Duplicate items %s%s%s\n" ),
590  flatList[ii].GetRef(),
591  tmp,
592  LIB_PART::SubReference( flatList[ii].m_unit ) );
593  }
594  else
595  {
596  msg.Printf( _( "Duplicate items %s%s\n" ),
597  flatList[ii].GetRef(),
598  tmp );
599  }
600 
601  aHandler( ERCE_DUPLICATE_REFERENCE, msg, &flatList[ii], &flatList[ii+1] );
602  error++;
603  continue;
604  }
605 
606  /* Test error if units are different but number of parts per package
607  * too high (ex U3 ( 1 part) and we find U3B this is an error) */
608  if( flatList[ii].GetLibPart()->GetUnitCount()
609  != flatList[ ii + 1].GetLibPart()->GetUnitCount() )
610  {
611  if( flatList[ii].m_numRef >= 0 )
612  tmp << flatList[ii].m_numRef;
613  else
614  tmp = wxT( "?" );
615 
616  if( ( flatList[ii].m_unit > 0 )
617  && ( flatList[ii].m_unit < 0x7FFFFFFF ) )
618  {
619  msg.Printf( _( "Duplicate items %s%s%s\n" ),
620  flatList[ii].GetRef(),
621  tmp,
622  LIB_PART::SubReference( flatList[ii].m_unit ) );
623  }
624  else
625  {
626  msg.Printf( _( "Duplicate items %s%s\n" ),
627  flatList[ii].GetRef(),
628  tmp );
629  }
630 
631  aHandler( ERCE_DUPLICATE_REFERENCE, msg, &flatList[ii], &flatList[ii+1] );
632  error++;
633  }
634 
635  // Error if values are different between units, for the same reference
636  int next = ii + 1;
637 
638  if( flatList[ii].CompareValue( flatList[next] ) != 0 )
639  {
640  msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
641  flatList[ii].GetRef(),
642  flatList[ii].m_numRef,
643  LIB_PART::SubReference( flatList[ii].m_unit ),
644  flatList[ii].m_value,
645  flatList[next].GetRef(),
646  flatList[next].m_numRef,
648  flatList[next].m_value );
649 
650  aHandler( ERCE_DIFFERENT_UNIT_VALUE, msg, &flatList[ii], &flatList[ii+1] );
651  error++;
652  }
653  }
654 
655  return error;
656 }
657 
658 
660  const SCH_SHEET_PATH& aSheetPath )
661 {
662  wxASSERT( aSymbol != NULL );
663 
664  m_rootSymbol = aSymbol;
665  m_libPart = aLibPart; // Warning: can be nullptr for orphan components
666  // (i.e. with a symbol library not found)
667  m_unit = aSymbol->GetUnitSelection( &aSheetPath );
668  m_footprint = aSymbol->GetFootprint( &aSheetPath, true );
669  m_sheetPath = aSheetPath;
670  m_isNew = false;
671  m_flag = 0;
672  m_symbolUuid = aSymbol->m_Uuid;
673  m_symbolPos = aSymbol->GetPosition();
674  m_sheetNum = 0;
675 
676  if( aSymbol->GetRef( &aSheetPath ).IsEmpty() )
677  aSymbol->SetRef( &aSheetPath, wxT( "DefRef?" ) );
678 
679  wxString ref = aSymbol->GetRef( &aSheetPath );
680  SetRef( ref );
681 
682  m_numRef = -1;
683 
684  if( aSymbol->GetValue( &aSheetPath, false ).IsEmpty() )
685  aSymbol->SetValue( &aSheetPath, wxT( "~" ) );
686 
687  m_value = aSymbol->GetValue( &aSheetPath, false );
688 }
689 
690 
692 {
693  if( m_numRef < 0 )
694  m_ref += '?';
695  else
696  m_ref = TO_UTF8( GetRef() << GetRefNumber() );
697 
701 }
702 
703 
705 {
706  std::string refText = GetRefStr();
707 
708  m_numRef = -1;
709 
710  int ll = refText.length() - 1;
711 
712  if( refText[ll] == '?' )
713  {
714  m_isNew = true;
715 
716  if( !IsUnitsLocked() )
717  m_unit = 0x7FFFFFFF;
718 
719  refText.erase( ll ); // delete last char
720 
721  SetRefStr( refText );
722  }
723  else if( isdigit( refText[ll] ) == 0 )
724  {
725  m_isNew = true;
726 
727  if( !IsUnitsLocked() )
728  m_unit = 0x7FFFFFFF;
729  }
730  else
731  {
732  while( ll >= 0 )
733  {
734  if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) )
735  ll--;
736  else
737  {
738  if( isdigit( refText[ll + 1] ) )
739  {
740  // null terminated C string into cp
741  const char* cp = refText.c_str() + ll + 1;
742 
743  m_numRef = atoi( cp );
744  }
745 
746  refText.erase( ll+1 ); // delete from ll+1 to end
747  break;
748  }
749  }
750 
751  SetRefStr( refText );
752  }
753 }
754 
755 
756 wxString SCH_REFERENCE_LIST::Shorthand( std::vector<SCH_REFERENCE> aList )
757 {
758  wxString retVal;
759  size_t i = 0;
760 
761  while( i < aList.size() )
762  {
763  wxString ref = aList[ i ].GetRef();
764  int numRef = aList[ i ].m_numRef;
765 
766  size_t range = 1;
767 
768  while( i + range < aList.size()
769  && aList[ i + range ].GetRef() == ref
770  && aList[ i + range ].m_numRef == int( numRef + range ) )
771  {
772  range++;
773  }
774 
775  if( !retVal.IsEmpty() )
776  retVal << wxT( ", " );
777 
778  if( range == 1 )
779  {
780  retVal << ref << aList[ i ].GetRefNumber();
781  }
782  else if( range == 2 )
783  {
784  retVal << ref << aList[ i ].GetRefNumber();
785  retVal << wxT( ", " );
786  retVal << ref << aList[ i + 1 ].GetRefNumber();
787  }
788  else
789  {
790  retVal << ref << aList[ i ].GetRefNumber();
791  retVal << wxT( "-" );
792  retVal << ref << aList[ i + ( range - 1 ) ].GetRefNumber();
793  }
794 
795  i+= range;
796  }
797 
798  return retVal;
799 }
CITER next(CITER it)
Definition: ptree.cpp:126
Units of same symbol have different values.
Definition: erc_settings.h:70
static bool sortByTimeStamp(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
void RemoveItem(unsigned int aIndex)
Remove an item from the list of references.
void Split()
Attempt to split the reference designator into a name (U) and number (1).
int FindRefByPath(const wxString &aPath) const
Search the list for a symbol with the given KIID path.
wxPoint m_symbolPos
The physical position of the symbol in schematic.
int m_sheetNum
The sheet number for the reference.
Collection of utility functions for component reference designators (refdes)
static wxString Shorthand(std::vector< SCH_REFERENCE > aList)
Return a shorthand string representing all the references in the list.
int GetUnit() const
wxString GetRefNumber() const
void SortByRefAndValue()
Sort the list of references by value.
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
int FindRef(const wxString &aPath) const
Search the list for a symbol with a given reference.
void SetRefStr(const std::string &aReference)
const char * c_str() const
Definition: utf8.h:102
const wxString GetFootprint(const SCH_SHEET_PATH *sheet, bool aResolve) const
Definition: sch_symbol.cpp:638
void GetRefsInUse(int aIndex, std::vector< int > &aIdList, int aMinRefId)
Add all the reference designator numbers greater than aMinRefId to aIdList skipping the reference at ...
int RefDesStringCompare(const wxString &aFirst, const wxString &aSecond)
Acts just like the strcmp function but treats numbers within the string text correctly for sorting.
int m_unit
The unit number for symbol with multiple parts.
wxString GetRef() const
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
const wxString GetValue(const SCH_SHEET_PATH *sheet, bool aResolve) const
Definition: sch_symbol.cpp:588
#define NULL
int CompareValue(const SCH_REFERENCE &item) const
wxString buildFullReference(const SCH_REFERENCE &aItem, int aUnitNumber=-1)
int CompareLibName(const SCH_REFERENCE &item) const
static bool sortByRefAndValue(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
bool m_isNew
True if not yet annotated.
wxString m_footprint
The footprint assigned.
void Annotate()
Update the annotation of the symbol according the the current object state.
KIID m_symbolUuid
UUID of the symbol.
Define a library symbol object.
Definition: lib_symbol.h:93
void Annotate(bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap)
Set the reference designators in the list that have not been annotated.
int FindUnit(size_t aIndex, int aUnit)
Search the sorted list of symbols for a another symbol with the same reference and a given part unit.
void SetUnit(int aUnit)
Change the unit number to aUnit.
Definition: sch_symbol.cpp:317
static bool sortByYPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Symbol has not been annotated.
Definition: erc_settings.h:68
wxString m_value
The symbol value.
static bool sortByReferenceOnly(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Container to map reference designators for multi-unit parts.
const KIID m_Uuid
Definition: eda_item.h:524
unsigned GetCount() const
int CompareRef(const SCH_REFERENCE &item) const
UTF8 m_ref
Symbol reference prefix, without number (for IC1, this is IC) )
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
Definition: sch_symbol.cpp:477
int CheckAnnotation(ANNOTATION_ERROR_HANDLER aErrorHandler)
Check for annotations errors.
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Definition: sch_symbol.cpp:562
const char * GetRefStr() const
Return reference name with unit altogether.
SCH_SHEET_PATH m_sheetPath
The sheet path for this reference.
More than one symbol with the same reference.
Definition: erc_settings.h:71
void SplitReferences()
Attempt to split all reference designators into a name (U) and number (1).
int m_numRef
The numeric part of the reference designator.
#define _(s)
Definition: 3d_actions.cpp:33
std::function< void(ERCE_T aType, const wxString &aMsg, SCH_REFERENCE *aItemA, SCH_REFERENCE *aItemB)> ANNOTATION_ERROR_HANDLER
Define a standard error handler for annotation errors.
bool IsSameInstance(const SCH_REFERENCE &other) const
Return whether this reference refers to the same symbol instance (symbol and sheet) as another.
static wxString SubReference(int aUnit, bool aAddSeparator=true)
Definition: lib_symbol.cpp:447
Schematic symbol object.
Definition: sch_symbol.h:79
wxPoint GetPosition() const override
Definition: sch_symbol.h:681
LIB_PART * m_libPart
The source symbol from a library.
int CreateFirstFreeRefId(std::vector< int > &aIdList, int aFirstValue)
Search for the first free reference number in aListId of reference numbers in use.
void SetRef(const wxString &aReference)
SCH_COMPONENT * m_rootSymbol
The symbol associated the reference object.
std::vector< SCH_REFERENCE > flatList
Symbol has more units than are defined.
Definition: erc_settings.h:69
int GetLastReference(int aIndex, int aMinValue)
Return the last used (greatest) reference number in the reference list for the prefix used by the sym...
void SetValue(const SCH_SHEET_PATH *sheet, const wxString &aValue)
Definition: sch_symbol.cpp:609
int Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare if this is the same sheet path as aSheetPathToTest.
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Definition: sch_symbol.cpp:546
A helper to define a symbol's reference designator in a schematic.
static bool sortByXPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:427