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