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  componentFlatList[ii].GetRef(),
556  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  componentFlatList[ii].GetRef(),
584  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; 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  componentFlatList[ii].GetRef(),
622  tmp,
623  componentFlatList[ii].m_Unit );
624  }
625  else
626  {
627  msg.Printf( _( "Multiple item %s%s\n" ),
628  componentFlatList[ii].GetRef(),
629  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  componentFlatList[ii].GetRef(),
673  componentFlatList[ii].m_NumRef,
675  componentFlatList[ii].m_Value->GetText(),
676  componentFlatList[next].GetRef(),
677  componentFlatList[next].m_NumRef,
679  componentFlatList[next].m_Value->GetText() );
680 
681  aReporter.Report( msg, REPORTER::RPT_ERROR );
682  error++;
683  }
684  }
685 
686  // count the duplicated time stamps
687  SortByTimeStamp();
688 
689  for( int ii = 0; ii < imax; ii++ )
690  {
691  if( ( componentFlatList[ii].m_TimeStamp != componentFlatList[ii + 1].m_TimeStamp )
692  || ( componentFlatList[ii].GetSheetPath() != componentFlatList[ii + 1].GetSheetPath() ) )
693  continue;
694 
695  // Same time stamp found.
696  wxString full_path;
697 
698  full_path.Printf( wxT( "%s%8.8X" ),
699  GetChars( componentFlatList[ii].GetSheetPath().Path() ),
700  componentFlatList[ii].m_TimeStamp );
701 
702  msg.Printf( _( "Duplicate time stamp (%s) for %s%d and %s%d" ),
703  full_path,
704  componentFlatList[ii].GetRef(),
705  componentFlatList[ii].m_NumRef,
706  componentFlatList[ii + 1].GetRef(),
707  componentFlatList[ii + 1].m_NumRef );
708 
709  aReporter.Report( msg, REPORTER::RPT_WARNING );
710  error++;
711  }
712 
713  return error;
714 }
715 
716 
718  SCH_SHEET_PATH& aSheetPath )
719 {
720  wxASSERT( aComponent != NULL );
721 
722  m_RootCmp = aComponent;
723  m_Entry = aLibPart; // Warning: can be nullptr for orphan components
724  // (i.e. with a symbol library not found)
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 
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  size_t i = 0;
819 
820  while( i < aList.size() )
821  {
822  wxString ref = aList[ i ].GetRef();
823  int numRef = aList[ i ].m_NumRef;
824 
825  size_t range = 1;
826 
827  while( i + range < aList.size()
828  && aList[ i + range ].GetRef() == ref
829  && aList[ i + range ].m_NumRef == int( numRef + range ) )
830  {
831  range++;
832  }
833 
834  if( !retVal.IsEmpty() )
835  retVal << wxT( ", " );
836 
837  if( range == 1 )
838  {
839  retVal << ref << aList[ i ].GetRefNumber();
840  }
841  else if( range == 2 )
842  {
843  retVal << ref << aList[ i ].GetRefNumber();
844  retVal << wxT( ", " );
845  retVal << ref << aList[ i + 1 ].GetRefNumber();
846  }
847  else
848  {
849  retVal << ref << aList[ i ].GetRefNumber();
850  retVal << wxT( "-" );
851  retVal << ref << aList[ i + ( range - 1 ) ].GetRefNumber();
852  }
853 
854  i+= range;
855  }
856 
857  return retVal;
858 }
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.
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...
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)...
UTF8 m_Ref
Component reference prefix, without number (for IC1, this is IC) )
int m_NumRef
The numeric part of the reference designator.
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...
void SetUnitSelection(SCH_SHEET_PATH *aSheet, int aUnitSelection)
int GetUnit() const
wxString GetRefNumber() const
int m_SheetNum
The sheet number for the reference.
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
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 SetRefStr(const std::string &aReference)
const char * c_str() const
Definition: utf8.h:107
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
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.
wxString GetRef() const
#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
#define VALUE
void SortByTimeStamp()
Function SortComponentsByTimeStamp sort the flat list by Time Stamp.
int CompareValue(const SCH_REFERENCE &item) const
wxString buildFullReference(const SCH_REFERENCE &aItem, int aUnitNumber=-1)
SCH_COMPONENT * m_RootCmp
The component associated the reference object.
EDA_TEXT * m_Value
The component value of the reference.
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:143
int CompareLibName(const SCH_REFERENCE &item) const
static bool sortByRefAndValue(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
LIB_PART * m_Entry
The source component from a library.
void Annotate()
Function Annotate updates the annotation of the component according the the current object state...
Define a library symbol object.
timestamp_t GetTimeStamp() const
Definition: base_struct.h:207
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...
void SetUnit(int aUnit)
Change the unit number to aUnit.
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.
SCH_SHEET_PATH m_SheetPath
The sheet path for this reference.
int CompareRef(const SCH_REFERENCE &item) 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
const char * GetRefStr() const
#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
bool IsSameInstance(const SCH_REFERENCE &other) const
Function IsSameInstance returns whether this reference refers to the same component instance (compone...
static wxString SubReference(int aUnit, bool aAddSeparator=true)
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:70
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 CreateFirstFreeRefId(std::vector< int > &aIdList, int aFirstValue)
Function CreateFirstFreeRefId searches for the first free reference number in aListId of reference nu...
void SetRef(const wxString &aReference)
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.
int Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Function Cmp Compare if this is the same sheet path as aSheetPathToTest.
Class SCH_REFERENCE is used as a helper to define a component&#39;s reference designator in a schematic...
bool m_IsNew
True if not yet annotated.
static bool sortByXPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
virtual void SetText(const wxString &aText)
Definition: eda_text.h:154
int RefDesStringCompare(wxString strFWord, wxString strSWord)
Function RefDesStringCompare acts just like the strcmp function but treats numbers within the string ...
Definition: string.cpp:542