KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_reference_list.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 1992-2018 jean-pierre Charras <jp.charras at wanadoo.fr>
5 * Copyright (C) 1992-2011 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
30
31#include <sch_reference_list.h>
32#include <core/kicad_algo.h>
33
34#include <wx/regex.h>
35#include <algorithm>
36#include <vector>
37#include <unordered_set>
38
39#include <string_utils.h>
40#include <erc/erc_settings.h>
41#include <refdes_tracker.h>
42#include <sch_symbol.h>
43#include <sch_edit_frame.h>
44
45
46void SCH_REFERENCE_LIST::RemoveItem( unsigned int aIndex )
47{
48 if( aIndex < m_flatList.size() )
49 m_flatList.erase( m_flatList.begin() + aIndex );
50}
51
52
54{
55 for( unsigned ii = 0; ii < GetCount(); ii++ )
56 {
57 if( m_flatList[ii].IsSameInstance( aItem ) )
58 return true;
59 }
60
61 return false;
62}
63
64
66{
67 int ii = item1.CompareRef( item2 );
68
69 if( ii == 0 )
70 ii = item1.m_sheetNum - item2.m_sheetNum;
71
72 if( ii == 0 )
73 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
74
75 if( ii == 0 )
76 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
77
78 if( ii == 0 )
79 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
80 else
81 return ii < 0;
82}
83
84
86{
87 int ii = item1.CompareRef( item2 );
88
89 if( ii == 0 )
90 ii = item1.m_sheetNum - item2.m_sheetNum;
91
92 if( ii == 0 )
93 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
94
95 if( ii == 0 )
96 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
97
98 if( ii == 0 )
99 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
100 else
101 return ii < 0;
102}
103
104
106 const SCH_REFERENCE& item2 )
107{
108 int ii = item1.CompareRef( item2 );
109
110 if( ii == 0 )
111 ii = item1.CompareValue( item2 );
112
113 if( ii == 0 )
114 ii = item1.m_unit - item2.m_unit;
115
116 if( ii == 0 )
117 ii = item1.m_sheetNum - item2.m_sheetNum;
118
119 if( ii == 0 )
120 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
121
122 if( ii == 0 )
123 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
124
125 if( ii == 0 )
126 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
127 else
128 return ii < 0;
129}
130
131
133 const SCH_REFERENCE& item2 )
134{
135 int ii = StrNumCmp( item1.GetRef(), item2.GetRef(), false );
136
137 if( ii == 0 )
138 ii = item1.m_unit - item2.m_unit;
139
140 if( ii == 0 )
141 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
142 else
143 return ii < 0;
144}
145
146
148 const SCH_REFERENCE& item2 )
149{
150 int ii = item1.m_sheetPath.Cmp( item2.m_sheetPath );
151
152 if( ii == 0 )
153 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
154 else
155 return ii < 0;
156}
157
158
160{
161 return item1.m_rootSymbol < item2.m_rootSymbol;
162}
163
164
165int SCH_REFERENCE_LIST::FindRefByFullPath( const wxString& aFullPath ) const
166{
167 for( size_t i = 0; i < m_flatList.size(); ++i )
168 {
169 if( m_flatList[i].GetFullPath() == aFullPath )
170 return i;
171 }
172
173 return -1;
174}
175
176
177int SCH_REFERENCE_LIST::FindRef( const wxString& aRef ) const
178{
179 for( size_t i = 0; i < m_flatList.size(); ++i )
180 {
181 if( m_flatList[i].GetRef() == aRef )
182 return i;
183 }
184
185 return -1;
186}
187
188
189void SCH_REFERENCE_LIST::GetRefsInUse( int aIndex, std::vector< int >& aIdList,
190 int aMinRefId ) const
191{
192 aIdList.clear();
193
194 for( const SCH_REFERENCE& ref : m_flatList )
195 {
196 // Don't add new references to the list as we will reannotate those
197 if( m_flatList[aIndex].CompareRef( ref ) == 0 && ref.m_numRef >= aMinRefId && !ref.m_isNew )
198 aIdList.push_back( ref.m_numRef );
199 }
200
201 std::sort( aIdList.begin(), aIdList.end() );
202
203 // Ensure each reference number appears only once. If there are symbols with
204 // multiple parts per package the same number will be stored for each part.
205 alg::remove_duplicates( aIdList );
206}
207
208
209std::vector<int> SCH_REFERENCE_LIST::GetUnitsMatchingRef( const SCH_REFERENCE& aRef ) const
210{
211 std::vector<int> unitsList;
212
213 // Always add this reference to the list
214 unitsList.push_back( aRef.m_unit );
215
216 for( SCH_REFERENCE ref : m_flatList )
217 {
218 if( ref.CompareValue( aRef ) != 0 )
219 continue;
220
221 if( ref.CompareLibName( aRef ) != 0 )
222 continue;
223
224 // Split if needed before comparing ref and number
225 if( ref.IsSplitNeeded() )
226 ref.Split();
227
228 if( ref.CompareRef( aRef ) != 0 )
229 continue;
230
231 if( ref.m_numRef != aRef.m_numRef )
232 continue;
233
234 unitsList.push_back( ref.m_unit );
235 }
236
237 std::sort( unitsList.begin(), unitsList.end() );
238
239 // Ensure each reference number appears only once. If there are symbols with
240 // multiple parts per package the same number will be stored for each part.
241 alg::remove_duplicates( unitsList );
242
243 return unitsList;
244}
245
246
248 const std::vector<int>& aRequiredUnits ) const
249{
250 // Create a map of references indexed by reference number, only including those with the same
251 // reference prefix as aRef
252 std::map<int, std::vector<SCH_REFERENCE>> refNumberMap;
253
254 for( const SCH_REFERENCE& ref : m_flatList )
255 {
256 // search only for the current reference prefix:
257 if( ref.CompareRef( aRef ) != 0 )
258 continue;
259
260 if( ref.m_isNew )
261 continue; // It will be reannotated
262
263 refNumberMap[ref.m_numRef].push_back( ref );
264 }
265
266 return m_refDesTracker->GetNextRefDesForUnits( aRef, refNumberMap, aRequiredUnits, aMinValue );
267}
268
269
270std::vector<SCH_SYMBOL_INSTANCE> SCH_REFERENCE_LIST::GetSymbolInstances() const
271{
272 std::vector<SCH_SYMBOL_INSTANCE> retval;
273
274 for( const SCH_REFERENCE& ref : m_flatList )
275 {
276 SCH_SYMBOL_INSTANCE instance;
277 instance.m_Path = ref.GetSheetPath().Path();
278 instance.m_Reference = ref.GetRef();
279 instance.m_Unit = ref.GetUnit();
280
281 retval.push_back( instance );
282 }
283
284 return retval;
285}
286
287
288// A helper function to build a full reference string of a SCH_REFERENCE item
289wxString buildFullReference( const SCH_REFERENCE& aItem, int aUnitNumber = -1 )
290{
291 wxString fullref;
292 fullref = aItem.GetRef() + aItem.GetRefNumber();
293
294 if( aUnitNumber < 0 )
295 fullref << ".." << aItem.GetUnit();
296 else
297 fullref << ".." << aUnitNumber;
298
299 return fullref;
300}
301
302
304 ANNOTATE_ALGO_T aAlgoOption,
305 int aStartNumber,
306 const SCH_REFERENCE_LIST& aAdditionalRefs,
307 bool aStartAtCurrent,
308 SCH_SHEET_LIST* aHierarchy )
309{
311
312 // All multi-unit symbols always locked to ensure consistent re-annotation
313 SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
314
315 for( size_t i = 0; i < GetCount(); i++ )
316 {
317 SCH_REFERENCE& ref = m_flatList[i];
318 wxString refstr = ref.GetSymbol()->GetRef( &ref.GetSheetPath() );
319
320 // Update sheet numbers based on the reference's sheet's position within the full
321 // hierarchy; we do this now before we annotate so annotation by sheet number * X
322 // works correctly.
323 if( aHierarchy )
324 {
325 SCH_SHEET_PATH* path = aHierarchy->FindSheetForPath( &ref.GetSheetPath() );
326 wxCHECK2_MSG( path, continue,
327 wxS( "Attempting to annotate item on sheet not part of the "
328 "hierarchy?" ) );
329
330 ref.SetSheetNumber( path->GetPageNumberAsInt() );
331 }
332
333 // Never lock unassigned references
334 if( refstr[refstr.Len() - 1] == '?' )
335 continue;
336
337 ref.m_isNew = true; // We want to reannotate all references
338
339 lockedSymbols[refstr].AddItem( ref );
340 }
341
342 AnnotateByOptions( aSortOption, aAlgoOption, aStartNumber, lockedSymbols, aAdditionalRefs,
343 aStartAtCurrent );
344}
345
346
347void SCH_REFERENCE_LIST::ReannotateDuplicates( const SCH_REFERENCE_LIST& aAdditionalReferences, ANNOTATE_ALGO_T aAlgoOption )
348{
349 ReannotateByOptions( UNSORTED, aAlgoOption, 0, aAdditionalReferences, true, nullptr );
350}
351
352
354 ANNOTATE_ALGO_T aAlgoOption,
355 int aStartNumber,
356 const SCH_MULTI_UNIT_REFERENCE_MAP& aLockedUnitMap,
357 const SCH_REFERENCE_LIST& aAdditionalRefs,
358 bool aStartAtCurrent )
359{
360 switch( aSortOption )
361 {
362 default:
365 }
366
367 bool useSheetNum;
368 int idStep;
369
370 switch( aAlgoOption )
371 {
372 default:
374 useSheetNum = false;
375 idStep = 1;
376 break;
377
379 useSheetNum = true;
380 idStep = 100;
381 aStartAtCurrent = false; // Not implemented for sheet # * 100
382 break;
383
385 useSheetNum = true;
386 idStep = 1000;
387 aStartAtCurrent = false; // Not implemented for sheet # * 1000
388 break;
389 }
390
391 Annotate( useSheetNum, idStep, aStartNumber, aLockedUnitMap, aAdditionalRefs, aStartAtCurrent );
392}
393
394
395void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
396 const SCH_MULTI_UNIT_REFERENCE_MAP& aLockedUnitMap,
397 const SCH_REFERENCE_LIST& aAdditionalRefs,
398 bool aStartAtCurrent )
399{
400 if( !m_refDesTracker )
401 {
402 wxLogError( wxS( "No reference tracker set for SCH_REFERENCE_LIST::Annotate()" ) );
403 return;
404 }
405
406 if ( m_flatList.size() == 0 )
407 return;
408
409 size_t originalSize = GetCount();
410
411 // For multi units symbols, store the list of already used full references.
412 // The algorithm tries to allocate the new reference to symbols having the same
413 // old reference.
414 // This algo works fine as long as the previous annotation has no duplicates.
415 // But when a hierarchy is reannotated with this option, the previous annotation can
416 // have duplicate references, and obviously we must fix these duplicate.
417 // therefore do not try to allocate a full reference more than once when trying
418 // to keep this order of multi units.
419 // inUseRefs keep trace of previously allocated references
420 std::unordered_set<wxString> inUseRefs;
421
422 for( size_t i = 0; i < aAdditionalRefs.GetCount(); i++ )
423 {
424 SCH_REFERENCE additionalRef = aAdditionalRefs[i];
425 additionalRef.Split();
426
427 // Add the additional reference to the multi-unit set if annotated
428 if( !additionalRef.m_isNew )
429 inUseRefs.insert( buildFullReference( additionalRef ) );
430
431 // We don't want to reannotate the additional references even if not annotated
432 // so we change the m_isNew flag to be false after splitting
433 additionalRef.m_isNew = false;
434 AddItem( additionalRef ); //add to this container
435 }
436
437 int LastReferenceNumber = 0;
438
439 /* calculate index of the first symbol with the same reference prefix
440 * than the current symbol. All symbols having the same reference
441 * prefix will receive a reference number with consecutive values:
442 * IC .. will be set to IC4, IC4, IC5 ...
443 */
444 unsigned first = 0;
445
446 // calculate the last used number for this reference prefix:
447 int minRefId;
448
449 // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
450 if( aUseSheetNum )
451 minRefId = m_flatList[first].m_sheetNum * aSheetIntervalId + 1;
452 else
453 minRefId = aStartNumber + 1;
454
455
456 for( unsigned ii = 0; ii < m_flatList.size(); ii++ )
457 {
458 auto& ref_unit = m_flatList[ii];
459
460 if( ref_unit.m_flag )
461 continue;
462
463 // Check whether this symbol is in aLockedUnitMap.
464 const SCH_REFERENCE_LIST* lockedList = nullptr;
465
466 for( const SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
467 {
468 unsigned n_refs = pair.second.GetCount();
469
470 for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
471 {
472 const SCH_REFERENCE &thisRef = pair.second[thisRefI];
473
474 if( thisRef.IsSameInstance( ref_unit ) )
475 {
476 lockedList = &pair.second;
477 break;
478 }
479 }
480
481 if( lockedList != nullptr )
482 break;
483 }
484
485 if( ( m_flatList[first].CompareRef( ref_unit ) != 0 )
486 || ( aUseSheetNum && ( m_flatList[first].m_sheetNum != ref_unit.m_sheetNum ) ) )
487 {
488 // New reference found: we need a new ref number for this reference
489 first = ii;
490
491 // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
492 if( aUseSheetNum )
493 minRefId = ref_unit.m_sheetNum * aSheetIntervalId + 1;
494 else
495 minRefId = aStartNumber + 1;
496 }
497
498 // Find references greater than current reference (unless not annotated)
499 if( aStartAtCurrent && ref_unit.m_numRef > 0 )
500 minRefId = ref_unit.m_numRef;
501
502 wxCHECK( ref_unit.GetLibPart(), /* void */ );
503
504 // Annotation of one part per package symbols (trivial case).
505 if( ref_unit.GetLibPart()->GetUnitCount() <= 1 )
506 {
507 if( ref_unit.m_isNew )
508 {
509 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, {} );
510 ref_unit.m_numRef = LastReferenceNumber;
511 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
512 }
513
514 ref_unit.m_flag = 1;
515 ref_unit.m_isNew = false;
516 continue;
517 }
518
519 // If this symbol is in aLockedUnitMap, copy the annotation to all
520 // symbols that are not it
521 if( lockedList != nullptr )
522 {
523 unsigned n_refs = lockedList->GetCount();
524 std::vector<int> units = lockedList->GetUnitsMatchingRef( ref_unit );
525
526 if( ref_unit.m_isNew )
527 {
528 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, units );
529 ref_unit.m_numRef = LastReferenceNumber;
530 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
531 ref_unit.m_isNew = false;
532 ref_unit.m_flag = 1;
533 }
534
535 for( unsigned lockedRefI = 0; lockedRefI < n_refs; ++lockedRefI )
536 {
537 const SCH_REFERENCE& lockedRef = ( *lockedList )[lockedRefI];
538
539 if( lockedRef.IsSameInstance( ref_unit ) )
540 {
541 // This is the symbol we're currently annotating. Hold the unit!
542 ref_unit.m_unit = lockedRef.m_unit;
543
544 // lock this new full reference
545 inUseRefs.insert( buildFullReference( ref_unit ) );
546 }
547
548 if( lockedRef.CompareValue( ref_unit ) != 0 )
549 continue;
550
551 if( lockedRef.CompareLibName( ref_unit ) != 0 )
552 continue;
553
554 // Find the matching symbol
555 for( unsigned jj = ii + 1; jj < m_flatList.size(); jj++ )
556 {
557 if( !lockedRef.IsSameInstance( m_flatList[jj] ) )
558 continue;
559
560 wxString ref_candidate = buildFullReference( ref_unit, lockedRef.m_unit );
561
562 // propagate the new reference and unit selection to the "old" symbol,
563 // if this new full reference is not already used (can happens when initial
564 // multiunits symbols have duplicate references)
565 if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
566 {
567 m_flatList[jj].m_numRef = ref_unit.m_numRef;
568 m_flatList[jj].m_numRefStr = ref_unit.m_numRefStr;
569 m_flatList[jj].m_isNew = false;
570 m_flatList[jj].m_flag = 1;
571
572 // lock this new full reference
573 inUseRefs.insert( ref_candidate );
574 break;
575 }
576 }
577 }
578 }
579 else if( ref_unit.m_isNew )
580 {
581 // Reference belonging to multi-unit symbol that has not yet been annotated. We don't
582 // know what group this might belong to, so just find the first unused reference for
583 // this specific unit. The other units will be annotated in the following passes.
584 std::vector<int> units = { ref_unit.GetUnit() };
585 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, units );
586 ref_unit.m_numRef = LastReferenceNumber;
587 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
588 ref_unit.m_isNew = false;
589 ref_unit.m_flag = 1;
590 }
591 }
592
593 // Remove aAdditionalRefs references
594 m_flatList.erase( m_flatList.begin() + originalSize, m_flatList.end() );
595
596 wxASSERT( originalSize == GetCount() ); // Make sure we didn't make a mistake
597}
598
599
601{
602 int error = 0;
603 wxString tmp;
604 wxString tmp2;
605 wxString msg;
606
608
609 // Split reference designators into name (prefix) and number: IC1 becomes IC, and 1.
611
612 // count not yet annotated items or annotation error.
613 for( unsigned ii = 0; ii < m_flatList.size(); ii++ )
614 {
615 msg.Empty();
616 tmp.Empty();
617
618 if( m_flatList[ii].m_isNew ) // Not yet annotated
619 {
620 if( m_flatList[ii].m_numRef >= 0 )
621 tmp << m_flatList[ii].m_numRefStr;
622 else
623 tmp = wxT( "?" );
624
625 if( ( m_flatList[ii].m_unit > 0 ) && ( m_flatList[ii].m_unit < 0x7FFFFFFF )
626 && m_flatList[ii].GetLibPart()->GetUnitCount() > 1 )
627 {
628 msg.Printf( _( "Item not annotated: %s%s (unit %d)" ),
629 m_flatList[ii].GetRef(),
630 tmp,
631 m_flatList[ii].m_unit );
632 }
633 else
634 {
635 msg.Printf( _( "Item not annotated: %s%s" ), m_flatList[ii].GetRef(), tmp );
636 }
637
638 aHandler( ERCE_UNANNOTATED, msg, &m_flatList[ii], nullptr );
639 error++;
640 break;
641 }
642
643 // Error if unit number selected does not exist (greater than the number of units in
644 // the symbol). This can happen if a symbol has changed in a library after a
645 // previous annotation.
646 if( std::max( m_flatList[ii].GetLibPart()->GetUnitCount(), 1 ) < m_flatList[ii].m_unit )
647 {
648 if( m_flatList[ii].m_numRef >= 0 )
649 tmp << m_flatList[ii].m_numRefStr;
650 else
651 tmp = wxT( "?" );
652
653 msg.Printf( _( "Error: symbol %s%s%s (unit %d) exceeds units defined (%d)" ),
654 m_flatList[ii].GetRef(),
655 tmp,
656 m_flatList[ii].GetSymbol()->SubReference( m_flatList[ii].GetUnit() ),
657 m_flatList[ii].m_unit,
658 m_flatList[ii].GetLibPart()->GetUnitCount() );
659
660 aHandler( ERCE_EXTRA_UNITS, msg, &m_flatList[ii], nullptr );
661 error++;
662 break;
663 }
664 }
665
666 // count the duplicated elements (if all are annotated)
667 int imax = m_flatList.size() - 1;
668
669 for( int ii = 0; ii < imax; ii++ )
670 {
671 msg.Empty();
672 tmp.Empty();
673 tmp2.Empty();
674
675 SCH_REFERENCE& first = m_flatList[ii];
676 SCH_REFERENCE& second = m_flatList[ii + 1];
677
678 if( ( first.CompareRef( second ) != 0 )
679 || ( first.m_numRef != second.m_numRef ) )
680 {
681 continue;
682 }
683
684 // Same reference found. If same unit, error!
685 if( first.m_unit == second.m_unit )
686 {
687 if( first.m_numRef >= 0 )
688 tmp << first.m_numRefStr;
689 else
690 tmp = wxT( "?" );
691
692 msg.Printf( _( "Duplicate items %s%s%s\n" ),
693 first.GetRef(),
694 tmp,
695 first.GetLibPart()->GetUnitCount() > 1 ? first.GetSymbol()->SubReference( first.GetUnit() )
696 : wxString( wxT( "" ) ) );
697
698 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &m_flatList[ii+1] );
699 error++;
700 continue;
701 }
702
703 /* Test error if units are different but number of parts per package
704 * too high (ex U3 ( 1 part) and we find U3B this is an error) */
705 if( first.GetLibPart()->GetUnitCount() != second.GetLibPart()->GetUnitCount() )
706 {
707 if( first.m_numRef >= 0 )
708 tmp << first.m_numRefStr;
709 else
710 tmp = wxT( "?" );
711
712 if( second.m_numRef >= 0 )
713 tmp2 << second.m_numRefStr;
714 else
715 tmp2 = wxT( "?" );
716
717 msg.Printf( _( "Differing unit counts for item %s%s%s and %s%s%s\n" ),
718 first.GetRef(),
719 tmp,
720 first.GetSymbol()->SubReference( first.GetUnit() ),
721 second.GetRef(),
722 tmp2,
723 first.GetSymbol()->SubReference( second.GetUnit() ) );
724
725 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &second );
726 error++;
727 continue;
728 }
729
730 // Error if values are different between units, for the same reference
731 if( first.CompareValue( second ) != 0 )
732 {
733 msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
734 first.GetRef(),
735 first.m_numRef,
736 first.GetSymbol()->SubReference( first.GetUnit() ),
737 first.m_value,
738 second.GetRef(),
739 second.m_numRef,
740 first.GetSymbol()->SubReference( second.GetUnit() ),
741 second.m_value );
742
743 aHandler( ERCE_DIFFERENT_UNIT_VALUE, msg, &first, &second );
744 error++;
745 }
746 }
747
748 return error;
749}
750
751
753{
754 wxASSERT( aSymbol != nullptr );
755
756 m_rootSymbol = aSymbol;
757 m_unit = aSymbol->GetUnitSelection( &aSheetPath );
758 m_footprint = aSymbol->GetFootprintFieldText( true, &aSheetPath, false );
759 m_sheetPath = aSheetPath;
760 m_isNew = false;
761 m_flag = 0;
762 m_symbolUuid = aSymbol->m_Uuid;
763 m_symbolPos = aSymbol->GetPosition();
764 m_sheetNum = 0;
765
766 if( aSymbol->GetRef( &aSheetPath ).IsEmpty() )
767 aSymbol->SetRef( &aSheetPath, wxT( "DefRef?" ) );
768
769 wxString ref = aSymbol->GetRef( &aSheetPath );
770 SetRef( ref );
771
772 m_numRef = -1;
773
774 if( aSymbol->GetValue( false, &aSheetPath, false ).IsEmpty() )
775 aSymbol->SetValueFieldText( wxT( "~" ) );
776
777 m_value = aSymbol->GetValue( false, &aSheetPath, false );
778}
779
780
782{
783 if( m_numRef < 0 )
784 m_ref += '?';
785 else
786 m_ref = TO_UTF8( GetRef() << GetRefNumber() );
787
788 m_rootSymbol->SetRef( &m_sheetPath, From_UTF8( m_ref.c_str() ) );
789 m_rootSymbol->SetUnit( m_unit );
790 m_rootSymbol->SetUnitSelection( &m_sheetPath, m_unit );
791}
792
793
795{
796 wxCHECK( m_rootSymbol && m_rootSymbol->GetLibSymbolRef()
797 && !m_rootSymbol->GetRef( &m_sheetPath ).IsEmpty(), false );
798
799 return m_rootSymbol->GetLibSymbolRef()->IsPower()
800 || m_rootSymbol->GetRef( &m_sheetPath )[0] == wxUniChar( '#' );
801}
802
803
805{
806 std::string refText = GetRefStr();
807
808 m_numRef = -1;
809 m_numRefStr.Clear();
810
811 int ll = refText.length() - 1;
812
813 if( refText[ll] == '?' )
814 {
815 m_isNew = true;
816
817 refText.erase( ll ); // delete last char
818
819 SetRefStr( refText );
820 }
821 else if( isdigit( refText[ll] ) == 0 )
822 {
823 m_isNew = true;
824 }
825 else
826 {
827 while( ll >= 0 )
828 {
829 if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) )
830 {
831 ll--;
832 }
833 else
834 {
835 if( isdigit( refText[ll + 1] ) )
836 {
837 // null terminated C string into cp
838 const char* cp = refText.c_str() + ll + 1;
839
840 m_numRef = atoi( cp );
841 }
842
843 m_numRefStr = std::string( refText, ll + 1 );
844 refText.erase( ll + 1 );
845 break;
846 }
847 }
848
849 SetRefStr( refText );
850 }
851}
852
853
855{
856 std::string refText = GetRefStr();
857
858 if( refText.empty() )
859 return false;
860
861 int ll = refText.length() - 1;
862
863 return ( refText[ll] == '?' ) || isdigit( refText[ll] );
864}
865
866
867wxString SCH_REFERENCE_LIST::Shorthand( std::vector<SCH_REFERENCE> aList,
868 const wxString& refDelimiter,
869 const wxString& refRangeDelimiter )
870{
871 wxString retVal;
872 size_t i = 0;
873
874 while( i < aList.size() )
875 {
876 wxString ref = aList[ i ].GetRef();
877 int numRef = aList[ i ].m_numRef;
878
879 size_t range = 1;
880
881 while( i + range < aList.size()
882 && aList[ i + range ].GetRef() == ref
883 && aList[ i + range ].m_numRef == int( numRef + range ) )
884 {
885 range++;
886
887 if( range == 2 && refRangeDelimiter.IsEmpty() )
888 break;
889 }
890
891 if( !retVal.IsEmpty() )
892 retVal << refDelimiter;
893
894 if( range == 1 )
895 {
896 retVal << ref << aList[ i ].GetRefNumber();
897 }
898 else if( range == 2 || refRangeDelimiter.IsEmpty() )
899 {
900 retVal << ref << aList[ i ].GetRefNumber();
901 retVal << refDelimiter;
902 retVal << ref << aList[ i + 1 ].GetRefNumber();
903 }
904 else
905 {
906 retVal << ref << aList[ i ].GetRefNumber();
907 retVal << refRangeDelimiter;
908 retVal << ref << aList[ i + ( range - 1 ) ].GetRefNumber();
909 }
910
911 i+= range;
912 }
913
914 return retVal;
915}
916
917
918wxString SCH_REFERENCE::formatRefStr( int aNumber ) const
919{
920 // To avoid a risk of duplicate, for power symbols the ref number is 0nnn instead of nnn.
921 // Just because sometimes only power symbols are annotated
922 if( GetSymbol() && GetLibPart() && GetLibPart()->IsPower() )
923 return wxString::Format( "0%d", aNumber );
924
925 return wxString::Format( "%d", aNumber );
926}
927
928
929#if defined( DEBUG )
930void SCH_REFERENCE_LIST::Show( const char* aPrefix )
931{
932 printf( "%s\n", aPrefix );
933
934 for( unsigned i = 0; i < m_flatList.size(); ++i )
935 {
936 SCH_REFERENCE& schref = m_flatList[i];
937
938 printf( " [%-2d] ref:%-8s num:%-3d lib_part:%s\n", i, schref.m_ref.ToStdString().c_str(),
939 schref.m_numRef, TO_UTF8( schref.GetLibPart()->GetName() ) );
940 }
941}
942#endif
const KIID m_Uuid
Definition eda_item.h:516
wxString GetName() const override
Definition lib_symbol.h:148
int GetUnitCount() const override
void ReannotateByOptions(ANNOTATE_ORDER_T aSortOption, ANNOTATE_ALGO_T aAlgoOption, int aStartNumber, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent, SCH_SHEET_LIST *aHierarchy)
Forces reannotation of the provided references.
static bool sortByRefAndValue(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
static bool sortBySymbolPtr(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
bool Contains(const SCH_REFERENCE &aItem) const
Return true if aItem exists in this list.
void AnnotateByOptions(enum ANNOTATE_ORDER_T aSortOption, enum ANNOTATE_ALGO_T aAlgoOption, int aStartNumber, const SCH_MULTI_UNIT_REFERENCE_MAP &aLockedUnitMap, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent)
Annotate the references by the provided options.
void Annotate(bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, const SCH_MULTI_UNIT_REFERENCE_MAP &aLockedUnitMap, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent=false)
Set the reference designators in the list that have not been annotated.
void SortByYCoordinate()
Sort the list of references by Y position.
static bool sortByTimeStamp(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
int FindRef(const wxString &aPath) const
Search the list for a symbol with a given reference.
void SortByXCoordinate()
Sort the list of references by X position.
static bool sortByXPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
int FindFirstUnusedReference(const SCH_REFERENCE &aRef, int aMinValue, const std::vector< int > &aRequiredUnits) const
Return the first unused reference number from the properties given in aRef, ensuring all of the units...
void SplitReferences()
Attempt to split all reference designators into a name (U) and number (1).
std::shared_ptr< REFDES_TRACKER > m_refDesTracker
A list of previously used reference designators.
void SortByRefAndValue()
Sort the list of references by value.
std::vector< int > GetUnitsMatchingRef(const SCH_REFERENCE &aRef) const
Return all the unit numbers for a given reference, comparing library reference, value,...
std::vector< SCH_REFERENCE > m_flatList
static bool sortByReferenceOnly(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
void GetRefsInUse(int aIndex, std::vector< int > &aIdList, int aMinRefId) const
Add all the reference designator numbers greater than aMinRefId to aIdList skipping the reference at ...
static wxString Shorthand(std::vector< SCH_REFERENCE > aList, const wxString &refDelimiter, const wxString &refRangeDelimiter)
Return a shorthand string representing all the references in the list.
int FindRefByFullPath(const wxString &aFullPath) const
Search the list for a symbol with the given KIID path (as string).
std::vector< SCH_SYMBOL_INSTANCE > GetSymbolInstances() const
void AddItem(const SCH_REFERENCE &aItem)
void RemoveItem(unsigned int aIndex)
Remove an item from the list of references.
void ReannotateDuplicates(const SCH_REFERENCE_LIST &aAdditionalReferences, ANNOTATE_ALGO_T aAlgoOption)
Convenience function for the Paste Unique functionality.
static bool sortByYPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
int CheckAnnotation(ANNOTATION_ERROR_HANDLER aErrorHandler)
Check for annotations errors.
A helper to define a symbol's reference designator in a schematic.
const SCH_SHEET_PATH & GetSheetPath() const
SCH_SYMBOL * m_rootSymbol
The symbol associated the reference object.
int m_unit
The unit number for symbol with multiple parts per package.
SCH_SHEET_PATH m_sheetPath
The sheet path for this reference.
wxString m_footprint
The footprint assigned.
wxString formatRefStr(int aNumber) const
int CompareLibName(const SCH_REFERENCE &item) const
int CompareRef(const SCH_REFERENCE &item) const
void SetRef(const wxString &aReference)
bool AlwaysAnnotate() const
Verify the reference should always be automatically annotated.
wxString m_numRefStr
The numeric part in original string form (may have leading zeroes).
bool m_isNew
True if not yet annotated.
void Split()
Attempt to split the reference designator into a name (U) and number (1).
bool IsSplitNeeded()
Determine if this reference needs to be split or if it likely already has been.
SCH_SYMBOL * GetSymbol() const
wxString m_ref
Symbol reference prefix, without number (for IC1, this is IC) )
wxString GetRef() const
int m_sheetNum
The sheet number for the reference.
void SetRefStr(const std::string &aReference)
int m_numRef
The numeric part of the reference designator.
LIB_SYMBOL * GetLibPart() const
void SetSheetNumber(int aSheetNumber)
const char * GetRefStr() const
bool IsSameInstance(const SCH_REFERENCE &other) const
Return whether this reference refers to the same symbol instance (symbol and sheet) as another.
KIID m_symbolUuid
UUID of the symbol.
wxString m_value
The symbol value.
VECTOR2I m_symbolPos
The physical position of the symbol in schematic used to annotate by X or Y position.
wxString GetRefNumber() const
int CompareValue(const SCH_REFERENCE &item) const
void Annotate()
Update the annotation of the symbol according the current object state.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
SCH_SHEET_PATH * FindSheetForPath(const SCH_SHEET_PATH *aPath)
Return a pointer to the first SCH_SHEET_PATH object (not necessarily the only one) matching the provi...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
int Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare if this is the same sheet path as aSheetPathToTest.
Schematic symbol object.
Definition sch_symbol.h:75
wxString SubReference(int aUnit, bool aAddSeparator=true) const
void SetValueFieldText(const wxString &aValue)
const wxString GetValue(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const override
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
const wxString GetFootprintFieldText(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const
VECTOR2I GetPosition() const override
Definition sch_symbol.h:760
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
#define _(s)
@ ERCE_UNANNOTATED
Symbol has not been annotated.
@ ERCE_DUPLICATE_REFERENCE
More than one symbol with the same reference.
@ ERCE_EXTRA_UNITS
Symbol has more units than are defined.
@ ERCE_DIFFERENT_UNIT_VALUE
Units of same symbol have different values.
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
Definition kicad_algo.h:161
wxString buildFullReference(const SCH_REFERENCE &aItem, int aUnitNumber=-1)
std::function< void(ERCE_T aType, const wxString &aMsg, SCH_REFERENCE *aItemA, SCH_REFERENCE *aItemB)> ANNOTATION_ERROR_HANDLER
Define a standard error handler for annotation errors.
ANNOTATE_ORDER_T
Schematic annotation order options.
@ UNSORTED
Annotate by position of symbol in the schematic sheet object list.
@ SORT_BY_X_POSITION
Annotate by X position from left to right.
@ SORT_BY_Y_POSITION
Annotate by Y position from top to bottom.
ANNOTATE_ALGO_T
Schematic annotation type options.
@ SHEET_NUMBER_X_1000
Annotate using the first free reference number starting at the sheet number * 1000.
@ INCREMENTAL_BY_REF
Annotate incrementally using the first free reference number.
@ SHEET_NUMBER_X_100
Annotate using the first free reference number starting at the sheet number * 100.
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Container to map reference designators for multi-unit parts.
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
wxString From_UTF8(const char *cstring)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
A simple container for schematic symbol instance information.