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 )
277 {
278  wxString fullref;
279  fullref = aItem.GetRef() + aItem.GetRefNumber();
280  fullref << ".." << aItem.GetUnit();
281 
282  return fullref;
283 }
284 
285 
286 void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
287  SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap )
288 {
289  if ( componentFlatList.size() == 0 )
290  return;
291 
292  int LastReferenceNumber = 0;
293  int NumberOfUnits, Unit;
294 
295  /* calculate index of the first component with the same reference prefix
296  * than the current component. All components having the same reference
297  * prefix will receive a reference number with consecutive values:
298  * IC .. will be set to IC4, IC4, IC5 ...
299  */
300  unsigned first = 0;
301 
302  // calculate the last used number for this reference prefix:
303 #ifdef USE_OLD_ALGO
304  int minRefId = 0;
305 
306  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
307  if( aUseSheetNum )
308  minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId;
309 
310  LastReferenceNumber = GetLastReference( first, minRefId );
311 #else
312  int minRefId;
313 
314  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
315  if( aUseSheetNum )
316  minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId + 1;
317  else
318  minRefId = aStartNumber + 1;
319 
320  // For multi units components, when "keep order of multi unit" option is selected,
321  // store the list of already used full references.
322  // The algorithm try to allocate the new reference to components having the same
323  // old reference.
324  // This algo works fine as long as the previous annotation has no duplicates.
325  // But when a hierarchy is reannotated with this option, the previous anotation can
326  // have duplicate references, and obviously we must fix these duplicate.
327  // therefore do not try to allocate a full reference more than once when trying
328  // to keep this order of multi units.
329  // inUseRefs keep trace of previously allocated references
330  std::unordered_set<wxString> inUseRefs;
331 
332  // This is the list of all Id already in use for a given reference prefix.
333  // Will be refilled for each new reference prefix.
334  std::vector<int>idList;
335  GetRefsInUse( first, idList, minRefId );
336 #endif
337  for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
338  {
339  if( componentFlatList[ii].m_Flag )
340  continue;
341 
342  // Check whether this component is in aLockedUnitMap.
343  SCH_REFERENCE_LIST* lockedList = NULL;
344  for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
345  {
346  unsigned n_refs = pair.second.GetCount();
347  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
348  {
349  SCH_REFERENCE &thisRef = pair.second[thisRefI];
350 
351  if( thisRef.IsSameInstance( componentFlatList[ii] ) )
352  {
353  lockedList = &pair.second;
354  break;
355  }
356  }
357  if( lockedList != NULL ) break;
358  }
359 
360  if( ( componentFlatList[first].CompareRef( componentFlatList[ii] ) != 0 )
361  || ( aUseSheetNum && ( componentFlatList[first].m_SheetNum != componentFlatList[ii].m_SheetNum ) ) )
362  {
363  // New reference found: we need a new ref number for this reference
364  first = ii;
365 #ifdef USE_OLD_ALGO
366  minRefId = 0;
367 
368  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
369  if( aUseSheetNum )
370  minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId;
371 
372  LastReferenceNumber = GetLastReference( ii, minRefId );
373 
374 #else
375  // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
376  if( aUseSheetNum )
377  minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId + 1;
378  else
379  minRefId = aStartNumber + 1;
380 
381  GetRefsInUse( first, idList, minRefId );
382 #endif
383  }
384 
385  // Annotation of one part per package components (trivial case).
386  if( componentFlatList[ii].GetLibPart()->GetUnitCount() <= 1 )
387  {
388  if( componentFlatList[ii].m_IsNew )
389  {
390 #ifdef USE_OLD_ALGO
391  LastReferenceNumber++;
392 #else
393  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
394 #endif
395  componentFlatList[ii].m_NumRef = LastReferenceNumber;
396  }
397 
398  componentFlatList[ii].m_Unit = 1;
399  componentFlatList[ii].m_Flag = 1;
400  componentFlatList[ii].m_IsNew = false;
401  continue;
402  }
403 
404  // Annotation of multi-unit parts ( n units per part ) (complex case)
405  NumberOfUnits = componentFlatList[ii].GetLibPart()->GetUnitCount();
406 
407  if( componentFlatList[ii].m_IsNew )
408  {
409 #ifdef USE_OLD_ALGO
410  LastReferenceNumber++;
411 #else
412  LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
413 #endif
414  componentFlatList[ii].m_NumRef = LastReferenceNumber;
415 
416  if( !componentFlatList[ii].IsUnitsLocked() )
417  componentFlatList[ii].m_Unit = 1;
418 
419  componentFlatList[ii].m_Flag = 1;
420  }
421 
422  // If this component is in aLockedUnitMap, copy the annotation to all
423  // components that are not it
424  if( lockedList != NULL )
425  {
426  unsigned n_refs = lockedList->GetCount();
427 
428  for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
429  {
430  SCH_REFERENCE &thisRef = (*lockedList)[thisRefI];
431 
432  if( thisRef.IsSameInstance( componentFlatList[ii] ) )
433  {
434  // This is the component we're currently annotating. Hold the unit!
435  componentFlatList[ii].m_Unit = thisRef.m_Unit;
436  }
437 
438  if( thisRef.CompareValue( componentFlatList[ii] ) != 0 )
439  continue;
440 
441  if( thisRef.CompareLibName( componentFlatList[ii] ) != 0 )
442  continue;
443 
444  // Find the matching component
445  for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
446  {
447  if( ! thisRef.IsSameInstance( componentFlatList[jj] ) )
448  continue;
449 
450  wxString ref_candidate = buildFullReference( componentFlatList[ii] );
451 
452  // propagate the new reference and unit selection to the "old" component,
453  // if this new full reference is not already used (can happens when initial
454  // multiunits components have duplicate references)
455  if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
456  {
457  componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
458  componentFlatList[jj].m_Unit = thisRef.m_Unit;
459  componentFlatList[jj].m_IsNew = false;
460  componentFlatList[jj].m_Flag = 1;
461  // lock this new full reference
462  inUseRefs.insert( ref_candidate );
463  break;
464  }
465  }
466  }
467  }
468 
469  else
470  {
471  /* search for others units of this component.
472  * we search for others parts that have the same value and the same
473  * reference prefix (ref without ref number)
474  */
475  for( Unit = 1; Unit <= NumberOfUnits; Unit++ )
476  {
477  if( componentFlatList[ii].m_Unit == Unit )
478  continue;
479 
480  int found = FindUnit( ii, Unit );
481 
482  if( found >= 0 )
483  continue; // this unit exists for this reference (unit already annotated)
484 
485  // Search a component to annotate ( same prefix, same value, not annotated)
486  for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
487  {
488  if( componentFlatList[jj].m_Flag ) // already tested
489  continue;
490 
491  if( componentFlatList[ii].CompareRef( componentFlatList[jj] ) != 0 )
492  continue;
493 
494  if( componentFlatList[jj].CompareValue( componentFlatList[ii] ) != 0 )
495  continue;
496 
497  if( componentFlatList[jj].CompareLibName( componentFlatList[ii] ) != 0 )
498  continue;
499 
500  if( !componentFlatList[jj].m_IsNew )
501  continue;
502 
503  // Component without reference number found, annotate it if possible
504  if( !componentFlatList[jj].IsUnitsLocked()
505  || ( componentFlatList[jj].m_Unit == Unit ) )
506  {
507  componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
508  componentFlatList[jj].m_Unit = Unit;
509  componentFlatList[jj].m_Flag = 1;
510  componentFlatList[jj].m_IsNew = false;
511  break;
512  }
513  }
514  }
515  }
516  }
517 }
518 
519 
521 {
522  int error = 0;
523  wxString tmp;
524  wxString msg;
525 
527 
528  // Spiit reference designators into name (prefix) and number: IC1 becomes IC, and 1.
529  SplitReferences();
530 
531  // count not yet annotated items or annotation error.
532  for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
533  {
534  msg.Empty();
535  tmp.Empty();
536 
537  if( componentFlatList[ii].m_IsNew ) // Not yet annotated
538  {
539  if( componentFlatList[ii].m_NumRef >= 0 )
540  tmp << componentFlatList[ii].m_NumRef;
541  else
542  tmp = wxT( "?" );
543 
544 
545  if( ( componentFlatList[ii].m_Unit > 0 )
546  && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) )
547  {
548  msg.Printf( _( "Item not annotated: %s%s (unit %d)\n" ),
549  GetChars( componentFlatList[ii].GetRef() ),
550  GetChars( tmp ),
551  componentFlatList[ii].m_Unit );
552  }
553  else
554  {
555  msg.Printf( _( "Item not annotated: %s%s\n" ),
556  GetChars( componentFlatList[ii].GetRef() ),
557  GetChars( tmp ) );
558  }
559 
560  aReporter.Report( msg, REPORTER::RPT_WARNING );
561  error++;
562  break;
563  }
564 
565  // Error if unit number selected does not exist ( greater than the number of
566  // parts in the component ). This can happen if a component has changed in a
567  // library after a previous annotation.
568  if( std::max( componentFlatList[ii].GetLibPart()->GetUnitCount(), 1 )
569  < componentFlatList[ii].m_Unit )
570  {
571  if( componentFlatList[ii].m_NumRef >= 0 )
572  tmp << componentFlatList[ii].m_NumRef;
573  else
574  tmp = wxT( "?" );
575 
576  msg.Printf( _( "Error: symbol %s%s unit %d and symbol has only %d units defined\n" ),
577  GetChars( componentFlatList[ii].GetRef() ),
578  GetChars( tmp ),
579  componentFlatList[ii].m_Unit,
580  componentFlatList[ii].GetLibPart()->GetUnitCount() );
581 
582  aReporter.Report( msg, REPORTER::RPT_ERROR );
583  error++;
584  break;
585  }
586  }
587 
588  if( error )
589  return error;
590 
591  // count the duplicated elements (if all are annotated)
592  int imax = componentFlatList.size() - 1;
593 
594  for( int ii = 0; (ii < imax) && (error < 4); ii++ )
595  {
596  msg.Empty();
597  tmp.Empty();
598 
599  if( ( componentFlatList[ii].CompareRef( componentFlatList[ii + 1] ) != 0 )
600  || ( componentFlatList[ii].m_NumRef != componentFlatList[ii + 1].m_NumRef ) )
601  continue;
602 
603  // Same reference found. If same unit, error!
604  if( componentFlatList[ii].m_Unit == componentFlatList[ii + 1].m_Unit )
605  {
606  if( componentFlatList[ii].m_NumRef >= 0 )
607  tmp << componentFlatList[ii].m_NumRef;
608  else
609  tmp = wxT( "?" );
610 
611  if( ( componentFlatList[ii].m_Unit > 0 )
612  && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) )
613  {
614  msg.Printf( _( "Multiple item %s%s (unit %d)\n" ),
615  GetChars( componentFlatList[ii].GetRef() ),
616  GetChars( tmp ),
617  componentFlatList[ii].m_Unit );
618  }
619  else
620  {
621  msg.Printf( _( "Multiple item %s%s\n" ),
622  GetChars( componentFlatList[ii].GetRef() ),
623  GetChars( tmp ) );
624  }
625 
626  aReporter.Report( msg, REPORTER::RPT_ERROR );
627  error++;
628  continue;
629  }
630 
631  /* Test error if units are different but number of parts per package
632  * too high (ex U3 ( 1 part) and we find U3B this is an error) */
633  if( componentFlatList[ii].GetLibPart()->GetUnitCount()
634  != componentFlatList[ii + 1].GetLibPart()->GetUnitCount() )
635  {
636  if( componentFlatList[ii].m_NumRef >= 0 )
637  tmp << componentFlatList[ii].m_NumRef;
638  else
639  tmp = wxT( "?" );
640 
641  if( ( componentFlatList[ii].m_Unit > 0 )
642  && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) )
643  {
644  msg.Printf( _( "Multiple item %s%s (unit %d)\n" ),
645  GetChars( componentFlatList[ii].GetRef() ),
646  GetChars( tmp ),
647  componentFlatList[ii].m_Unit );
648  }
649  else
650  {
651  msg.Printf( _( "Multiple item %s%s\n" ),
652  GetChars( componentFlatList[ii].GetRef() ),
653  GetChars( tmp ) );
654  }
655 
656  aReporter.Report( msg, REPORTER::RPT_ERROR );
657  error++;
658  }
659 
660  // Error if values are different between units, for the same reference
661  int next = ii + 1;
662 
663  if( componentFlatList[ii].CompareValue( componentFlatList[next] ) != 0 )
664  {
665  msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
666  GetChars( componentFlatList[ii].GetRef() ),
667  componentFlatList[ii].m_NumRef,
669  componentFlatList[ii].m_Unit ) ),
670  GetChars( componentFlatList[ii].m_Value->GetText() ),
671  GetChars( componentFlatList[next].GetRef() ),
672  componentFlatList[next].m_NumRef,
674  componentFlatList[next].m_Unit ) ),
675  GetChars( componentFlatList[next].m_Value->GetText() ) );
676 
677  aReporter.Report( msg, REPORTER::RPT_ERROR );
678  error++;
679  }
680  }
681 
682  // count the duplicated time stamps
683  SortByTimeStamp();
684 
685  for( int ii = 0; ( ii < imax ) && ( error < 4 ); ii++ )
686  {
687  if( ( componentFlatList[ii].m_TimeStamp != componentFlatList[ii + 1].m_TimeStamp )
688  || ( componentFlatList[ii].GetSheetPath() != componentFlatList[ii + 1].GetSheetPath() ) )
689  continue;
690 
691  // Same time stamp found.
692  wxString full_path;
693 
694  full_path.Printf( wxT( "%s%8.8X" ),
695  GetChars( componentFlatList[ii].GetSheetPath().Path() ),
696  componentFlatList[ii].m_TimeStamp );
697 
698  msg.Printf( _( "Duplicate time stamp (%s) for %s%d and %s%d" ),
699  GetChars( full_path ),
700  GetChars( componentFlatList[ii].GetRef() ), componentFlatList[ii].m_NumRef,
701  GetChars( componentFlatList[ii + 1].GetRef() ),
702  componentFlatList[ii + 1].m_NumRef );
703 
704  aReporter.Report( msg, REPORTER::RPT_WARNING );
705  error++;
706  }
707 
708  return error;
709 }
710 
711 
713  SCH_SHEET_PATH& aSheetPath )
714 {
715  wxASSERT( aComponent != NULL && aLibPart != NULL );
716 
717  m_RootCmp = aComponent;
718  m_Entry = aLibPart;
719  m_Unit = aComponent->GetUnitSelection( &aSheetPath );
720  m_SheetPath = aSheetPath;
721  m_IsNew = false;
722  m_Flag = 0;
723  m_TimeStamp = aComponent->GetTimeStamp();
724  m_CmpPos = aComponent->GetPosition();
725  m_SheetNum = 0;
726 
727  if( aComponent->GetRef( &aSheetPath ).IsEmpty() )
728  aComponent->SetRef( &aSheetPath, wxT( "DefRef?" ) );
729 
730  wxString ref = aComponent->GetRef( &aSheetPath );
731  SetRef( ref );
732 
733  m_NumRef = -1;
734 
735  if( aComponent->GetField( VALUE )->GetText().IsEmpty() )
736  aComponent->GetField( VALUE )->SetText( wxT( "~" ) );
737 
738  m_Value = aComponent->GetField( VALUE );
739 }
740 
741 
743 {
744  if( m_NumRef < 0 )
745  m_Ref += '?';
746  else
747  {
748  m_Ref = TO_UTF8( GetRef() << GetRefNumber() );
749  }
750 
751  m_RootCmp->SetRef( &m_SheetPath, FROM_UTF8( m_Ref.c_str() ) );
752  m_RootCmp->SetUnit( m_Unit );
753  m_RootCmp->SetUnitSelection( &m_SheetPath, m_Unit );
754 }
755 
756 
758 {
759  std::string refText = GetRefStr();
760 
761  m_NumRef = -1;
762 
763  int ll = refText.length() - 1;
764 
765  if( refText[ll] == '?' )
766  {
767  m_IsNew = true;
768 
769  if( !IsUnitsLocked() )
770  m_Unit = 0x7FFFFFFF;
771 
772  refText.erase( ll ); // delete last char
773 
774  SetRefStr( refText );
775  }
776  else if( isdigit( refText[ll] ) == 0 )
777  {
778  m_IsNew = true;
779 
780  if( !IsUnitsLocked() )
781  m_Unit = 0x7FFFFFFF;
782  }
783  else
784  {
785  while( ll >= 0 )
786  {
787  if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) )
788  ll--;
789  else
790  {
791  if( isdigit( refText[ll + 1] ) )
792  {
793  // null terminated C string into cp
794  const char* cp = refText.c_str() + ll + 1;
795 
796  m_NumRef = atoi( cp );
797  }
798 
799  refText.erase( ll+1 ); // delete from ll+1 to end
800  break;
801  }
802  }
803 
804  SetRefStr( refText );
805  }
806 }
807 
808 
809 wxString SCH_REFERENCE_LIST::Shorthand( std::vector<SCH_REFERENCE> aList )
810 {
811  wxString retVal;
812 
813  std::sort( aList.begin(), aList.end(),
814  []( const SCH_REFERENCE& lhs, const SCH_REFERENCE& rhs ) -> bool
815  {
816  wxString lhRef( lhs.GetRef() << lhs.GetRefNumber() );
817  wxString rhRef( rhs.GetRef() << rhs.GetRefNumber() );
818  return RefDesStringCompare( lhRef, rhRef ) < 0;
819  } );
820 
821  size_t i = 0;
822 
823  while( i < aList.size() )
824  {
825  wxString ref = aList[ i ].GetRef();
826 
827  size_t j = i;
828 
829  while( j + 1 < aList.size() && aList[ j + 1 ].GetRef() == ref )
830  j = j + 1;
831 
832  if( !retVal.IsEmpty() )
833  retVal << wxT( ", " );
834 
835  if( j == i )
836  {
837  retVal << ref << aList[ i ].GetRefNumber();
838  }
839  else if( j == i + 1 )
840  {
841  retVal << ref << aList[ i ].GetRefNumber();
842  retVal << wxT( ", " );
843  retVal << ref << aList[ j ].GetRefNumber();
844  }
845  else
846  {
847  retVal << ref << aList[ i ].GetRefNumber();
848  retVal << wxT( " - " );
849  retVal << ref << aList[ j ].GetRefNumber();
850  }
851 
852  i = j + 1;
853  }
854 
855  return retVal;
856 }
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.
int CompareLibName(const SCH_REFERENCE &item) const
int RefDesStringCompare(const wxString &strFWord, const wxString &strSWord)
Function RefDesStringCompare acts just like the strcmp function but treats numbers within the string ...
Definition: string.cpp:466
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...
int CompareValue(const SCH_REFERENCE &item) const
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)...
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...
int m_SheetNum
The sheet number for the reference.
bool IsSameInstance(const SCH_REFERENCE &other) const
Function IsSameInstance returns whether this reference refers to the same component instance (compone...
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
int GetUnit() const
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 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.
#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
void SortByTimeStamp()
Function SortComponentsByTimeStamp sort the flat list by Time Stamp.
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
int CompareRef(const SCH_REFERENCE &item) const
SCH_COMPONENT * m_RootCmp
The component associated the reference object.
static bool sortByRefAndValue(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:128
void Annotate()
Function Annotate updates the annotation of the component according the the current object state...
Define a library symbol object.
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...
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.
YYCODETYPE lhs
SCH_SHEET_PATH m_SheetPath
The sheet path for this reference.
wxString GetRef() 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
#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
static wxString SubReference(int aUnit, bool aAddSeparator=true)
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
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 Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Function Cmp Compare if this is the same sheet path as aSheetPathToTest.
int CreateFirstFreeRefId(std::vector< int > &aIdList, int aFirstValue)
Function CreateFirstFreeRefId searches for the first free reference number in aListId of reference nu...
int GetLastReference(int aIndex, int aMinValue)
Function GetLastReference returns the last used (greatest) reference number in the reference list for...
wxString buildFullReference(const SCH_REFERENCE &aItem)
int CheckAnnotation(REPORTER &aReporter)
Function CheckAnnotation check for annotations errors.
unsigned GetCount()
Function GetCount.
wxString GetRefNumber() const
#define VALUE
Class SCH_REFERENCE is used as a helper to define a component&#39;s reference designator in a schematic...
timestamp_t GetTimeStamp() const
Definition: base_struct.h:215
static bool sortByXPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
virtual void SetText(const wxString &aText)
Definition: eda_text.h:139