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  auto& ref_unit = componentFlatList[ii];
345 
346  if( ref_unit.m_Flag )
347  continue;
348 
349  // Check whether this component is in aLockedUnitMap.
350  SCH_REFERENCE_LIST* lockedList = NULL;
351  for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
352  {
353  unsigned n_refs = pair.second.GetCount();
354 
355  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
356  {
357  SCH_REFERENCE &thisRef = pair.second[thisRefI];
358 
359  if( thisRef.IsSameInstance( ref_unit ) )
360  {
361  lockedList = &pair.second;
362  break;
363  }
364  }
365  if( lockedList != NULL ) break;
366  }
367 
368  if( ( componentFlatList[first].CompareRef( ref_unit ) != 0 )
369  || ( aUseSheetNum && ( componentFlatList[first].m_SheetNum != ref_unit.m_SheetNum ) ) )
370  {
371  // New reference found: we need a new ref number for this reference
372  first = ii;
373 #ifdef USE_OLD_ALGO
374  minRefId = 0;
375 
376  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
377  if( aUseSheetNum )
378  minRefId = ref_unit.m_SheetNum * aSheetIntervalId;
379 
380  LastReferenceNumber = GetLastReference( ii, minRefId );
381 
382 #else
383  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
384  if( aUseSheetNum )
385  minRefId = ref_unit.m_SheetNum * aSheetIntervalId + 1;
386  else
387  minRefId = aStartNumber + 1;
388 
389  GetRefsInUse( first, idList, minRefId );
390 #endif
391  }
392 
393  // Annotation of one part per package components (trivial case).
394  if( ref_unit.GetLibPart()->GetUnitCount() <= 1 )
395  {
396  if( ref_unit.m_IsNew )
397  {
398 #ifdef USE_OLD_ALGO
399  LastReferenceNumber++;
400 #else
401  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
402 #endif
403  ref_unit.m_NumRef = LastReferenceNumber;
404  }
405 
406  ref_unit.m_Unit = 1;
407  ref_unit.m_Flag = 1;
408  ref_unit.m_IsNew = false;
409  continue;
410  }
411 
412  // Annotation of multi-unit parts ( n units per part ) (complex case)
413  NumberOfUnits = ref_unit.GetLibPart()->GetUnitCount();
414 
415  if( ref_unit.m_IsNew )
416  {
417 #ifdef USE_OLD_ALGO
418  LastReferenceNumber++;
419 #else
420  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
421 #endif
422  ref_unit.m_NumRef = LastReferenceNumber;
423 
424  if( !ref_unit.IsUnitsLocked() )
425  ref_unit.m_Unit = 1;
426 
427  ref_unit.m_Flag = 1;
428  }
429 
430  // If this component is in aLockedUnitMap, copy the annotation to all
431  // components that are not it
432  if( lockedList != NULL )
433  {
434  unsigned n_refs = lockedList->GetCount();
435 
436  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
437  {
438  SCH_REFERENCE &thisRef = (*lockedList)[thisRefI];
439 
440  if( thisRef.IsSameInstance( ref_unit ) )
441  {
442  // This is the component we're currently annotating. Hold the unit!
443  ref_unit.m_Unit = thisRef.m_Unit;
444  // lock this new full reference
445  inUseRefs.insert( buildFullReference( ref_unit ) );
446  }
447 
448  if( thisRef.CompareValue( ref_unit ) != 0 )
449  continue;
450 
451  if( thisRef.CompareLibName( ref_unit ) != 0 )
452  continue;
453 
454  // Find the matching component
455  for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
456  {
457  if( ! thisRef.IsSameInstance( componentFlatList[jj] ) )
458  continue;
459 
460  wxString ref_candidate = buildFullReference( ref_unit, thisRef.m_Unit );
461 
462  // propagate the new reference and unit selection to the "old" component,
463  // if this new full reference is not already used (can happens when initial
464  // multiunits components have duplicate references)
465  if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
466  {
467  componentFlatList[jj].m_NumRef = ref_unit.m_NumRef;
468  componentFlatList[jj].m_Unit = thisRef.m_Unit;
469  componentFlatList[jj].m_IsNew = false;
470  componentFlatList[jj].m_Flag = 1;
471  // lock this new full reference
472  inUseRefs.insert( ref_candidate );
473  break;
474  }
475  }
476  }
477  }
478  else
479  {
480  /* search for others units of this component.
481  * we search for others parts that have the same value and the same
482  * reference prefix (ref without ref number)
483  */
484  for( Unit = 1; Unit <= NumberOfUnits; Unit++ )
485  {
486  if( ref_unit.m_Unit == Unit )
487  continue;
488 
489  int found = FindUnit( ii, Unit );
490 
491  if( found >= 0 )
492  continue; // this unit exists for this reference (unit already annotated)
493 
494  // Search a component to annotate ( same prefix, same value, not annotated)
495  for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
496  {
497  auto& cmp_unit = componentFlatList[jj];
498 
499  if( cmp_unit.m_Flag ) // already tested
500  continue;
501 
502  if( cmp_unit.CompareRef( ref_unit ) != 0 )
503  continue;
504 
505  if( cmp_unit.CompareValue( ref_unit ) != 0 )
506  continue;
507 
508  if( cmp_unit.CompareLibName( ref_unit ) != 0 )
509  continue;
510 
511  if( aUseSheetNum &&
512  cmp_unit.GetSheetPath().Cmp( ref_unit.GetSheetPath() ) != 0 )
513  continue;
514 
515  if( !cmp_unit.m_IsNew )
516  continue;
517 
518  // Component without reference number found, annotate it if possible
519  if( !cmp_unit.IsUnitsLocked()
520  || ( cmp_unit.m_Unit == Unit ) )
521  {
522  cmp_unit.m_NumRef = ref_unit.m_NumRef;
523  cmp_unit.m_Unit = Unit;
524  cmp_unit.m_Flag = 1;
525  cmp_unit.m_IsNew = false;
526  break;
527  }
528  }
529  }
530  }
531  }
532 }
533 
534 
536 {
537  int error = 0;
538  wxString tmp;
539  wxString msg;
540 
542 
543  // Spiit reference designators into name (prefix) and number: IC1 becomes IC, and 1.
544  SplitReferences();
545 
546  // count not yet annotated items or annotation error.
547  for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
548  {
549  msg.Empty();
550  tmp.Empty();
551 
552  if( componentFlatList[ii].m_IsNew ) // Not yet annotated
553  {
554  if( componentFlatList[ii].m_NumRef >= 0 )
555  tmp << componentFlatList[ii].m_NumRef;
556  else
557  tmp = wxT( "?" );
558 
559 
560  if( ( componentFlatList[ii].m_Unit > 0 )
561  && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) )
562  {
563  msg.Printf( _( "Item not annotated: %s%s (unit %d)\n" ),
564  componentFlatList[ii].GetRef(),
565  tmp,
566  componentFlatList[ii].m_Unit );
567  }
568  else
569  {
570  msg.Printf( _( "Item not annotated: %s%s\n" ),
571  GetChars( componentFlatList[ii].GetRef() ),
572  GetChars( tmp ) );
573  }
574 
575  aReporter.Report( msg, REPORTER::RPT_WARNING );
576  error++;
577  break;
578  }
579 
580  // Error if unit number selected does not exist ( greater than the number of
581  // parts in the component ). This can happen if a component has changed in a
582  // library after a previous annotation.
583  if( std::max( componentFlatList[ii].GetLibPart()->GetUnitCount(), 1 )
584  < componentFlatList[ii].m_Unit )
585  {
586  if( componentFlatList[ii].m_NumRef >= 0 )
587  tmp << componentFlatList[ii].m_NumRef;
588  else
589  tmp = wxT( "?" );
590 
591  msg.Printf( _( "Error: symbol %s%s unit %d and symbol has only %d units defined\n" ),
592  componentFlatList[ii].GetRef(),
593  tmp,
594  componentFlatList[ii].m_Unit,
595  componentFlatList[ii].GetLibPart()->GetUnitCount() );
596 
597  aReporter.Report( msg, REPORTER::RPT_ERROR );
598  error++;
599  break;
600  }
601  }
602 
603  if( error )
604  return error;
605 
606  // count the duplicated elements (if all are annotated)
607  int imax = componentFlatList.size() - 1;
608 
609  for( int ii = 0; ii < imax; ii++ )
610  {
611  msg.Empty();
612  tmp.Empty();
613 
614  if( ( componentFlatList[ii].CompareRef( componentFlatList[ii + 1] ) != 0 )
615  || ( componentFlatList[ii].m_NumRef != componentFlatList[ii + 1].m_NumRef ) )
616  continue;
617 
618  // Same reference found. If same unit, error!
619  if( componentFlatList[ii].m_Unit == componentFlatList[ii + 1].m_Unit )
620  {
621  if( componentFlatList[ii].m_NumRef >= 0 )
622  tmp << componentFlatList[ii].m_NumRef;
623  else
624  tmp = wxT( "?" );
625 
626  if( ( componentFlatList[ii].m_Unit > 0 )
627  && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) )
628  {
629  msg.Printf( _( "Multiple item %s%s (unit %d)\n" ),
630  componentFlatList[ii].GetRef(),
631  tmp,
632  componentFlatList[ii].m_Unit );
633  }
634  else
635  {
636  msg.Printf( _( "Multiple item %s%s\n" ),
637  componentFlatList[ii].GetRef(),
638  tmp );
639  }
640 
641  aReporter.Report( msg, REPORTER::RPT_ERROR );
642  error++;
643  continue;
644  }
645 
646  /* Test error if units are different but number of parts per package
647  * too high (ex U3 ( 1 part) and we find U3B this is an error) */
648  if( componentFlatList[ii].GetLibPart()->GetUnitCount()
649  != componentFlatList[ii + 1].GetLibPart()->GetUnitCount() )
650  {
651  if( componentFlatList[ii].m_NumRef >= 0 )
652  tmp << componentFlatList[ii].m_NumRef;
653  else
654  tmp = wxT( "?" );
655 
656  if( ( componentFlatList[ii].m_Unit > 0 )
657  && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) )
658  {
659  msg.Printf( _( "Multiple item %s%s (unit %d)\n" ),
660  GetChars( componentFlatList[ii].GetRef() ),
661  GetChars( tmp ),
662  componentFlatList[ii].m_Unit );
663  }
664  else
665  {
666  msg.Printf( _( "Multiple item %s%s\n" ),
667  GetChars( componentFlatList[ii].GetRef() ),
668  GetChars( tmp ) );
669  }
670 
671  aReporter.Report( msg, REPORTER::RPT_ERROR );
672  error++;
673  }
674 
675  // Error if values are different between units, for the same reference
676  int next = ii + 1;
677 
678  if( componentFlatList[ii].CompareValue( componentFlatList[next] ) != 0 )
679  {
680  msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
681  componentFlatList[ii].GetRef(),
682  componentFlatList[ii].m_NumRef,
684  componentFlatList[ii].m_Value->GetText(),
685  componentFlatList[next].GetRef(),
686  componentFlatList[next].m_NumRef,
688  componentFlatList[next].m_Value->GetText() );
689 
690  aReporter.Report( msg, REPORTER::RPT_ERROR );
691  error++;
692  }
693  }
694 
695  // count the duplicated time stamps
696  SortByTimeStamp();
697 
698  for( int ii = 0; ii < imax; ii++ )
699  {
700  if( ( componentFlatList[ii].m_TimeStamp != componentFlatList[ii + 1].m_TimeStamp )
701  || ( componentFlatList[ii].GetSheetPath() != componentFlatList[ii + 1].GetSheetPath() ) )
702  continue;
703 
704  // Same time stamp found.
705  wxString full_path;
706 
707  full_path.Printf( wxT( "%s%8.8X" ),
708  GetChars( componentFlatList[ii].GetSheetPath().Path() ),
709  componentFlatList[ii].m_TimeStamp );
710 
711  msg.Printf( _( "Duplicate time stamp (%s) for %s%d and %s%d" ),
712  full_path,
713  componentFlatList[ii].GetRef(),
714  componentFlatList[ii].m_NumRef,
715  componentFlatList[ii + 1].GetRef(),
716  componentFlatList[ii + 1].m_NumRef );
717 
718  aReporter.Report( msg, REPORTER::RPT_WARNING );
719  error++;
720  }
721 
722  return error;
723 }
724 
725 
727  SCH_SHEET_PATH& aSheetPath )
728 {
729  wxASSERT( aComponent != NULL );
730 
731  m_RootCmp = aComponent;
732  m_Entry = aLibPart; // Warning: can be nullptr for orphan components
733  // (i.e. with a symbol library not found)
734  m_Unit = aComponent->GetUnitSelection( &aSheetPath );
735  m_SheetPath = aSheetPath;
736  m_IsNew = false;
737  m_Flag = 0;
738  m_TimeStamp = aComponent->GetTimeStamp();
739  m_CmpPos = aComponent->GetPosition();
740  m_SheetNum = 0;
741 
742  if( aComponent->GetRef( &aSheetPath ).IsEmpty() )
743  aComponent->SetRef( &aSheetPath, wxT( "DefRef?" ) );
744 
745  wxString ref = aComponent->GetRef( &aSheetPath );
746  SetRef( ref );
747 
748  m_NumRef = -1;
749 
750  if( aComponent->GetField( VALUE )->GetText().IsEmpty() )
751  aComponent->GetField( VALUE )->SetText( wxT( "~" ) );
752 
753  m_Value = aComponent->GetField( VALUE );
754 }
755 
756 
758 {
759  if( m_NumRef < 0 )
760  m_Ref += '?';
761  else
762  {
763  m_Ref = TO_UTF8( GetRef() << GetRefNumber() );
764  }
765 
769 }
770 
771 
773 {
774  std::string refText = GetRefStr();
775 
776  m_NumRef = -1;
777 
778  int ll = refText.length() - 1;
779 
780  if( refText[ll] == '?' )
781  {
782  m_IsNew = true;
783 
784  if( !IsUnitsLocked() )
785  m_Unit = 0x7FFFFFFF;
786 
787  refText.erase( ll ); // delete last char
788 
789  SetRefStr( refText );
790  }
791  else if( isdigit( refText[ll] ) == 0 )
792  {
793  m_IsNew = true;
794 
795  if( !IsUnitsLocked() )
796  m_Unit = 0x7FFFFFFF;
797  }
798  else
799  {
800  while( ll >= 0 )
801  {
802  if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) )
803  ll--;
804  else
805  {
806  if( isdigit( refText[ll + 1] ) )
807  {
808  // null terminated C string into cp
809  const char* cp = refText.c_str() + ll + 1;
810 
811  m_NumRef = atoi( cp );
812  }
813 
814  refText.erase( ll+1 ); // delete from ll+1 to end
815  break;
816  }
817  }
818 
819  SetRefStr( refText );
820  }
821 }
822 
823 
824 wxString SCH_REFERENCE_LIST::Shorthand( std::vector<SCH_REFERENCE> aList )
825 {
826  wxString retVal;
827  size_t i = 0;
828 
829  while( i < aList.size() )
830  {
831  wxString ref = aList[ i ].GetRef();
832  int numRef = aList[ i ].m_NumRef;
833 
834  size_t range = 1;
835 
836  while( i + range < aList.size()
837  && aList[ i + range ].GetRef() == ref
838  && aList[ i + range ].m_NumRef == int( numRef + range ) )
839  {
840  range++;
841  }
842 
843  if( !retVal.IsEmpty() )
844  retVal << wxT( ", " );
845 
846  if( range == 1 )
847  {
848  retVal << ref << aList[ i ].GetRefNumber();
849  }
850  else if( range == 2 )
851  {
852  retVal << ref << aList[ i ].GetRefNumber();
853  retVal << wxT( ", " );
854  retVal << ref << aList[ i + 1 ].GetRefNumber();
855  }
856  else
857  {
858  retVal << ref << aList[ i ].GetRefNumber();
859  retVal << wxT( "-" );
860  retVal << ref << aList[ i + ( range - 1 ) ].GetRefNumber();
861  }
862 
863  i+= range;
864  }
865 
866  return retVal;
867 }
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:62
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:48
#define VALUE
void SortByTimeStamp()
Function SortComponentsByTimeStamp sort the flat list by Time Stamp.
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:126
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.
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:216
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.
#define _(s)
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.
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:101
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:649
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:73
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.
virtual const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:124
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)