KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_board_reannotate.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) 2020 Brian Piccioni [email protected]
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Brian Piccioni <[email protected]>
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
27
28#include <algorithm>
29#include <base_units.h>
30#include <bitmaps.h>
31#include <board_commit.h>
32#include <confirm.h>
33#include <ctype.h>
35#include <string_utils.h> // StrNumCmp
36#include <kiface_base.h>
37#include <pcbnew_settings.h>
38#include <refdes_utils.h>
39#include <richio.h>
40#include <tool/grid_menu.h>
42#include <wx/valtext.h>
43
44
48
49//
50// This converts the index into a sort code. Note that Back sort code will have left and
51// right swapped.
52//
54 SORTYFIRST + ASCENDINGFIRST + ASCENDINGSECOND, // "Top to bottom, left to right", // 100
55 SORTYFIRST + ASCENDINGFIRST + DESCENDINGSECOND, // "Top to bottom, right to left", // 101
56 SORTYFIRST + DESCENDINGFIRST + ASCENDINGSECOND, // "Back to Front, left to right", // 110
57 SORTYFIRST + DESCENDINGFIRST + DESCENDINGSECOND, // "Back to Front, right to left", // 111
58 SORTXFIRST + ASCENDINGFIRST + ASCENDINGSECOND, // "Left to right, Front to Back", // 000
59 SORTXFIRST + ASCENDINGFIRST + DESCENDINGSECOND, // "Left to right, Back to Front", // 001
60 SORTXFIRST + DESCENDINGFIRST + ASCENDINGSECOND, // "Right to left, Front to Back", // 010
61 SORTXFIRST + DESCENDINGFIRST + DESCENDINGSECOND // "Right to left, Back to Front", // 011
62};
63
64
65//
66// Back Left/Right is opposite because it is a mirror image (coordinates are from the top)
67//
69 SORTYFIRST + ASCENDINGFIRST + DESCENDINGSECOND, // "Top to bottom, left to right", // 101
70 SORTYFIRST + ASCENDINGFIRST + ASCENDINGSECOND, // "Top to bottom, right to left", // 100
71 SORTYFIRST + DESCENDINGFIRST + DESCENDINGSECOND, // "Bottom to top, left to right", // 111
72 SORTYFIRST + DESCENDINGFIRST + ASCENDINGSECOND, // "Bottom to top, right to left", // 110
73 SORTXFIRST + DESCENDINGFIRST + ASCENDINGSECOND, // "Left to right, top to bottom", // 010
74 SORTXFIRST + DESCENDINGFIRST + DESCENDINGSECOND, // "Left to right, bottom to top", // 011
75 SORTXFIRST + ASCENDINGFIRST + ASCENDINGSECOND, // "Right to left, top to bottom", // 000
76 SORTXFIRST + ASCENDINGFIRST + DESCENDINGSECOND // "Right to left, bottom to top", // 001
77};
78
79#define SetSortCodes( DirArray, Code ) \
80 { \
81 g_SortYFirst = ( ( DirArray[Code] & SORTYFIRST ) != 0 ); \
82 g_DescendingFirst = ( ( DirArray[Code] & DESCENDINGFIRST ) != 0 ); \
83 g_DescendingSecond = ( ( DirArray[Code] & DESCENDINGSECOND ) != 0 ); \
84 }
85
86
87wxString ActionMessage[] = {
88 "", // UPDATE_REFDES
89 _( "(not updated)" ), // EMPTY_REFDES
90 _( "(unannotated; not updated)" ), // INVALID_REFDES
91 _( "(excluded)" ) // EXCLUDE_REFDES
92};
93
94
96 DIALOG_BOARD_REANNOTATE_BASE( aParentFrame ),
97 m_frame( aParentFrame ),
98 m_footprints( aParentFrame->GetBoard()->Footprints() )
99{
100 // Init bitmaps associated to some wxRadioButton
109
110 m_FrontRefDesStart->SetValidator( wxTextValidator( wxFILTER_DIGITS ) );
111 m_BackRefDesStart->SetValidator( wxTextValidator( wxFILTER_DIGITS ) );
112
113 SetupStandardButtons( { { wxID_OK, _( "Reannotate PCB" ) },
114 { wxID_CANCEL, _( "Close" ) } } );
115
116 wxArrayString gridslist;
117 GRID_MENU::BuildChoiceList( &gridslist, m_frame->config(), aParentFrame );
118
119 m_GridChoice->Set( gridslist );
120
121 int gridIndex = m_frame->config()->m_Window.grid.last_size_idx;
122
123 if( gridIndex >= 0 && gridIndex < (int) m_GridChoice->GetCount() )
124 m_GridChoice->SetSelection( gridIndex );
125 else
126 m_GridChoice->SetSelection( 0 );
127
128 m_ExcludeList->SetToolTip( m_ExcludeListText->GetToolTipText() );
129 m_GridChoice->SetToolTip( m_SortGridText->GetToolTipText() );
130
131 m_MessageWindow->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
132
134}
135
136
137void DIALOG_BOARD_REANNOTATE::OnCloseClick( wxCommandEvent& event )
138{
139 EndDialog( wxID_OK );
140}
141
142
144{
145 PCB_SELECTION selection = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
146
147 if( !selection.Empty() )
148 m_AnnotateSelection->SetValue( true );
149
150 // Ensure m_GridChoice selection validity
151 // If not, the choice 0 is arbitrary
152 if( m_GridChoice->GetSelection() < 0 || m_GridChoice->GetSelection() >= (int)m_GridChoice->GetCount() )
153 m_GridChoice->SetSelection( 0 );
154
155 return true;
156}
157
158
159void DIALOG_BOARD_REANNOTATE::FilterPrefix( wxTextCtrl* aPrefix )
160{
161 std::string tmps = VALIDPREFIX;
162
163 if( aPrefix->GetValue().empty() )
164 return; //Should never happen
165
166 char lastc = aPrefix->GetValue().Last();
167
168 if( isalnum( (int) lastc ) )
169 return;
170
171 if( tmps.find( lastc ) != std::string::npos )
172 return;
173
174 tmps = aPrefix->GetValue();
175 aPrefix->Clear();
176 tmps.pop_back();
177 aPrefix->AppendText( tmps );
178}
179
180
182 int aStartRefDes )
183{
184 for( size_t i = 0; i < m_refDesPrefixInfos.size(); i++ ) // See if it is in the info array
185 {
186 if( m_refDesPrefixInfos[i].RefDesPrefix == aRefDesPrefix ) // Found it!
187 return &m_refDesPrefixInfos[i];
188 }
189
190 // Wasn't in the info array so add it
191 REFDES_PREFIX_INFO newtype;
192 newtype.RefDesPrefix = aRefDesPrefix;
193 newtype.LastUsedRefDes = aStartRefDes - 1;
194 m_refDesPrefixInfos.push_back( newtype );
195
196 return &m_refDesPrefixInfos.back();
197}
198
199
201{
203}
204
205
206void DIALOG_BOARD_REANNOTATE::FilterBackPrefix( wxCommandEvent& event )
207{
209}
210
211
212void DIALOG_BOARD_REANNOTATE::OnApplyClick( wxCommandEvent& event )
213{
214 m_MessageWindow->SetLazyUpdate( true );
215
216 if( ReannotateBoard() )
217 {
218 ShowReport( _( "PCB successfully reannotated" ), RPT_SEVERITY_ACTION );
219 ShowReport( _( "PCB annotation changes should be synchronized with schematic using "
220 "\"Update Schematic from PCB\"." ), RPT_SEVERITY_WARNING );
221 }
222
223 m_MessageWindow->SetLazyUpdate( false );
224 m_MessageWindow->Flush( false );
225 m_frame->GetCanvas()->Refresh(); // Redraw
226 m_frame->OnModify(); // Need to save file on exit.
227}
228
229
230int DIALOG_BOARD_REANNOTATE::RoundToGrid( int aCoord, int aGrid )
231{
232 if( 0 == aGrid )
233 aGrid = MINGRID;
234
235 int rounder;
236 rounder = aCoord % aGrid;
237 aCoord -= rounder;
238
239 if( abs( rounder ) > ( aGrid / 2 ) )
240 aCoord += ( aCoord < 0 ? -aGrid : aGrid );
241
242 return ( aCoord );
243}
244
245
248static bool ChangeArrayCompare( const REFDES_CHANGE& aA, const REFDES_CHANGE& aB )
249{
250 return ( StrNumCmp( aA.OldRefDesString, aB.OldRefDesString ) < 0 );
251}
252
253
256static bool FootprintCompare( const REFDES_INFO& aA, const REFDES_INFO& aB )
257{
258 int X0 = aA.roundedx, X1 = aB.roundedx, Y0 = aA.roundedy, Y1 = aB.roundedy;
259
260 if( g_SortYFirst ) //If sorting by Y then X, swap X and Y
261 {
262 std::swap( X0, Y0 );
263 std::swap( X1, Y1 );
264 }
265
266 // If descending, same compare just swap directions
268 std::swap( X0, X1 );
269
271 std::swap( Y0, Y1 );
272
273 if( X0 < X1 )
274 return true; // yes, it's smaller
275 else if( X0 > X1 )
276 return false; // no, it's not
277 else if( Y0 < Y1 )
278 return true;
279 else
280 return false;
281}
282
283
284wxString empty_str()
285{
286 return wxT( "<i>" ) + _( "unannotated footprint" ) + wxT( "</i>" );
287}
288
289
290wxString unknown_str()
291{
292 return wxT( "<i>" ) + _( "unknown" ) + wxT( "</i>" );
293}
294
295
297{
298 return wxString::Format( wxT( "%s, %s" ),
299 m_frame->MessageTextFromValue( aX ),
300 m_frame->MessageTextFromValue( aY ) );
301}
302
303
304void DIALOG_BOARD_REANNOTATE::ShowReport( const wxString& aMessage, SEVERITY aSeverity )
305{
306 wxStringTokenizer msgs( aMessage, "\n" );
307
308 while( msgs.HasMoreTokens() )
309 m_MessageWindow->Report( msgs.GetNextToken(), aSeverity );
310}
311
312
314{
315 wxString message;
316
317 message = _( "Reference Designator Prefixes in Use" );
318 message += wxT( "<br/>-------------------------------------------------------------<br/>" );
319
320 int i = 1;
321
322 for( const REFDES_PREFIX_INFO& info : m_refDesPrefixInfos ) // Show all the types of refdes
323 message += info.RefDesPrefix + ( ( i++ % 16 ) == 0 ? wxT( "<br/>" ) : wxS( " " ) );
324
325 message += wxT( "<br/>" );
326
327 if( !m_excludeArray.empty() )
328 {
329 wxString excludes;
330
331 for( wxString& exclude : m_excludeArray ) // Show the refdes we are excluding
332 excludes += exclude + wxS( " " );
333
334 message += wxString::Format( _( "(Excluding %s from reannotation.)" ), excludes );
335 }
336
337 ShowReport( message + wxT( "<br/>" ), RPT_SEVERITY_INFO );
338
339 message = _( "Change Log" );
340 message += wxT( "<br/>-------------------------------------------------------------<br/>" );
341
342 for( const REFDES_CHANGE& change : m_changeArray )
343 {
344 if( change.Action != UPDATE_REFDES )
345 {
346 message += wxString::Format( wxT( "%s <i>%s</i><br/>" ),
347 change.OldRefDesString.IsEmpty() ? empty_str() : change.OldRefDesString,
348 ActionMessage[change.Action] );
349 }
350 else
351 {
352 message += wxString::Format( wxT( "%s -> %s<br/>" ),
353 change.OldRefDesString.IsEmpty() ? empty_str() : change.OldRefDesString,
354 change.NewRefDes.IsEmpty() ? empty_str() : change.NewRefDes );
355 }
356 }
357
359}
360
361
362void DIALOG_BOARD_REANNOTATE::LogFootprints( const std::vector<REFDES_INFO>& aFootprints )
363{
364 wxString message = aFootprints.front().Front ? _( "Front Footprints" ) : _( "Back Footprints" );
365 message += ' ';
366
367 if( m_locationChoice->GetSelection() == 0 )
368 message += _( "(sorted by footprint location)" );
369 else
370 message += _( "(sorted by reference designator location)" );
371
372 message += wxT( "<br/>-------------------------------------------------------------" );
373
374 int i = 1;
375
376 for( const REFDES_INFO& fp : aFootprints )
377 {
378 message += wxString::Format( _( "<br/>%d %s at %s (rounded to %s)" ),
379 i++,
380 fp.RefDesString.IsEmpty() ? empty_str() : fp.RefDesString,
381 CoordTowxString( fp.x, fp.y ),
382 CoordTowxString( fp.roundedx, fp.roundedy ) );
383 }
384
385 ShowReport( message + wxT( "<br/>" ), RPT_SEVERITY_INFO );
386}
387
388
390{
391 std::vector<REFDES_INFO> BadRefDes;
392 wxString message1, message2, badrefdes;
393 STRING_FORMATTER stringformatter;
394 REFDES_CHANGE* newref;
396
397 if( !BuildFootprintList( BadRefDes ) )
398 {
399 ShowReport( _( "Selected options resulted in errors! Change them and try again." ), RPT_SEVERITY_ERROR );
400 return false;
401 }
402
403 if( !BadRefDes.empty() )
404 {
405 message1.Printf( _( "PCB has %d empty or invalid reference designations." ), (int) BadRefDes.size() );
406 message2.Printf( _( "You may wish to run DRC with 'Test for parity between PCB and schematic' checked." ) );
407
408 for( const REFDES_INFO& mod : BadRefDes )
409 {
410 badrefdes += wxString::Format( _( "<br/> RefDes: %s; footprint: %s at %s on PCB." ),
411 mod.RefDesString.IsEmpty() ? empty_str() : mod.RefDesString,
412 mod.FPID.IsValid() ? wxString( mod.FPID.Format().c_str() ) : unknown_str(),
413 CoordTowxString( mod.x, mod.y ) );
414 }
415
416 ShowReport( message1 + wxT( "<br/>" ) + message2 + badrefdes + wxT( "<br/>" ), RPT_SEVERITY_WARNING );
417
418 if( !IsOK( m_frame, message1 + "\n" + message2 + "\n \n" + _( "Reannotate anyway?" ) ) )
419 return false;
420 }
421
422 BOARD_COMMIT commit( m_frame );
423
424 for( FOOTPRINT* footprint : m_footprints )
425 {
426 newref = GetNewRefDes( footprint );
427
428 if( nullptr == newref )
429 return false;
430
431 commit.Modify( footprint ); // Make a copy for undo
432 footprint->SetReference( newref->NewRefDes ); // Update the PCB reference
433 m_frame->GetCanvas()->GetView()->Update( footprint ); // Touch the footprint
434 }
435
436 commit.Push( _( "Annotation" ) );
437 return true;
438}
439
440
441bool DIALOG_BOARD_REANNOTATE::BuildFootprintList( std::vector<REFDES_INFO>& aBadRefDes )
442{
443 bool annotateSelected = m_AnnotateSelection->GetValue();
444 bool annotateFront = m_AnnotateFront->GetValue();
445 bool annotateBack = m_AnnotateBack->GetValue();
446 bool skipLocked = m_ExcludeLocked->GetValue();
447
448 GRID sortGridMils = m_frame->config()->m_Window.grid.grids[ m_GridChoice->GetSelection() ];
449 int sortGridx = (int) EDA_UNIT_UTILS::UI::ValueFromString( pcbIUScale, EDA_UNITS::MILS, sortGridMils.x );
450 int sortGridy = (int) EDA_UNIT_UTILS::UI::ValueFromString( pcbIUScale, EDA_UNITS::MILS, sortGridMils.y );
451
452 int errorcount = 0;
453 size_t firstnum = 0;
454
455 m_frontFootprints.clear();
456 m_backFootprints.clear();
457 m_excludeArray.clear();
458 m_footprints = m_frame->GetBoard()->Footprints();
459
460 wxStringTokenizer tokenizer( m_ExcludeList->GetValue(), ", \t\r\n", wxTOKEN_STRTOK );
461
462 while( tokenizer.HasMoreTokens() )
463 m_excludeArray.push_back( tokenizer.GetNextToken() );
464
465 REFDES_INFO fpData;
466 bool useFPLocation = m_locationChoice->GetSelection() == 0;
467
468 for( FOOTPRINT* footprint : m_footprints )
469 {
470 fpData.Uuid = footprint->m_Uuid;
471 fpData.RefDesString = footprint->GetReference();
472 fpData.FPID = footprint->GetFPID();
473 fpData.x = useFPLocation ? footprint->GetPosition().x
474 : footprint->Reference().GetPosition().x;
475 fpData.y = useFPLocation ? footprint->GetPosition().y
476 : footprint->Reference().GetPosition().y;
477 fpData.roundedx = RoundToGrid( fpData.x, sortGridx ); // Round to sort
478 fpData.roundedy = RoundToGrid( fpData.y, sortGridy );
479 fpData.Front = footprint->GetLayer() == F_Cu;
480 fpData.Action = UPDATE_REFDES; // Usually good
481
482 if( fpData.RefDesString.IsEmpty() )
483 {
484 fpData.Action = EMPTY_REFDES;
485 }
486 else
487 {
488 firstnum = fpData.RefDesString.find_first_of( wxT( "0123456789" ) );
489
490 if( std::string::npos == firstnum )
491 fpData.Action = INVALID_REFDES;
492 }
493
494 // Get the type (R, C, etc)
495 fpData.RefDesPrefix = fpData.RefDesString.substr( 0, firstnum );
496
497 for( const wxString& excluded : m_excludeArray )
498 {
499 // If exclusion ends in *, apply it to entire refdes
500 if( excluded.EndsWith( '*' ) )
501 {
502 if( fpData.RefDesString.Matches( excluded ) )
503 {
504 fpData.Action = EXCLUDE_REFDES;
505 break;
506 }
507 }
508 else if( excluded == fpData.RefDesPrefix )
509 {
510 fpData.Action = EXCLUDE_REFDES;
511 break;
512 }
513 }
514
515 if( footprint->IsLocked() && skipLocked )
516 fpData.Action = EXCLUDE_REFDES;
517 else if( annotateSelected )
518 fpData.Action = footprint->IsSelected() ? UPDATE_REFDES : EXCLUDE_REFDES;
519 else if( annotateFront )
520 fpData.Action = fpData.Front ? UPDATE_REFDES : EXCLUDE_REFDES;
521 else if( annotateBack )
522 fpData.Action = fpData.Front ? EXCLUDE_REFDES : UPDATE_REFDES;
523
524 if( fpData.Front )
525 m_frontFootprints.push_back( fpData );
526 else
527 m_backFootprints.push_back( fpData );
528 }
529
530 int sortCode = 0; // Convert radio button to sort direction code
531
532 for( wxRadioButton* sortbuttons : m_sortButtons )
533 {
534 if( sortbuttons->GetValue() )
535 break;
536
537 sortCode++;
538 }
539
540 if( sortCode >= (int) m_sortButtons.size() )
541 sortCode = 0;
542
543 // Determine the sort order for the front.
545
546 // Sort the front footprints.
548
549 // Determine the sort order for the back.
551
552 // Sort the back footprints.
553 sort( m_backFootprints.begin(), m_backFootprints.end(), FootprintCompare );
554
555 m_refDesPrefixInfos.clear();
556 m_changeArray.clear();
557
559
560 if( !m_frontFootprints.empty() )
561 {
563 m_FrontPrefix->GetValue(), m_RemoveFrontPrefix->GetValue(), aBadRefDes );
564 }
565
566 if( !m_backFootprints.empty() )
567 {
569 m_BackPrefix->GetValue(), m_RemoveBackPrefix->GetValue(), aBadRefDes );
570 }
571
572 if( !m_changeArray.empty() )
573 sort( m_changeArray.begin(), m_changeArray.end(), ChangeArrayCompare );
574
576
577 size_t changearraysize = m_changeArray.size();
578
579 for( size_t i = 0; i < changearraysize; i++ ) // Scan through for duplicates if update or skip
580 {
581 if( m_changeArray[i].Action != EMPTY_REFDES && m_changeArray[i].Action != INVALID_REFDES )
582 {
583 for( size_t j = i + 1; j < changearraysize; j++ )
584 {
585 if( m_changeArray[i].NewRefDes == m_changeArray[j].NewRefDes )
586 {
587 ShowReport( wxString::Format( _( "Duplicate instances of %s" ), m_changeArray[j].NewRefDes ),
589
590 if( errorcount++ > MAXERROR )
591 {
592 ShowReport( _( "Aborted: too many errors" ), RPT_SEVERITY_ERROR );
593 break;
594 }
595 }
596 }
597 }
598
599 if( errorcount > MAXERROR )
600 break;
601 }
602
603 return ( errorcount == 0 );
604}
605
607{
608 std::vector<REFDES_INFO> excludedFootprints;
609
610 for( const REFDES_INFO& fpData : m_frontFootprints )
611 {
612 if( fpData.Action == EXCLUDE_REFDES )
613 excludedFootprints.push_back( fpData );
614 }
615
616 for( const REFDES_INFO& fpData : m_backFootprints )
617 {
618 if( fpData.Action == EXCLUDE_REFDES )
619 excludedFootprints.push_back( fpData );
620 }
621
622 for( const REFDES_INFO& fpData : excludedFootprints )
623 {
624 if( fpData.Action == EXCLUDE_REFDES )
625 {
626 REFDES_PREFIX_INFO* refDesInfo = GetOrBuildRefDesInfo( fpData.RefDesPrefix );
627 refDesInfo->UnavailableRefs.insert( UTIL::GetRefDesNumber( fpData.RefDesString ) );
628 }
629 }
630}
631
632
633void DIALOG_BOARD_REANNOTATE::BuildChangeArray( std::vector<REFDES_INFO>& aFootprints,
634 unsigned int aStartRefDes, const wxString& aPrefix,
635 bool aRemovePrefix, std::vector<REFDES_INFO>& aBadRefDes )
636{
637 size_t prefixsize = aPrefix.size();
638
639 bool haveprefix = ( 0 != prefixsize ); // Do I have a prefix?
640 bool addprefix = haveprefix & !aRemovePrefix; // Yes- and I'm not removing it
641 aRemovePrefix &= haveprefix; // Only remove if I have a prefix
642
643 bool prefixpresent; // Prefix found
644
645 LogFootprints( aFootprints );
646
647 if( aStartRefDes != 0 ) // Initialize the change array if present
648 {
649 for( REFDES_PREFIX_INFO& prefixInfo : m_refDesPrefixInfos )
650 prefixInfo.LastUsedRefDes = aStartRefDes - 1;
651 }
652
653 for( REFDES_INFO fpData : aFootprints )
654 {
655 REFDES_CHANGE change;
656
657 change.Uuid = fpData.Uuid;
658 change.Action = fpData.Action;
659 change.OldRefDesString = fpData.RefDesString;
660 change.NewRefDes = fpData.RefDesString;
661 change.Front = fpData.Front;
662
663 if( fpData.RefDesString.IsEmpty() )
664 fpData.Action = EMPTY_REFDES;
665
666 if( ( change.Action == EMPTY_REFDES ) || ( change.Action == INVALID_REFDES ) )
667 {
668 m_changeArray.push_back( change );
669 aBadRefDes.push_back( fpData );
670 continue;
671 }
672
673 if( change.Action == UPDATE_REFDES )
674 {
675 prefixpresent = ( fpData.RefDesPrefix.find( aPrefix ) == 0 );
676
677 if( addprefix && !prefixpresent )
678 fpData.RefDesPrefix.insert( 0, aPrefix ); // Add prefix once only
679
680 if( aRemovePrefix && prefixpresent ) // If there is a prefix remove it
681 fpData.RefDesPrefix.erase( 0, prefixsize );
682
683 REFDES_PREFIX_INFO* refDesInfo = GetOrBuildRefDesInfo( fpData.RefDesPrefix, aStartRefDes );
684 unsigned int newRefDesNumber = refDesInfo->LastUsedRefDes + 1;
685
686 while( refDesInfo->UnavailableRefs.count( newRefDesNumber ) )
687 newRefDesNumber++;
688
689 change.NewRefDes = refDesInfo->RefDesPrefix + std::to_string( newRefDesNumber );
690 refDesInfo->LastUsedRefDes = newRefDesNumber;
691 }
692
693 m_changeArray.push_back( change );
694 }
695}
696
697
699{
700 size_t i;
701
702 for( i = 0; i < m_changeArray.size(); i++ )
703 {
704 if( aFootprint->m_Uuid == m_changeArray[i].Uuid )
705 return ( &m_changeArray[i] );
706 }
707
708 ShowReport( _( "Footprint not found in changelist" ) + wxS( " " ) + aFootprint->GetReference(),
710
711 return nullptr; // Should never happen
712}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
@ reannotate_down_left
@ reannotate_up_right
@ reannotate_right_down
@ reannotate_up_left
@ reannotate_left_down
@ reannotate_down_right
@ reannotate_left_up
@ reannotate_right_up
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
DIALOG_BOARD_REANNOTATE_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Geographical Reannotation"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
std::vector< REFDES_CHANGE > m_changeArray
std::vector< wxString > m_excludeArray
bool BuildFootprintList(std::vector< REFDES_INFO > &aBadRefDes)
Build the footprint lists, sort it, filter for excludes, then build the change list.
void FilterBackPrefix(wxCommandEvent &event) override
std::vector< REFDES_INFO > m_frontFootprints
wxString CoordTowxString(int aX, int aY)
Convert coordinates to wxString.
void FilterPrefix(wxTextCtrl *aPrefix)
Check to make sure the prefix (if there is one) is properly constructed.
void BuildChangeArray(std::vector< REFDES_INFO > &aFootprints, unsigned int aStartRefDes, const wxString &aPrefix, bool aRemovePrefix, std::vector< REFDES_INFO > &aBadRefDes)
Scan through the footprint arrays and create the from -> to array.
void LogFootprints(const std::vector< REFDES_INFO > &aFootprints)
Create a list of the footprints and their coordinates.
int RoundToGrid(int aCoord, int aGrid)
Round an int coordinate to a suitable grid.
REFDES_PREFIX_INFO * GetOrBuildRefDesInfo(const wxString &aRefDesPrefix, int aStartRefDes=1)
Get the structure representing the information currently held for aRefDesPrefix or create one if it d...
void BuildUnavailableRefsList()
Build list of unavailable references. E.g. unselected footprints or locked footprints.
void LogChangePlan(void)
Create an audit trail of the changes.
void OnCloseClick(wxCommandEvent &event) override
REFDES_CHANGE * GetNewRefDes(FOOTPRINT *aFootprint)
bool ReannotateBoard(void)
Actually reannotate the board.
void ShowReport(const wxString &aMessage, SEVERITY aSeverity)
Break report into strings separated by and sent to the reporter.
std::vector< REFDES_INFO > m_backFootprints
std::vector< REFDES_PREFIX_INFO > m_refDesPrefixInfos
DIALOG_BOARD_REANNOTATE(PCB_EDIT_FRAME *aParentFrame)
void OnApplyClick(wxCommandEvent &event) override
std::vector< wxRadioButton * > m_sortButtons
void FilterFrontPrefix(wxCommandEvent &event) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
const KIID m_Uuid
Definition eda_item.h:516
const wxString & GetReference() const
Definition footprint.h:661
static void BuildChoiceList(wxArrayString *aGridsList, APP_SETTINGS_BASE *aCfg, EDA_DRAW_FRAME *aParent)
Definition grid_menu.cpp:83
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
Store information read from a netlist along with the flags used to update the NETLIST in the BOARD.
The main frame for Pcbnew.
The selection tool: currently supports:
bool Empty() const
Checks if there is anything selected.
Definition selection.h:115
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:450
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:259
This file is part of the common library.
int BackDirectionsArray[]
int FrontDirectionsArray[]
bool g_DescendingFirst
wxString unknown_str()
bool g_DescendingSecond
wxString empty_str()
#define SetSortCodes(DirArray, Code)
bool g_SortYFirst
static bool ChangeArrayCompare(const REFDES_CHANGE &aA, const REFDES_CHANGE &aB)
Compare function used to compare ChangeArray element for sort.
static bool FootprintCompare(const REFDES_INFO &aA, const REFDES_INFO &aB)
Compare function to sort footprints.
wxString ActionMessage[]
#define MAXERROR
#define DESCENDINGFIRST
#define SORTXFIRST
#define DESCENDINGSECOND
#define ASCENDINGFIRST
#define SORTYFIRST
#define ASCENDINGSECOND
#define MINGRID
#define VALIDPREFIX
#define _(s)
@ F_Cu
Definition layer_ids.h:64
KICOMMON_API long long int ValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue in aUnits to internal units used by the application.
int GetRefDesNumber(const wxString &aRefDes)
Get the numeric suffix from a refdes - e.g.
BOARD * GetBoard()
Collection of utility functions for component reference designators (refdes)
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
@ RPT_SEVERITY_ACTION
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
Common grid settings, available to every frame.
wxString y
wxString x
std::set< unsigned int > UnavailableRefs