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  for( unsigned ii = 0; ii < GetCount(); ii++ )
54  {
55  if( flatList[ii].IsSameInstance( aItem ) )
56  return true;
57  }
58 
59  return false;
60 }
61 
62 
64 {
65  int ii = item1.CompareRef( item2 );
66 
67  if( ii == 0 )
68  ii = item1.m_sheetNum - item2.m_sheetNum;
69 
70  if( ii == 0 )
71  ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
72 
73  if( ii == 0 )
74  ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
75 
76  if( ii == 0 )
77  return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
78  else
79  return ii < 0;
80 }
81 
82 
84 {
85  int ii = item1.CompareRef( item2 );
86 
87  if( ii == 0 )
88  ii = item1.m_sheetNum - item2.m_sheetNum;
89 
90  if( ii == 0 )
91  ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
92 
93  if( ii == 0 )
94  ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
95 
96  if( ii == 0 )
97  return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
98  else
99  return ii < 0;
100 }
101 
102 
104  const SCH_REFERENCE& item2 )
105 {
106  int ii = item1.CompareRef( item2 );
107 
108  if( ii == 0 )
109  ii = item1.CompareValue( item2 );
110 
111  if( ii == 0 )
112  ii = item1.m_unit - item2.m_unit;
113 
114  if( ii == 0 )
115  ii = item1.m_sheetNum - item2.m_sheetNum;
116 
117  if( ii == 0 )
118  ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
119 
120  if( ii == 0 )
121  ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
122 
123  if( ii == 0 )
124  return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
125  else
126  return ii < 0;
127 }
128 
129 
131  const SCH_REFERENCE& item2 )
132 {
133  int ii = UTIL::RefDesStringCompare( item1.GetRef(), item2.GetRef() );
134 
135  if( ii == 0 )
136  ii = item1.m_unit - item2.m_unit;
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 
146  const SCH_REFERENCE& item2 )
147 {
148  int ii = item1.m_sheetPath.Cmp( item2.m_sheetPath );
149 
150  if( ii == 0 )
151  return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
152  else
153  return ii < 0;
154 }
155 
156 
157 int SCH_REFERENCE_LIST::FindUnit( size_t aIndex, int aUnit ) const
158 {
159  int NumRef = flatList[aIndex].m_numRef;
160 
161  for( size_t ii = 0; ii < flatList.size(); ii++ )
162  {
163  if( ( aIndex == ii )
164  || ( flatList[ii].m_isNew )
165  || ( flatList[ii].m_numRef != NumRef )
166  || ( flatList[aIndex].CompareRef( flatList[ii] ) != 0 ) )
167  continue;
168 
169  if( flatList[ii].m_unit == aUnit )
170  return (int) ii;
171  }
172 
173  return -1;
174 }
175 
176 
177 int SCH_REFERENCE_LIST::FindRefByPath( const wxString& aPath ) const
178 {
179  for( size_t i = 0; i < flatList.size(); ++i )
180  {
181  if( flatList[i].GetPath() == aPath )
182  return i;
183  }
184 
185  return -1;
186 }
187 
188 
189 int SCH_REFERENCE_LIST::FindRef( const wxString& aRef ) const
190 {
191  for( size_t i = 0; i < flatList.size(); ++i )
192  {
193  if( flatList[i].GetRef() == aRef )
194  return i;
195  }
196 
197  return -1;
198 }
199 
200 
201 void SCH_REFERENCE_LIST::GetRefsInUse( int aIndex, std::vector< int >& aIdList, int aMinRefId ) const
202 {
203  aIdList.clear();
204 
205  for( const SCH_REFERENCE& ref : flatList )
206  {
207  // Don't add new references to the list as we will reannotate those
208  if( flatList[aIndex].CompareRef( ref ) == 0 && ref.m_numRef >= aMinRefId && !ref.m_isNew )
209  aIdList.push_back( ref.m_numRef );
210  }
211 
212  sort( aIdList.begin(), aIdList.end() );
213 
214  // Ensure each reference number appears only once. If there are components with
215  // multiple parts per package the same number will be stored for each part.
216  std::vector< int >::iterator it = unique( aIdList.begin(), aIdList.end() );
217 
218  // Using the C++ unique algorithm only moves the duplicate entries to the end of
219  // of the array. This removes the duplicate entries from the array.
220  aIdList.resize( it - aIdList.begin() );
221 }
222 
223 
224 int SCH_REFERENCE_LIST::GetLastReference( int aIndex, int aMinValue ) const
225 {
226  int lastNumber = aMinValue;
227 
228  for( const SCH_REFERENCE& ref : flatList )
229  {
230  // search only for the current reference prefix:
231  if( flatList[aIndex].CompareRef( ref ) != 0 )
232  continue;
233 
234  // update max value for the current reference prefix
235  if( lastNumber < ref.m_numRef )
236  lastNumber = ref.m_numRef;
237  }
238 
239  return lastNumber;
240 }
241 
242 
243 std::vector<SYMBOL_INSTANCE_REFERENCE> SCH_REFERENCE_LIST::GetSymbolInstances() const
244 {
245  std::vector<SYMBOL_INSTANCE_REFERENCE> retval;
246 
247  for( const SCH_REFERENCE& ref : flatList )
248  {
249  SYMBOL_INSTANCE_REFERENCE instance;
250  instance.m_Path = ref.GetPath();
251  instance.m_Reference = ref.GetRef();
252  instance.m_Unit = ref.GetUnit();
253  instance.m_Value = ref.GetValue();
254  instance.m_Footprint = ref.GetFootprint();
255 
256  retval.push_back( instance );
257  }
258 
259  return retval;
260 }
261 
262 
263 int SCH_REFERENCE_LIST::CreateFirstFreeRefId( std::vector<int>& aIdList, int aFirstValue )
264 {
265  int expectedId = aFirstValue;
266 
267  // We search for expected Id a value >= aFirstValue.
268  // Skip existing Id < aFirstValue
269  unsigned ii = 0;
270 
271  for( ; ii < aIdList.size(); ii++ )
272  {
273  if( expectedId <= aIdList[ii] )
274  break;
275  }
276 
277  // Ids are sorted by increasing value, from aFirstValue
278  // So we search from aFirstValue the first not used value, i.e. the first hole in list.
279  for( ; ii < aIdList.size(); ii++ )
280  {
281  if( expectedId != aIdList[ii] ) // This id is not yet used.
282  {
283  // Insert this free Id, in order to keep list sorted
284  aIdList.insert( aIdList.begin() + ii, expectedId );
285  return expectedId;
286  }
287 
288  expectedId++;
289  }
290 
291  // All existing Id are tested, and all values are found in use.
292  // So Create a new one.
293  aIdList.push_back( expectedId );
294  return expectedId;
295 }
296 
297 
298 // A helper function to build a full reference string of a SCH_REFERENCE item
299 wxString buildFullReference( const SCH_REFERENCE& aItem, int aUnitNumber = -1 )
300 {
301  wxString fullref;
302  fullref = aItem.GetRef() + aItem.GetRefNumber();
303 
304  if( aUnitNumber < 0 )
305  fullref << ".." << aItem.GetUnit();
306  else
307  fullref << ".." << aUnitNumber;
308 
309  return fullref;
310 }
311 
313 {
314  SplitReferences();
315 
316  // All multi-unit symbols always locked to ensure consistent re-annotation
317  SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
318 
319  for( size_t i = 0; i < GetCount(); i++ )
320  {
321  SCH_REFERENCE& ref = flatList[i];
322  wxString refstr = ref.GetSymbol()->GetRef( &ref.GetSheetPath() );
323 
324  // Never lock unassigned references
325  if( refstr[refstr.Len() - 1] == '?' )
326  continue;
327 
328  lockedSymbols[refstr].AddItem( ref );
329 
330  ref.m_isNew = true; // We want to reannotate all references
331  }
332 
333  Annotate( false, 0, 0, lockedSymbols, aAdditionalReferences, true );
334 }
335 
336 void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
337  SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap,
338  const SCH_REFERENCE_LIST& aAdditionalRefs, bool aStartAtCurrent )
339 {
340  if ( flatList.size() == 0 )
341  return;
342 
343  size_t originalSize = GetCount();
344 
345  // For multi units components, store the list of already used full references.
346  // The algorithm tries to allocate the new reference to components having the same
347  // old reference.
348  // This algo works fine as long as the previous annotation has no duplicates.
349  // But when a hierarchy is reannotated with this option, the previous anotation can
350  // have duplicate references, and obviously we must fix these duplicate.
351  // therefore do not try to allocate a full reference more than once when trying
352  // to keep this order of multi units.
353  // inUseRefs keep trace of previously allocated references
354  std::unordered_set<wxString> inUseRefs;
355 
356  for( size_t i = 0; i < aAdditionalRefs.GetCount(); i++ )
357  {
358  SCH_REFERENCE additionalRef = aAdditionalRefs[i];
359  additionalRef.Split();
360 
361  // Add the additional reference to the multi-unit set if annotated
362  if( !additionalRef.m_isNew )
363  inUseRefs.insert( buildFullReference( additionalRef ) );
364 
365  // We don't want to reannotate the additional references even if not annotated
366  // so we change the m_isNew flag to be false after splitting
367  additionalRef.m_isNew = false;
368  AddItem( additionalRef ); //add to this container
369  }
370 
371  int LastReferenceNumber = 0;
372  int NumberOfUnits, Unit;
373 
374  /* calculate index of the first component with the same reference prefix
375  * than the current component. All components having the same reference
376  * prefix will receive a reference number with consecutive values:
377  * IC .. will be set to IC4, IC4, IC5 ...
378  */
379  unsigned first = 0;
380 
381  // calculate the last used number for this reference prefix:
382  int minRefId;
383 
384  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
385  if( aUseSheetNum )
386  minRefId = flatList[first].m_sheetNum * aSheetIntervalId + 1;
387  else
388  minRefId = aStartNumber + 1;
389 
390  // This is the list of all Id already in use for a given reference prefix.
391  // Will be refilled for each new reference prefix.
392  std::vector<int>idList;
393  GetRefsInUse( first, idList, minRefId );
394 
395  for( unsigned ii = 0; ii < flatList.size(); ii++ )
396  {
397  auto& ref_unit = flatList[ii];
398 
399  if( ref_unit.m_flag )
400  continue;
401 
402  // Check whether this component is in aLockedUnitMap.
403  SCH_REFERENCE_LIST* lockedList = NULL;
404  for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
405  {
406  unsigned n_refs = pair.second.GetCount();
407 
408  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
409  {
410  SCH_REFERENCE &thisRef = pair.second[thisRefI];
411 
412  if( thisRef.IsSameInstance( ref_unit ) )
413  {
414  lockedList = &pair.second;
415  break;
416  }
417  }
418  if( lockedList != NULL ) break;
419  }
420 
421  if( ( flatList[first].CompareRef( ref_unit ) != 0 )
422  || ( aUseSheetNum && ( flatList[first].m_sheetNum != ref_unit.m_sheetNum ) ) )
423  {
424  // New reference found: we need a new ref number for this reference
425  first = ii;
426 
427  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
428  if( aUseSheetNum )
429  minRefId = ref_unit.m_sheetNum * aSheetIntervalId + 1;
430  else
431  minRefId = aStartNumber + 1;
432 
433  GetRefsInUse( first, idList, minRefId );
434  }
435 
436  // Find references greater than current reference (unless not annotated)
437  if( aStartAtCurrent && ref_unit.m_numRef > 0 )
438  {
439  minRefId = ref_unit.m_numRef;
440  GetRefsInUse( first, idList, minRefId );
441  }
442 
443  // Annotation of one part per package components (trivial case).
444  if( ref_unit.GetLibPart()->GetUnitCount() <= 1 )
445  {
446  if( ref_unit.m_isNew )
447  {
448  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
449  ref_unit.m_numRef = LastReferenceNumber;
450  }
451 
452  ref_unit.m_flag = 1;
453  ref_unit.m_isNew = false;
454  continue;
455  }
456 
457  // Annotation of multi-unit parts ( n units per part ) (complex case)
458  NumberOfUnits = ref_unit.GetLibPart()->GetUnitCount();
459 
460  if( ref_unit.m_isNew )
461  {
462  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
463  ref_unit.m_numRef = LastReferenceNumber;
464 
465  ref_unit.m_flag = 1;
466  }
467 
468  // If this component is in aLockedUnitMap, copy the annotation to all
469  // components that are not it
470  if( lockedList != NULL )
471  {
472  unsigned n_refs = lockedList->GetCount();
473 
474  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
475  {
476  SCH_REFERENCE &thisRef = (*lockedList)[thisRefI];
477 
478  if( thisRef.IsSameInstance( ref_unit ) )
479  {
480  // This is the component we're currently annotating. Hold the unit!
481  ref_unit.m_unit = thisRef.m_unit;
482  // lock this new full reference
483  inUseRefs.insert( buildFullReference( ref_unit ) );
484  }
485 
486  if( thisRef.CompareValue( ref_unit ) != 0 )
487  continue;
488 
489  if( thisRef.CompareLibName( ref_unit ) != 0 )
490  continue;
491 
492  // Find the matching component
493  for( unsigned jj = ii + 1; jj < flatList.size(); jj++ )
494  {
495  if( ! thisRef.IsSameInstance( flatList[jj] ) )
496  continue;
497 
498  wxString ref_candidate = buildFullReference( ref_unit, thisRef.m_unit );
499 
500  // propagate the new reference and unit selection to the "old" component,
501  // if this new full reference is not already used (can happens when initial
502  // multiunits components have duplicate references)
503  if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
504  {
505  flatList[jj].m_numRef = ref_unit.m_numRef;
506  flatList[jj].m_isNew = false;
507  flatList[jj].m_flag = 1;
508  // lock this new full reference
509  inUseRefs.insert( ref_candidate );
510  break;
511  }
512  }
513  }
514  }
515  else
516  {
517  /* search for others units of this component.
518  * we search for others parts that have the same value and the same
519  * reference prefix (ref without ref number)
520  */
521  for( Unit = 1; Unit <= NumberOfUnits; Unit++ )
522  {
523  if( ref_unit.m_unit == Unit )
524  continue;
525 
526  int found = FindUnit( ii, Unit );
527 
528  if( found >= 0 )
529  continue; // this unit exists for this reference (unit already annotated)
530 
531  // Search a component to annotate ( same prefix, same value, not annotated)
532  for( unsigned jj = ii + 1; jj < flatList.size(); jj++ )
533  {
534  auto& cmp_unit = flatList[jj];
535 
536  if( cmp_unit.m_flag ) // already tested
537  continue;
538 
539  if( cmp_unit.CompareRef( ref_unit ) != 0 )
540  continue;
541 
542  if( cmp_unit.CompareValue( ref_unit ) != 0 )
543  continue;
544 
545  if( cmp_unit.CompareLibName( ref_unit ) != 0 )
546  continue;
547 
548  if( aUseSheetNum &&
549  cmp_unit.GetSheetPath().Cmp( ref_unit.GetSheetPath() ) != 0 )
550  continue;
551 
552  if( !cmp_unit.m_isNew )
553  continue;
554 
555  // Component without reference number found, annotate it if possible
556  if( cmp_unit.m_unit == Unit )
557  {
558  cmp_unit.m_numRef = ref_unit.m_numRef;
559  cmp_unit.m_flag = 1;
560  cmp_unit.m_isNew = false;
561  break;
562  }
563  }
564  }
565  }
566  }
567 
568  // Remove aAdditionalRefs references
569  for( size_t i = originalSize; i < ( aAdditionalRefs.GetCount() + originalSize ); i++ )
570  RemoveItem( originalSize );
571 
572  wxASSERT( originalSize == GetCount() ); // Make sure we didn't make a mistake
573 }
574 
576 {
577  int error = 0;
578  wxString tmp;
579  wxString msg;
580 
582 
583  // Spiit reference designators into name (prefix) and number: IC1 becomes IC, and 1.
584  SplitReferences();
585 
586  // count not yet annotated items or annotation error.
587  for( unsigned ii = 0; ii < flatList.size(); ii++ )
588  {
589  msg.Empty();
590  tmp.Empty();
591 
592  if( flatList[ii].m_isNew ) // Not yet annotated
593  {
594  if( flatList[ii].m_numRef >= 0 )
595  tmp << flatList[ii].m_numRef;
596  else
597  tmp = wxT( "?" );
598 
599 
600  if( ( flatList[ii].m_unit > 0 ) && ( flatList[ii].m_unit < 0x7FFFFFFF ) )
601  {
602  msg.Printf( _( "Item not annotated: %s%s (unit %d)\n" ),
603  flatList[ii].GetRef(),
604  tmp,
605  flatList[ii].m_unit );
606  }
607  else
608  {
609  msg.Printf( _( "Item not annotated: %s%s\n" ),
610  flatList[ii].GetRef(),
611  tmp );
612  }
613 
614  aHandler( ERCE_UNANNOTATED, msg, &flatList[ii], nullptr );
615  error++;
616  break;
617  }
618 
619  // Error if unit number selected does not exist (greater than the number of units in
620  // the component). This can happen if a component has changed in a library after a
621  // previous annotation.
622  if( std::max( flatList[ii].GetLibPart()->GetUnitCount(), 1 ) < flatList[ii].m_unit )
623  {
624  if( flatList[ii].m_numRef >= 0 )
625  tmp << flatList[ii].m_numRef;
626  else
627  tmp = wxT( "?" );
628 
629  msg.Printf( _( "Error: symbol %s%s%s (unit %d) exceeds units defined (%d)\n" ),
630  flatList[ii].GetRef(),
631  tmp,
632  LIB_PART::SubReference( flatList[ii].m_unit ),
633  flatList[ii].m_unit,
634  flatList[ii].GetLibPart()->GetUnitCount() );
635 
636  aHandler( ERCE_EXTRA_UNITS, msg, &flatList[ii], nullptr );
637  error++;
638  break;
639  }
640  }
641 
642  // count the duplicated elements (if all are annotated)
643  int imax = flatList.size() - 1;
644 
645  for( int ii = 0; ii < imax; ii++ )
646  {
647  msg.Empty();
648  tmp.Empty();
649 
650  if( ( flatList[ii].CompareRef( flatList[ii + 1] ) != 0 )
651  || ( flatList[ii].m_numRef != flatList[ ii + 1].m_numRef ) )
652  {
653  continue;
654  }
655 
656  // Same reference found. If same unit, error!
657  if( flatList[ii].m_unit == flatList[ ii + 1].m_unit )
658  {
659  if( flatList[ii].m_numRef >= 0 )
660  tmp << flatList[ii].m_numRef;
661  else
662  tmp = wxT( "?" );
663 
664  if( ( flatList[ii].m_unit > 0 ) && ( flatList[ii].m_unit < 0x7FFFFFFF ) )
665  {
666  msg.Printf( _( "Duplicate items %s%s%s\n" ),
667  flatList[ii].GetRef(),
668  tmp,
669  LIB_PART::SubReference( flatList[ii].m_unit ) );
670  }
671  else
672  {
673  msg.Printf( _( "Duplicate items %s%s\n" ),
674  flatList[ii].GetRef(),
675  tmp );
676  }
677 
678  aHandler( ERCE_DUPLICATE_REFERENCE, msg, &flatList[ii], &flatList[ii+1] );
679  error++;
680  continue;
681  }
682 
683  /* Test error if units are different but number of parts per package
684  * too high (ex U3 ( 1 part) and we find U3B this is an error) */
685  if( flatList[ii].GetLibPart()->GetUnitCount()
686  != flatList[ ii + 1].GetLibPart()->GetUnitCount() )
687  {
688  if( flatList[ii].m_numRef >= 0 )
689  tmp << flatList[ii].m_numRef;
690  else
691  tmp = wxT( "?" );
692 
693  if( ( flatList[ii].m_unit > 0 )
694  && ( flatList[ii].m_unit < 0x7FFFFFFF ) )
695  {
696  msg.Printf( _( "Duplicate items %s%s%s\n" ),
697  flatList[ii].GetRef(),
698  tmp,
699  LIB_PART::SubReference( flatList[ii].m_unit ) );
700  }
701  else
702  {
703  msg.Printf( _( "Duplicate items %s%s\n" ),
704  flatList[ii].GetRef(),
705  tmp );
706  }
707 
708  aHandler( ERCE_DUPLICATE_REFERENCE, msg, &flatList[ii], &flatList[ii+1] );
709  error++;
710  }
711 
712  // Error if values are different between units, for the same reference
713  int next = ii + 1;
714 
715  if( flatList[ii].CompareValue( flatList[next] ) != 0 )
716  {
717  msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
718  flatList[ii].GetRef(),
719  flatList[ii].m_numRef,
720  LIB_PART::SubReference( flatList[ii].m_unit ),
721  flatList[ii].m_value,
722  flatList[next].GetRef(),
723  flatList[next].m_numRef,
725  flatList[next].m_value );
726 
727  aHandler( ERCE_DIFFERENT_UNIT_VALUE, msg, &flatList[ii], &flatList[ii+1] );
728  error++;
729  }
730  }
731 
732  return error;
733 }
734 
735 
737  const SCH_SHEET_PATH& aSheetPath )
738 {
739  wxASSERT( aSymbol != NULL );
740 
741  m_rootSymbol = aSymbol;
742  m_libPart = aLibPart; // Warning: can be nullptr for orphan components
743  // (i.e. with a symbol library not found)
744  m_unit = aSymbol->GetUnitSelection( &aSheetPath );
745  m_footprint = aSymbol->GetFootprint( &aSheetPath, true );
746  m_sheetPath = aSheetPath;
747  m_isNew = false;
748  m_flag = 0;
749  m_symbolUuid = aSymbol->m_Uuid;
750  m_symbolPos = aSymbol->GetPosition();
751  m_sheetNum = 0;
752 
753  if( aSymbol->GetRef( &aSheetPath ).IsEmpty() )
754  aSymbol->SetRef( &aSheetPath, wxT( "DefRef?" ) );
755 
756  wxString ref = aSymbol->GetRef( &aSheetPath );
757  SetRef( ref );
758 
759  m_numRef = -1;
760 
761  if( aSymbol->GetValue( &aSheetPath, false ).IsEmpty() )
762  aSymbol->SetValue( &aSheetPath, wxT( "~" ) );
763 
764  m_value = aSymbol->GetValue( &aSheetPath, false );
765 }
766 
767 
769 {
770  if( m_numRef < 0 )
771  m_ref += '?';
772  else
773  m_ref = TO_UTF8( GetRef() << GetRefNumber() );
774 
778 }
779 
780 
782 {
783  std::string refText = GetRefStr();
784 
785  m_numRef = -1;
786 
787  int ll = refText.length() - 1;
788 
789  if( refText[ll] == '?' )
790  {
791  m_isNew = true;
792 
793  refText.erase( ll ); // delete last char
794 
795  SetRefStr( refText );
796  }
797  else if( isdigit( refText[ll] ) == 0 )
798  {
799  m_isNew = true;
800  }
801  else
802  {
803  while( ll >= 0 )
804  {
805  if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) )
806  ll--;
807  else
808  {
809  if( isdigit( refText[ll + 1] ) )
810  {
811  // null terminated C string into cp
812  const char* cp = refText.c_str() + ll + 1;
813 
814  m_numRef = atoi( cp );
815  }
816 
817  refText.erase( ll+1 ); // delete from ll+1 to end
818  break;
819  }
820  }
821 
822  SetRefStr( refText );
823  }
824 }
825 
826 
827 wxString SCH_REFERENCE_LIST::Shorthand( std::vector<SCH_REFERENCE> aList )
828 {
829  wxString retVal;
830  size_t i = 0;
831 
832  while( i < aList.size() )
833  {
834  wxString ref = aList[ i ].GetRef();
835  int numRef = aList[ i ].m_numRef;
836 
837  size_t range = 1;
838 
839  while( i + range < aList.size()
840  && aList[ i + range ].GetRef() == ref
841  && aList[ i + range ].m_numRef == int( numRef + range ) )
842  {
843  range++;
844  }
845 
846  if( !retVal.IsEmpty() )
847  retVal << wxT( ", " );
848 
849  if( range == 1 )
850  {
851  retVal << ref << aList[ i ].GetRefNumber();
852  }
853  else if( range == 2 )
854  {
855  retVal << ref << aList[ i ].GetRefNumber();
856  retVal << wxT( ", " );
857  retVal << ref << aList[ i + 1 ].GetRefNumber();
858  }
859  else
860  {
861  retVal << ref << aList[ i ].GetRefNumber();
862  retVal << wxT( "-" );
863  retVal << ref << aList[ i + ( range - 1 ) ].GetRefNumber();
864  }
865 
866  i+= range;
867  }
868 
869  return retVal;
870 }
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.
const SCH_SHEET_PATH & GetSheetPath() const
void ReannotateDuplicates(const SCH_REFERENCE_LIST &aAdditionalReferences)
Replace any duplicate reference designators with the next available number after the present number.
wxPoint m_symbolPos
The physical position of the symbol in schematic used to annotate by X or Y position.
int m_sheetNum
The sheet number for the reference.
Collection of utility functions for component reference designators (refdes)
std::vector< SYMBOL_INSTANCE_REFERENCE > GetSymbolInstances() const
static wxString Shorthand(std::vector< SCH_REFERENCE > aList)
Return a shorthand string representing all the references in the list.
void AddItem(const SCH_REFERENCE &aItem)
int GetUnit() const
wxString GetRefNumber() const
int GetLastReference(int aIndex, int aMinValue) const
Return the last used (greatest) reference number in the reference list for the prefix used by the sym...
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
Return the instance-specific footprint assignment for the given sheet path.
Definition: sch_symbol.cpp:614
int FindUnit(size_t aIndex, int aUnit) const
Search the sorted list of symbols for a another symbol with the same reference and a given part unit.
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 per package.
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
Return the instance-specific value for the given sheet path.
Definition: sch_symbol.cpp:563
#define NULL
void GetRefsInUse(int aIndex, std::vector< int > &aIdList, int aMinRefId) const
Add all the reference designator numbers greater than aMinRefId to aIdList skipping the reference at ...
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
A simple container for schematic symbol instance information.
size_t GetCount() const
void SetUnit(int aUnit)
Change the unit number to aUnit.
Definition: sch_symbol.cpp:321
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
bool Contains(const SCH_REFERENCE &aItem)
Return true if aItem exists in this list.
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.
SCH_COMPONENT * GetSymbol() const
const KIID m_Uuid
Definition: eda_item.h:525
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:471
int CheckAnnotation(ANNOTATION_ERROR_HANDLER aErrorHandler)
Check for annotations errors.
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
Definition: sch_symbol.cpp:537
void Annotate(bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent=false)
Set the reference designators in the list that have not been annotated.
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:78
wxPoint GetPosition() const override
Definition: sch_symbol.h:641
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
void SetValue(const SCH_SHEET_PATH *sheet, const wxString &aValue)
Definition: sch_symbol.cpp:584
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
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:521
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:431