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 <[email protected]>
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 <string_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 = StrNumCmp( item1.GetRef(), item2.GetRef(), false );
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,
202  int aMinRefId ) const
203 {
204  aIdList.clear();
205 
206  for( const SCH_REFERENCE& ref : flatList )
207  {
208  // Don't add new references to the list as we will reannotate those
209  if( flatList[aIndex].CompareRef( ref ) == 0 && ref.m_numRef >= aMinRefId && !ref.m_isNew )
210  aIdList.push_back( ref.m_numRef );
211  }
212 
213  sort( aIdList.begin(), aIdList.end() );
214 
215  // Ensure each reference number appears only once. If there are symbols with
216  // multiple parts per package the same number will be stored for each part.
217  std::vector< int >::iterator it = unique( aIdList.begin(), aIdList.end() );
218 
219  // Using the C++ unique algorithm only moves the duplicate entries to the end of
220  // of the array. This removes the duplicate entries from the array.
221  aIdList.resize( it - aIdList.begin() );
222 }
223 
224 
225 int SCH_REFERENCE_LIST::GetLastReference( int aIndex, int aMinValue ) const
226 {
227  int lastNumber = aMinValue;
228 
229  for( const SCH_REFERENCE& ref : flatList )
230  {
231  // search only for the current reference prefix:
232  if( flatList[aIndex].CompareRef( ref ) != 0 )
233  continue;
234 
235  // update max value for the current reference prefix
236  if( lastNumber < ref.m_numRef )
237  lastNumber = ref.m_numRef;
238  }
239 
240  return lastNumber;
241 }
242 
243 
244 std::vector<SYMBOL_INSTANCE_REFERENCE> SCH_REFERENCE_LIST::GetSymbolInstances() const
245 {
246  std::vector<SYMBOL_INSTANCE_REFERENCE> retval;
247 
248  for( const SCH_REFERENCE& ref : flatList )
249  {
250  SYMBOL_INSTANCE_REFERENCE instance;
251  instance.m_Path = ref.GetPath();
252  instance.m_Reference = ref.GetRef();
253  instance.m_Unit = ref.GetUnit();
254  instance.m_Value = ref.GetValue();
255  instance.m_Footprint = ref.GetFootprint();
256 
257  retval.push_back( instance );
258  }
259 
260  return retval;
261 }
262 
263 
264 int SCH_REFERENCE_LIST::CreateFirstFreeRefId( std::vector<int>& aIdList, int aFirstValue )
265 {
266  int expectedId = aFirstValue;
267 
268  // We search for expected Id a value >= aFirstValue.
269  // Skip existing Id < aFirstValue
270  unsigned ii = 0;
271 
272  for( ; ii < aIdList.size(); ii++ )
273  {
274  if( expectedId <= aIdList[ii] )
275  break;
276  }
277 
278  // Ids are sorted by increasing value, from aFirstValue
279  // So we search from aFirstValue the first not used value, i.e. the first hole in list.
280  for( ; ii < aIdList.size(); ii++ )
281  {
282  if( expectedId != aIdList[ii] ) // This id is not yet used.
283  {
284  // Insert this free Id, in order to keep list sorted
285  aIdList.insert( aIdList.begin() + ii, expectedId );
286  return expectedId;
287  }
288 
289  expectedId++;
290  }
291 
292  // All existing Id are tested, and all values are found in use.
293  // So Create a new one.
294  aIdList.push_back( expectedId );
295  return expectedId;
296 }
297 
298 
299 // A helper function to build a full reference string of a SCH_REFERENCE item
300 wxString buildFullReference( const SCH_REFERENCE& aItem, int aUnitNumber = -1 )
301 {
302  wxString fullref;
303  fullref = aItem.GetRef() + aItem.GetRefNumber();
304 
305  if( aUnitNumber < 0 )
306  fullref << ".." << aItem.GetUnit();
307  else
308  fullref << ".." << aUnitNumber;
309 
310  return fullref;
311 }
312 
313 
315 {
316  SplitReferences();
317 
318  // All multi-unit symbols always locked to ensure consistent re-annotation
319  SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
320 
321  for( size_t i = 0; i < GetCount(); i++ )
322  {
323  SCH_REFERENCE& ref = flatList[i];
324  wxString refstr = ref.GetSymbol()->GetRef( &ref.GetSheetPath() );
325 
326  // Never lock unassigned references
327  if( refstr[refstr.Len() - 1] == '?' )
328  continue;
329 
330  lockedSymbols[refstr].AddItem( ref );
331 
332  ref.m_isNew = true; // We want to reannotate all references
333  }
334 
335  Annotate( false, 0, 0, lockedSymbols, aAdditionalReferences, true );
336 }
337 
338 
339 void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
340  SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap,
341  const SCH_REFERENCE_LIST& aAdditionalRefs, bool aStartAtCurrent )
342 {
343  if ( flatList.size() == 0 )
344  return;
345 
346  size_t originalSize = GetCount();
347 
348  // For multi units symbols, store the list of already used full references.
349  // The algorithm tries to allocate the new reference to symbols having the same
350  // old reference.
351  // This algo works fine as long as the previous annotation has no duplicates.
352  // But when a hierarchy is reannotated with this option, the previous annotation can
353  // have duplicate references, and obviously we must fix these duplicate.
354  // therefore do not try to allocate a full reference more than once when trying
355  // to keep this order of multi units.
356  // inUseRefs keep trace of previously allocated references
357  std::unordered_set<wxString> inUseRefs;
358 
359  for( size_t i = 0; i < aAdditionalRefs.GetCount(); i++ )
360  {
361  SCH_REFERENCE additionalRef = aAdditionalRefs[i];
362  additionalRef.Split();
363 
364  // Add the additional reference to the multi-unit set if annotated
365  if( !additionalRef.m_isNew )
366  inUseRefs.insert( buildFullReference( additionalRef ) );
367 
368  // We don't want to reannotate the additional references even if not annotated
369  // so we change the m_isNew flag to be false after splitting
370  additionalRef.m_isNew = false;
371  AddItem( additionalRef ); //add to this container
372  }
373 
374  int LastReferenceNumber = 0;
375  int NumberOfUnits, Unit;
376 
377  /* calculate index of the first symbol with the same reference prefix
378  * than the current symbol. All symbols having the same reference
379  * prefix will receive a reference number with consecutive values:
380  * IC .. will be set to IC4, IC4, IC5 ...
381  */
382  unsigned first = 0;
383 
384  // calculate the last used number for this reference prefix:
385  int minRefId;
386 
387  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
388  if( aUseSheetNum )
389  minRefId = flatList[first].m_sheetNum * aSheetIntervalId + 1;
390  else
391  minRefId = aStartNumber + 1;
392 
393  // This is the list of all Id already in use for a given reference prefix.
394  // Will be refilled for each new reference prefix.
395  std::vector<int>idList;
396  GetRefsInUse( first, idList, minRefId );
397 
398  for( unsigned ii = 0; ii < flatList.size(); ii++ )
399  {
400  auto& ref_unit = flatList[ii];
401 
402  if( ref_unit.m_flag )
403  continue;
404 
405  // Check whether this symbol is in aLockedUnitMap.
406  SCH_REFERENCE_LIST* lockedList = nullptr;
407 
408  for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
409  {
410  unsigned n_refs = pair.second.GetCount();
411 
412  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
413  {
414  SCH_REFERENCE &thisRef = pair.second[thisRefI];
415 
416  if( thisRef.IsSameInstance( ref_unit ) )
417  {
418  lockedList = &pair.second;
419  break;
420  }
421  }
422 
423  if( lockedList != nullptr )
424  break;
425  }
426 
427  if( ( flatList[first].CompareRef( ref_unit ) != 0 )
428  || ( aUseSheetNum && ( flatList[first].m_sheetNum != ref_unit.m_sheetNum ) ) )
429  {
430  // New reference found: we need a new ref number for this reference
431  first = ii;
432 
433  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
434  if( aUseSheetNum )
435  minRefId = ref_unit.m_sheetNum * aSheetIntervalId + 1;
436  else
437  minRefId = aStartNumber + 1;
438 
439  GetRefsInUse( first, idList, minRefId );
440  }
441 
442  // Find references greater than current reference (unless not annotated)
443  if( aStartAtCurrent && ref_unit.m_numRef > 0 )
444  {
445  minRefId = ref_unit.m_numRef;
446  GetRefsInUse( first, idList, minRefId );
447  }
448 
449  // Annotation of one part per package symbols (trivial case).
450  if( ref_unit.GetLibPart()->GetUnitCount() <= 1 )
451  {
452  if( ref_unit.m_isNew )
453  {
454  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
455  ref_unit.m_numRef = LastReferenceNumber;
456  }
457 
458  ref_unit.m_flag = 1;
459  ref_unit.m_isNew = false;
460  continue;
461  }
462 
463  // Annotation of multi-unit parts ( n units per part ) (complex case)
464  NumberOfUnits = ref_unit.GetLibPart()->GetUnitCount();
465 
466  if( ref_unit.m_isNew )
467  {
468  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
469  ref_unit.m_numRef = LastReferenceNumber;
470 
471  ref_unit.m_flag = 1;
472  }
473 
474  // If this symbol is in aLockedUnitMap, copy the annotation to all
475  // symbols that are not it
476  if( lockedList != nullptr )
477  {
478  unsigned n_refs = lockedList->GetCount();
479 
480  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
481  {
482  SCH_REFERENCE &thisRef = (*lockedList)[thisRefI];
483 
484  if( thisRef.IsSameInstance( ref_unit ) )
485  {
486  // This is the symbol we're currently annotating. Hold the unit!
487  ref_unit.m_unit = thisRef.m_unit;
488  // lock this new full reference
489  inUseRefs.insert( buildFullReference( ref_unit ) );
490  }
491 
492  if( thisRef.CompareValue( ref_unit ) != 0 )
493  continue;
494 
495  if( thisRef.CompareLibName( ref_unit ) != 0 )
496  continue;
497 
498  // Find the matching symbol
499  for( unsigned jj = ii + 1; jj < flatList.size(); jj++ )
500  {
501  if( ! thisRef.IsSameInstance( flatList[jj] ) )
502  continue;
503 
504  wxString ref_candidate = buildFullReference( ref_unit, thisRef.m_unit );
505 
506  // propagate the new reference and unit selection to the "old" symbol,
507  // if this new full reference is not already used (can happens when initial
508  // multiunits symbols have duplicate references)
509  if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
510  {
511  flatList[jj].m_numRef = ref_unit.m_numRef;
512  flatList[jj].m_isNew = false;
513  flatList[jj].m_flag = 1;
514  // lock this new full reference
515  inUseRefs.insert( ref_candidate );
516  break;
517  }
518  }
519  }
520  }
521  else
522  {
523  /* search for others units of this symbol.
524  * we search for others parts that have the same value and the same
525  * reference prefix (ref without ref number)
526  */
527  for( Unit = 1; Unit <= NumberOfUnits; Unit++ )
528  {
529  if( ref_unit.m_unit == Unit )
530  continue;
531 
532  int found = FindUnit( ii, Unit );
533 
534  if( found >= 0 )
535  continue; // this unit exists for this reference (unit already annotated)
536 
537  // Search a symbol to annotate ( same prefix, same value, not annotated)
538  for( unsigned jj = ii + 1; jj < flatList.size(); jj++ )
539  {
540  auto& cmp_unit = flatList[jj];
541 
542  if( cmp_unit.m_flag ) // already tested
543  continue;
544 
545  if( cmp_unit.CompareRef( ref_unit ) != 0 )
546  continue;
547 
548  if( cmp_unit.CompareValue( ref_unit ) != 0 )
549  continue;
550 
551  if( cmp_unit.CompareLibName( ref_unit ) != 0 )
552  continue;
553 
554  if( aUseSheetNum &&
555  cmp_unit.GetSheetPath().Cmp( ref_unit.GetSheetPath() ) != 0 )
556  continue;
557 
558  if( !cmp_unit.m_isNew )
559  continue;
560 
561  // Symbol without reference number found, annotate it if possible.
562  if( cmp_unit.m_unit == Unit )
563  {
564  cmp_unit.m_numRef = ref_unit.m_numRef;
565  cmp_unit.m_flag = 1;
566  cmp_unit.m_isNew = false;
567  break;
568  }
569  }
570  }
571  }
572  }
573 
574  // Remove aAdditionalRefs references
575  for( size_t i = originalSize; i < ( aAdditionalRefs.GetCount() + originalSize ); i++ )
576  RemoveItem( originalSize );
577 
578  wxASSERT( originalSize == GetCount() ); // Make sure we didn't make a mistake
579 }
580 
581 
583 {
584  int error = 0;
585  wxString tmp;
586  wxString msg;
587 
589 
590  // Split reference designators into name (prefix) and number: IC1 becomes IC, and 1.
591  SplitReferences();
592 
593  // count not yet annotated items or annotation error.
594  for( unsigned ii = 0; ii < flatList.size(); ii++ )
595  {
596  msg.Empty();
597  tmp.Empty();
598 
599  if( flatList[ii].m_isNew ) // Not yet annotated
600  {
601  if( flatList[ii].m_numRef >= 0 )
602  tmp << flatList[ii].m_numRef;
603  else
604  tmp = wxT( "?" );
605 
606  if( ( flatList[ii].m_unit > 0 ) && ( flatList[ii].m_unit < 0x7FFFFFFF ) )
607  {
608  msg.Printf( _( "Item not annotated: %s%s (unit %d)\n" ),
609  flatList[ii].GetRef(),
610  tmp,
611  flatList[ii].m_unit );
612  }
613  else
614  {
615  msg.Printf( _( "Item not annotated: %s%s\n" ), flatList[ii].GetRef(), tmp );
616  }
617 
618  aHandler( ERCE_UNANNOTATED, msg, &flatList[ii], nullptr );
619  error++;
620  break;
621  }
622 
623  // Error if unit number selected does not exist (greater than the number of units in
624  // the symbol). This can happen if a symbol has changed in a library after a
625  // previous annotation.
626  if( std::max( flatList[ii].GetLibPart()->GetUnitCount(), 1 ) < flatList[ii].m_unit )
627  {
628  if( flatList[ii].m_numRef >= 0 )
629  tmp << flatList[ii].m_numRef;
630  else
631  tmp = wxT( "?" );
632 
633  msg.Printf( _( "Error: symbol %s%s%s (unit %d) exceeds units defined (%d)\n" ),
634  flatList[ii].GetRef(),
635  tmp,
636  LIB_SYMBOL::SubReference( flatList[ii].m_unit ),
637  flatList[ii].m_unit,
638  flatList[ii].GetLibPart()->GetUnitCount() );
639 
640  aHandler( ERCE_EXTRA_UNITS, msg, &flatList[ii], nullptr );
641  error++;
642  break;
643  }
644  }
645 
646  // count the duplicated elements (if all are annotated)
647  int imax = flatList.size() - 1;
648 
649  for( int ii = 0; ii < imax; ii++ )
650  {
651  msg.Empty();
652  tmp.Empty();
653 
654  if( ( flatList[ii].CompareRef( flatList[ii + 1] ) != 0 )
655  || ( flatList[ii].m_numRef != flatList[ ii + 1].m_numRef ) )
656  {
657  continue;
658  }
659 
660  // Same reference found. If same unit, error!
661  if( flatList[ii].m_unit == flatList[ ii + 1].m_unit )
662  {
663  if( flatList[ii].m_numRef >= 0 )
664  tmp << flatList[ii].m_numRef;
665  else
666  tmp = wxT( "?" );
667 
668  if( ( flatList[ii].m_unit > 0 ) && ( flatList[ii].m_unit < 0x7FFFFFFF ) )
669  {
670  msg.Printf( _( "Duplicate items %s%s%s\n" ),
671  flatList[ii].GetRef(),
672  tmp,
673  LIB_SYMBOL::SubReference( flatList[ii].m_unit ) );
674  }
675  else
676  {
677  msg.Printf( _( "Duplicate items %s%s\n" ), flatList[ii].GetRef(), tmp );
678  }
679 
680  aHandler( ERCE_DUPLICATE_REFERENCE, msg, &flatList[ii], &flatList[ii+1] );
681  error++;
682  continue;
683  }
684 
685  /* Test error if units are different but number of parts per package
686  * too high (ex U3 ( 1 part) and we find U3B this is an error) */
687  if( flatList[ii].GetLibPart()->GetUnitCount()
688  != flatList[ ii + 1].GetLibPart()->GetUnitCount() )
689  {
690  if( flatList[ii].m_numRef >= 0 )
691  tmp << flatList[ii].m_numRef;
692  else
693  tmp = wxT( "?" );
694 
695  if( ( flatList[ii].m_unit > 0 )
696  && ( flatList[ii].m_unit < 0x7FFFFFFF ) )
697  {
698  msg.Printf( _( "Duplicate items %s%s%s\n" ),
699  flatList[ii].GetRef(),
700  tmp,
701  LIB_SYMBOL::SubReference( flatList[ii].m_unit ) );
702  }
703  else
704  {
705  msg.Printf( _( "Duplicate items %s%s\n" ), flatList[ii].GetRef(), 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_SYMBOL::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 != nullptr );
740 
741  m_rootSymbol = aSymbol;
742  m_libPart = aLibSymbol; // Warning: can be nullptr for orphan symbols
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 SetUnit(int aUnit)
Change the unit number to aUnit.
Definition: sch_symbol.cpp:331
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.
LIB_SYMBOL * m_libPart
The source symbol from a library.
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.
void SetValue(const SCH_SHEET_PATH *sheet, const wxString &aValue)
Definition: sch_symbol.cpp:594
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
static wxString SubReference(int aUnit, bool aAddSeparator=true)
Definition: lib_symbol.cpp:444
SCH_SYMBOL * GetSymbol() const
wxString GetRefNumber() const
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:441
Define a library symbol object.
Definition: lib_symbol.h:96
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
Definition: sch_symbol.cpp:547
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
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 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
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.
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:531
wxString m_footprint
The footprint assigned.
void Annotate()
Update the annotation of the symbol according the current object state.
KIID m_symbolUuid
UUID of the symbol.
A simple container for schematic symbol instance information.
size_t GetCount() const
#define _(s)
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.
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:573
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:475
int CompareRef(const SCH_REFERENCE &item) const
UTF8 m_ref
Symbol reference prefix, without number (for IC1, this is IC) )
int CheckAnnotation(ANNOTATION_ERROR_HANDLER aErrorHandler)
Check for annotations errors.
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.
Schematic symbol object.
Definition: sch_symbol.h:78
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.
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.
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:481
bool IsSameInstance(const SCH_REFERENCE &other) const
Return whether this reference refers to the same symbol instance (symbol and sheet) as another.
wxPoint GetPosition() const override
Definition: sch_symbol.h:644
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)
std::vector< SCH_REFERENCE > flatList
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:624
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
Symbol has more units than are defined.
Definition: erc_settings.h:69
SCH_SYMBOL * m_rootSymbol
The symbol associated the reference object.
int Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare if this is the same sheet path as aSheetPathToTest.
A helper to define a symbol's reference designator in a schematic.
static bool sortByXPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)