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
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
159int SCH_REFERENCE_LIST::FindRefByFullPath( const wxString& aFullPath ) const
160{
161 for( size_t i = 0; i < m_flatList.size(); ++i )
162 {
163 if( m_flatList[i].GetFullPath() == aFullPath )
164 return i;
165 }
166
167 return -1;
168}
169
170
171int SCH_REFERENCE_LIST::FindRef( const wxString& aRef ) const
172{
173 for( size_t i = 0; i < m_flatList.size(); ++i )
174 {
175 if( m_flatList[i].GetRef() == aRef )
176 return i;
177 }
178
179 return -1;
180}
181
182
183void SCH_REFERENCE_LIST::GetRefsInUse( int aIndex, std::vector< int >& aIdList,
184 int aMinRefId ) const
185{
186 aIdList.clear();
187
188 for( const SCH_REFERENCE& ref : m_flatList )
189 {
190 // Don't add new references to the list as we will reannotate those
191 if( m_flatList[aIndex].CompareRef( ref ) == 0 && ref.m_numRef >= aMinRefId && !ref.m_isNew )
192 aIdList.push_back( ref.m_numRef );
193 }
194
195 std::sort( aIdList.begin(), aIdList.end() );
196
197 // Ensure each reference number appears only once. If there are symbols with
198 // multiple parts per package the same number will be stored for each part.
199 alg::remove_duplicates( aIdList );
200}
201
202
203std::vector<int> SCH_REFERENCE_LIST::GetUnitsMatchingRef( const SCH_REFERENCE& aRef ) const
204{
205 std::vector<int> unitsList;
206
207 // Always add this reference to the list
208 unitsList.push_back( aRef.m_unit );
209
210 for( SCH_REFERENCE ref : m_flatList )
211 {
212 if( ref.CompareValue( aRef ) != 0 )
213 continue;
214
215 if( ref.CompareLibName( aRef ) != 0 )
216 continue;
217
218 // Split if needed before comparing ref and number
219 if( ref.IsSplitNeeded() )
220 ref.Split();
221
222 if( ref.CompareRef( aRef ) != 0 )
223 continue;
224
225 if( ref.m_numRef != aRef.m_numRef )
226 continue;
227
228 unitsList.push_back( ref.m_unit );
229 }
230
231 std::sort( unitsList.begin(), unitsList.end() );
232
233 // Ensure each reference number appears only once. If there are symbols with
234 // multiple parts per package the same number will be stored for each part.
235 alg::remove_duplicates( unitsList );
236
237 return unitsList;
238}
239
240
242 const std::vector<int>& aRequiredUnits ) const
243{
244 // Create a map of references indexed by reference number, only including those with the same
245 // reference prefix as aRef
246 std::map<int, std::vector<SCH_REFERENCE>> refNumberMap;
247
248 for( const SCH_REFERENCE& ref : m_flatList )
249 {
250 // search only for the current reference prefix:
251 if( ref.CompareRef( aRef ) != 0 )
252 continue;
253
254 if( ref.m_isNew )
255 continue; // It will be reannotated
256
257 refNumberMap[ref.m_numRef].push_back( ref );
258 }
259
260 return m_refDesTracker->GetNextRefDesForUnits( aRef, refNumberMap, aRequiredUnits, aMinValue );
261}
262
263
264std::vector<SCH_SYMBOL_INSTANCE> SCH_REFERENCE_LIST::GetSymbolInstances() const
265{
266 std::vector<SCH_SYMBOL_INSTANCE> retval;
267
268 for( const SCH_REFERENCE& ref : m_flatList )
269 {
270 SCH_SYMBOL_INSTANCE instance;
271 instance.m_Path = ref.GetSheetPath().Path();
272 instance.m_Reference = ref.GetRef();
273 instance.m_Unit = ref.GetUnit();
274
275 retval.push_back( instance );
276 }
277
278 return retval;
279}
280
281
282// A helper function to build a full reference string of a SCH_REFERENCE item
283wxString buildFullReference( const SCH_REFERENCE& aItem, int aUnitNumber = -1 )
284{
285 wxString fullref;
286 fullref = aItem.GetRef() + aItem.GetRefNumber();
287
288 if( aUnitNumber < 0 )
289 fullref << ".." << aItem.GetUnit();
290 else
291 fullref << ".." << aUnitNumber;
292
293 return fullref;
294}
295
296
298 ANNOTATE_ALGO_T aAlgoOption,
299 int aStartNumber,
300 const SCH_REFERENCE_LIST& aAdditionalRefs,
301 bool aStartAtCurrent,
302 SCH_SHEET_LIST* aHierarchy )
303{
305
306 // All multi-unit symbols always locked to ensure consistent re-annotation
307 SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
308
309 for( size_t i = 0; i < GetCount(); i++ )
310 {
311 SCH_REFERENCE& ref = m_flatList[i];
312 wxString refstr = ref.GetSymbol()->GetRef( &ref.GetSheetPath() );
313
314 // Update sheet numbers based on the reference's sheet's position within the full
315 // hierarchy; we do this now before we annotate so annotation by sheet number * X
316 // works correctly.
317 if( aHierarchy )
318 {
319 SCH_SHEET_PATH* path = aHierarchy->FindSheetForPath( &ref.GetSheetPath() );
320 wxCHECK2_MSG( path, continue,
321 wxS( "Attempting to annotate item on sheet not part of the "
322 "hierarchy?" ) );
323
324 ref.SetSheetNumber( path->GetVirtualPageNumber() );
325 }
326
327 // Never lock unassigned references
328 if( refstr[refstr.Len() - 1] == '?' )
329 continue;
330
331 ref.m_isNew = true; // We want to reannotate all references
332
333 lockedSymbols[refstr].AddItem( ref );
334 }
335
336 AnnotateByOptions( aSortOption, aAlgoOption, aStartNumber, lockedSymbols, aAdditionalRefs,
337 aStartAtCurrent );
338}
339
340
342{
343 ReannotateByOptions( UNSORTED, INCREMENTAL_BY_REF, 0, aAdditionalReferences, true, nullptr );
344}
345
346
348 ANNOTATE_ALGO_T aAlgoOption,
349 int aStartNumber,
350 const SCH_MULTI_UNIT_REFERENCE_MAP& aLockedUnitMap,
351 const SCH_REFERENCE_LIST& aAdditionalRefs,
352 bool aStartAtCurrent )
353{
354 switch( aSortOption )
355 {
356 default:
359 }
360
361 bool useSheetNum;
362 int idStep;
363
364 switch( aAlgoOption )
365 {
366 default:
368 useSheetNum = false;
369 idStep = 1;
370 break;
371
373 useSheetNum = true;
374 idStep = 100;
375 aStartAtCurrent = false; // Not implemented for sheet # * 100
376 break;
377
379 useSheetNum = true;
380 idStep = 1000;
381 aStartAtCurrent = false; // Not implemented for sheet # * 1000
382 break;
383 }
384
385 Annotate( useSheetNum, idStep, aStartNumber, aLockedUnitMap, aAdditionalRefs, aStartAtCurrent );
386}
387
388
389void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
390 const SCH_MULTI_UNIT_REFERENCE_MAP& aLockedUnitMap,
391 const SCH_REFERENCE_LIST& aAdditionalRefs,
392 bool aStartAtCurrent )
393{
394 if( !m_refDesTracker )
395 {
396 wxLogError( wxS( "No reference tracker set for SCH_REFERENCE_LIST::Annotate()" ) );
397 return;
398 }
399
400 if ( m_flatList.size() == 0 )
401 return;
402
403 size_t originalSize = GetCount();
404
405 // For multi units symbols, store the list of already used full references.
406 // The algorithm tries to allocate the new reference to symbols having the same
407 // old reference.
408 // This algo works fine as long as the previous annotation has no duplicates.
409 // But when a hierarchy is reannotated with this option, the previous annotation can
410 // have duplicate references, and obviously we must fix these duplicate.
411 // therefore do not try to allocate a full reference more than once when trying
412 // to keep this order of multi units.
413 // inUseRefs keep trace of previously allocated references
414 std::unordered_set<wxString> inUseRefs;
415
416 for( size_t i = 0; i < aAdditionalRefs.GetCount(); i++ )
417 {
418 SCH_REFERENCE additionalRef = aAdditionalRefs[i];
419 additionalRef.Split();
420
421 // Add the additional reference to the multi-unit set if annotated
422 if( !additionalRef.m_isNew )
423 inUseRefs.insert( buildFullReference( additionalRef ) );
424
425 // We don't want to reannotate the additional references even if not annotated
426 // so we change the m_isNew flag to be false after splitting
427 additionalRef.m_isNew = false;
428 AddItem( additionalRef ); //add to this container
429 }
430
431 int LastReferenceNumber = 0;
432
433 /* calculate index of the first symbol with the same reference prefix
434 * than the current symbol. All symbols having the same reference
435 * prefix will receive a reference number with consecutive values:
436 * IC .. will be set to IC4, IC4, IC5 ...
437 */
438 unsigned first = 0;
439
440 // calculate the last used number for this reference prefix:
441 int minRefId;
442
443 // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
444 if( aUseSheetNum )
445 minRefId = m_flatList[first].m_sheetNum * aSheetIntervalId + 1;
446 else
447 minRefId = aStartNumber + 1;
448
449
450 for( unsigned ii = 0; ii < m_flatList.size(); ii++ )
451 {
452 auto& ref_unit = m_flatList[ii];
453
454 if( ref_unit.m_flag )
455 continue;
456
457 // Check whether this symbol is in aLockedUnitMap.
458 const SCH_REFERENCE_LIST* lockedList = nullptr;
459
460 for( const SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
461 {
462 unsigned n_refs = pair.second.GetCount();
463
464 for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
465 {
466 const SCH_REFERENCE &thisRef = pair.second[thisRefI];
467
468 if( thisRef.IsSameInstance( ref_unit ) )
469 {
470 lockedList = &pair.second;
471 break;
472 }
473 }
474
475 if( lockedList != nullptr )
476 break;
477 }
478
479 if( ( m_flatList[first].CompareRef( ref_unit ) != 0 )
480 || ( aUseSheetNum && ( m_flatList[first].m_sheetNum != ref_unit.m_sheetNum ) ) )
481 {
482 // New reference found: we need a new ref number for this reference
483 first = ii;
484
485 // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
486 if( aUseSheetNum )
487 minRefId = ref_unit.m_sheetNum * aSheetIntervalId + 1;
488 else
489 minRefId = aStartNumber + 1;
490 }
491
492 // Find references greater than current reference (unless not annotated)
493 if( aStartAtCurrent && ref_unit.m_numRef > 0 )
494 minRefId = ref_unit.m_numRef;
495
496 wxCHECK( ref_unit.GetLibPart(), /* void */ );
497
498 // Annotation of one part per package symbols (trivial case).
499 if( ref_unit.GetLibPart()->GetUnitCount() <= 1 )
500 {
501 if( ref_unit.m_isNew )
502 {
503 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, {} );
504 ref_unit.m_numRef = LastReferenceNumber;
505 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
506 }
507
508 ref_unit.m_flag = 1;
509 ref_unit.m_isNew = false;
510 continue;
511 }
512
513 // If this symbol is in aLockedUnitMap, copy the annotation to all
514 // symbols that are not it
515 if( lockedList != nullptr )
516 {
517 unsigned n_refs = lockedList->GetCount();
518 std::vector<int> units = lockedList->GetUnitsMatchingRef( ref_unit );
519
520 if( ref_unit.m_isNew )
521 {
522 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, units );
523 ref_unit.m_numRef = LastReferenceNumber;
524 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
525 ref_unit.m_isNew = false;
526 ref_unit.m_flag = 1;
527 }
528
529 for( unsigned lockedRefI = 0; lockedRefI < n_refs; ++lockedRefI )
530 {
531 const SCH_REFERENCE& lockedRef = ( *lockedList )[lockedRefI];
532
533 if( lockedRef.IsSameInstance( ref_unit ) )
534 {
535 // This is the symbol we're currently annotating. Hold the unit!
536 ref_unit.m_unit = lockedRef.m_unit;
537
538 // lock this new full reference
539 inUseRefs.insert( buildFullReference( ref_unit ) );
540 }
541
542 if( lockedRef.CompareValue( ref_unit ) != 0 )
543 continue;
544
545 if( lockedRef.CompareLibName( ref_unit ) != 0 )
546 continue;
547
548 // Find the matching symbol
549 for( unsigned jj = ii + 1; jj < m_flatList.size(); jj++ )
550 {
551 if( !lockedRef.IsSameInstance( m_flatList[jj] ) )
552 continue;
553
554 wxString ref_candidate = buildFullReference( ref_unit, lockedRef.m_unit );
555
556 // propagate the new reference and unit selection to the "old" symbol,
557 // if this new full reference is not already used (can happens when initial
558 // multiunits symbols have duplicate references)
559 if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
560 {
561 m_flatList[jj].m_numRef = ref_unit.m_numRef;
562 m_flatList[jj].m_numRefStr = ref_unit.m_numRefStr;
563 m_flatList[jj].m_isNew = false;
564 m_flatList[jj].m_flag = 1;
565
566 // lock this new full reference
567 inUseRefs.insert( ref_candidate );
568 break;
569 }
570 }
571 }
572 }
573 else if( ref_unit.m_isNew )
574 {
575 // Reference belonging to multi-unit symbol that has not yet been annotated. We don't
576 // know what group this might belong to, so just find the first unused reference for
577 // this specific unit. The other units will be annotated in the following passes.
578 std::vector<int> units = { ref_unit.GetUnit() };
579 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, units );
580 ref_unit.m_numRef = LastReferenceNumber;
581 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
582 ref_unit.m_isNew = false;
583 ref_unit.m_flag = 1;
584 }
585 }
586
587 // Remove aAdditionalRefs references
588 m_flatList.erase( m_flatList.begin() + originalSize, m_flatList.end() );
589
590 wxASSERT( originalSize == GetCount() ); // Make sure we didn't make a mistake
591}
592
593
595{
596 int error = 0;
597 wxString tmp;
598 wxString tmp2;
599 wxString msg;
600
602
603 // Split reference designators into name (prefix) and number: IC1 becomes IC, and 1.
605
606 // count not yet annotated items or annotation error.
607 for( unsigned ii = 0; ii < m_flatList.size(); ii++ )
608 {
609 msg.Empty();
610 tmp.Empty();
611
612 if( m_flatList[ii].m_isNew ) // Not yet annotated
613 {
614 if( m_flatList[ii].m_numRef >= 0 )
615 tmp << m_flatList[ii].m_numRefStr;
616 else
617 tmp = wxT( "?" );
618
619 if( ( m_flatList[ii].m_unit > 0 ) && ( m_flatList[ii].m_unit < 0x7FFFFFFF )
620 && m_flatList[ii].GetLibPart()->GetUnitCount() > 1 )
621 {
622 msg.Printf( _( "Item not annotated: %s%s (unit %d)" ),
623 m_flatList[ii].GetRef(),
624 tmp,
625 m_flatList[ii].m_unit );
626 }
627 else
628 {
629 msg.Printf( _( "Item not annotated: %s%s" ), m_flatList[ii].GetRef(), tmp );
630 }
631
632 aHandler( ERCE_UNANNOTATED, msg, &m_flatList[ii], nullptr );
633 error++;
634 break;
635 }
636
637 // Error if unit number selected does not exist (greater than the number of units in
638 // the symbol). This can happen if a symbol has changed in a library after a
639 // previous annotation.
640 if( std::max( m_flatList[ii].GetLibPart()->GetUnitCount(), 1 ) < m_flatList[ii].m_unit )
641 {
642 if( m_flatList[ii].m_numRef >= 0 )
643 tmp << m_flatList[ii].m_numRefStr;
644 else
645 tmp = wxT( "?" );
646
647 msg.Printf( _( "Error: symbol %s%s%s (unit %d) exceeds units defined (%d)" ),
648 m_flatList[ii].GetRef(),
649 tmp,
650 m_flatList[ii].GetSymbol()->SubReference( m_flatList[ii].GetUnit() ),
651 m_flatList[ii].m_unit,
652 m_flatList[ii].GetLibPart()->GetUnitCount() );
653
654 aHandler( ERCE_EXTRA_UNITS, msg, &m_flatList[ii], nullptr );
655 error++;
656 break;
657 }
658 }
659
660 // count the duplicated elements (if all are annotated)
661 int imax = m_flatList.size() - 1;
662
663 for( int ii = 0; ii < imax; ii++ )
664 {
665 msg.Empty();
666 tmp.Empty();
667 tmp2.Empty();
668
669 SCH_REFERENCE& first = m_flatList[ii];
670 SCH_REFERENCE& second = m_flatList[ii + 1];
671
672 if( ( first.CompareRef( second ) != 0 )
673 || ( first.m_numRef != second.m_numRef ) )
674 {
675 continue;
676 }
677
678 // Same reference found. If same unit, error!
679 if( first.m_unit == second.m_unit )
680 {
681 if( first.m_numRef >= 0 )
682 tmp << first.m_numRefStr;
683 else
684 tmp = wxT( "?" );
685
686 msg.Printf( _( "Duplicate items %s%s%s\n" ),
687 first.GetRef(),
688 tmp,
689 first.GetLibPart()->GetUnitCount() > 1 ? first.GetSymbol()->SubReference( first.GetUnit() )
690 : wxString( wxT( "" ) ) );
691
692 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &m_flatList[ii+1] );
693 error++;
694 continue;
695 }
696
697 /* Test error if units are different but number of parts per package
698 * too high (ex U3 ( 1 part) and we find U3B this is an error) */
699 if( first.GetLibPart()->GetUnitCount() != second.GetLibPart()->GetUnitCount() )
700 {
701 if( first.m_numRef >= 0 )
702 tmp << first.m_numRefStr;
703 else
704 tmp = wxT( "?" );
705
706 if( second.m_numRef >= 0 )
707 tmp2 << second.m_numRefStr;
708 else
709 tmp2 = wxT( "?" );
710
711 msg.Printf( _( "Differing unit counts for item %s%s%s and %s%s%s\n" ),
712 first.GetRef(),
713 tmp,
714 first.GetSymbol()->SubReference( first.GetUnit() ),
715 second.GetRef(),
716 tmp2,
717 first.GetSymbol()->SubReference( second.GetUnit() ) );
718
719 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &second );
720 error++;
721 continue;
722 }
723
724 // Error if values are different between units, for the same reference
725 if( first.CompareValue( second ) != 0 )
726 {
727 msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
728 first.GetRef(),
729 first.m_numRef,
730 first.GetSymbol()->SubReference( first.GetUnit() ),
731 first.m_value,
732 second.GetRef(),
733 second.m_numRef,
734 first.GetSymbol()->SubReference( second.GetUnit() ),
735 second.m_value );
736
737 aHandler( ERCE_DIFFERENT_UNIT_VALUE, msg, &first, &second );
738 error++;
739 }
740 }
741
742 return error;
743}
744
745
747{
748 wxASSERT( aSymbol != nullptr );
749
750 m_rootSymbol = aSymbol;
751 m_unit = aSymbol->GetUnitSelection( &aSheetPath );
752 m_footprint = aSymbol->GetFootprintFieldText( true, &aSheetPath, false );
753 m_sheetPath = aSheetPath;
754 m_isNew = false;
755 m_flag = 0;
756 m_symbolUuid = aSymbol->m_Uuid;
757 m_symbolPos = aSymbol->GetPosition();
758 m_sheetNum = 0;
759
760 if( aSymbol->GetRef( &aSheetPath ).IsEmpty() )
761 aSymbol->SetRef( &aSheetPath, wxT( "DefRef?" ) );
762
763 wxString ref = aSymbol->GetRef( &aSheetPath );
764 SetRef( ref );
765
766 m_numRef = -1;
767
768 if( aSymbol->GetValue( false, &aSheetPath, false ).IsEmpty() )
769 aSymbol->SetValueFieldText( wxT( "~" ) );
770
771 m_value = aSymbol->GetValue( false, &aSheetPath, false );
772}
773
774
776{
777 if( m_numRef < 0 )
778 m_ref += '?';
779 else
780 m_ref = TO_UTF8( GetRef() << GetRefNumber() );
781
785}
786
787
789{
791 && !m_rootSymbol->GetRef( &m_sheetPath ).IsEmpty(), false );
792
793 return m_rootSymbol->GetLibSymbolRef()->IsPower()
794 || m_rootSymbol->GetRef( &m_sheetPath )[0] == wxUniChar( '#' );
795}
796
797
799{
800 std::string refText = GetRefStr();
801
802 m_numRef = -1;
803 m_numRefStr.Clear();
804
805 int ll = refText.length() - 1;
806
807 if( refText[ll] == '?' )
808 {
809 m_isNew = true;
810
811 refText.erase( ll ); // delete last char
812
813 SetRefStr( refText );
814 }
815 else if( isdigit( refText[ll] ) == 0 )
816 {
817 m_isNew = true;
818 }
819 else
820 {
821 while( ll >= 0 )
822 {
823 if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) )
824 {
825 ll--;
826 }
827 else
828 {
829 if( isdigit( refText[ll + 1] ) )
830 {
831 // null terminated C string into cp
832 const char* cp = refText.c_str() + ll + 1;
833
834 m_numRef = atoi( cp );
835 }
836
837 m_numRefStr = std::string( refText, ll + 1 );
838 refText.erase( ll + 1 );
839 break;
840 }
841 }
842
843 SetRefStr( refText );
844 }
845}
846
847
849{
850 std::string refText = GetRefStr();
851
852 if( refText.empty() )
853 return false;
854
855 int ll = refText.length() - 1;
856
857 return ( refText[ll] == '?' ) || isdigit( refText[ll] );
858}
859
860
861wxString SCH_REFERENCE_LIST::Shorthand( std::vector<SCH_REFERENCE> aList,
862 const wxString& refDelimiter,
863 const wxString& refRangeDelimiter )
864{
865 wxString retVal;
866 size_t i = 0;
867
868 while( i < aList.size() )
869 {
870 wxString ref = aList[ i ].GetRef();
871 int numRef = aList[ i ].m_numRef;
872
873 size_t range = 1;
874
875 while( i + range < aList.size()
876 && aList[ i + range ].GetRef() == ref
877 && aList[ i + range ].m_numRef == int( numRef + range ) )
878 {
879 range++;
880
881 if( range == 2 && refRangeDelimiter.IsEmpty() )
882 break;
883 }
884
885 if( !retVal.IsEmpty() )
886 retVal << refDelimiter;
887
888 if( range == 1 )
889 {
890 retVal << ref << aList[ i ].GetRefNumber();
891 }
892 else if( range == 2 || refRangeDelimiter.IsEmpty() )
893 {
894 retVal << ref << aList[ i ].GetRefNumber();
895 retVal << refDelimiter;
896 retVal << ref << aList[ i + 1 ].GetRefNumber();
897 }
898 else
899 {
900 retVal << ref << aList[ i ].GetRefNumber();
901 retVal << refRangeDelimiter;
902 retVal << ref << aList[ i + ( range - 1 ) ].GetRefNumber();
903 }
904
905 i+= range;
906 }
907
908 return retVal;
909}
910
911
912wxString SCH_REFERENCE::formatRefStr( int aNumber ) const
913{
914 // To avoid a risk of duplicate, for power symbols the ref number is 0nnn instead of nnn.
915 // Just because sometimes only power symbols are annotated
916 if( GetSymbol() && GetLibPart() && GetLibPart()->IsPower() )
917 return wxString::Format( "0%d", aNumber );
918
919 return wxString::Format( "%d", aNumber );
920}
921
922
923#if defined( DEBUG )
924void SCH_REFERENCE_LIST::Show( const char* aPrefix )
925{
926 printf( "%s\n", aPrefix );
927
928 for( unsigned i = 0; i < m_flatList.size(); ++i )
929 {
930 SCH_REFERENCE& schref = m_flatList[i];
931
932 printf( " [%-2d] ref:%-8s num:%-3d lib_part:%s\n", i, schref.m_ref.ToStdString().c_str(),
933 schref.m_numRef, TO_UTF8( schref.GetLibPart()->GetName() ) );
934 }
935}
936#endif
const KIID m_Uuid
Definition: eda_item.h:516
wxString GetName() const override
Definition: lib_symbol.h:149
int GetUnitCount() const override
virtual void SetUnit(int aUnit)
Definition: sch_item.h:238
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
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)
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)
size_t GetCount() const
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 ...
void ReannotateDuplicates(const SCH_REFERENCE_LIST &aAdditionalReferences)
Convenience function for the Paste Unique functionality.
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.
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.
int GetUnit() const
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
Definition: sch_symbol.cpp:677
void SetValueFieldText(const wxString &aValue)
Definition: sch_symbol.cpp:738
const wxString GetValue(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const override
Definition: sch_symbol.cpp:728
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
Definition: sch_symbol.cpp:600
const wxString GetFootprintFieldText(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const
Definition: sch_symbol.cpp:744
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:767
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:686
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
Definition: sch_symbol.cpp:702
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:183
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
Definition: sch_symbol.cpp:558
#define _(s)
@ ERCE_UNANNOTATED
Symbol has not been annotated.
Definition: erc_settings.h:82
@ ERCE_DUPLICATE_REFERENCE
More than one symbol with the same reference.
Definition: erc_settings.h:85
@ ERCE_EXTRA_UNITS
Symbol has more units than are defined.
Definition: erc_settings.h:83
@ ERCE_DIFFERENT_UNIT_VALUE
Units of same symbol have different values.
Definition: erc_settings.h:84
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.
Definition: string_utils.h:429
A simple container for schematic symbol instance information.