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/tokenzr.h>
43#include <wx/valtext.h>
44
45
49
50//
51// This converts the index into a sort code. Note that Back sort code will have left and
52// right swapped.
53//
55 SORTYFIRST + ASCENDINGFIRST + ASCENDINGSECOND, // "Top to bottom, left to right", // 100
56 SORTYFIRST + ASCENDINGFIRST + DESCENDINGSECOND, // "Top to bottom, right to left", // 101
57 SORTYFIRST + DESCENDINGFIRST + ASCENDINGSECOND, // "Back to Front, left to right", // 110
58 SORTYFIRST + DESCENDINGFIRST + DESCENDINGSECOND, // "Back to Front, right to left", // 111
59 SORTXFIRST + ASCENDINGFIRST + ASCENDINGSECOND, // "Left to right, Front to Back", // 000
60 SORTXFIRST + ASCENDINGFIRST + DESCENDINGSECOND, // "Left to right, Back to Front", // 001
61 SORTXFIRST + DESCENDINGFIRST + ASCENDINGSECOND, // "Right to left, Front to Back", // 010
62 SORTXFIRST + DESCENDINGFIRST + DESCENDINGSECOND // "Right to left, Back to Front", // 011
63};
64
65
66//
67// Back Left/Right is opposite because it is a mirror image (coordinates are from the top)
68//
70 SORTYFIRST + ASCENDINGFIRST + DESCENDINGSECOND, // "Top to bottom, left to right", // 101
71 SORTYFIRST + ASCENDINGFIRST + ASCENDINGSECOND, // "Top to bottom, right to left", // 100
72 SORTYFIRST + DESCENDINGFIRST + DESCENDINGSECOND, // "Bottom to top, left to right", // 111
73 SORTYFIRST + DESCENDINGFIRST + ASCENDINGSECOND, // "Bottom to top, right to left", // 110
74 SORTXFIRST + DESCENDINGFIRST + ASCENDINGSECOND, // "Left to right, top to bottom", // 010
75 SORTXFIRST + DESCENDINGFIRST + DESCENDINGSECOND, // "Left to right, bottom to top", // 011
76 SORTXFIRST + ASCENDINGFIRST + ASCENDINGSECOND, // "Right to left, top to bottom", // 000
77 SORTXFIRST + ASCENDINGFIRST + DESCENDINGSECOND // "Right to left, bottom to top", // 001
78};
79
80#define SetSortCodes( DirArray, Code ) \
81 { \
82 g_SortYFirst = ( ( DirArray[Code] & SORTYFIRST ) != 0 ); \
83 g_DescendingFirst = ( ( DirArray[Code] & DESCENDINGFIRST ) != 0 ); \
84 g_DescendingSecond = ( ( DirArray[Code] & DESCENDINGSECOND ) != 0 ); \
85 }
86
87
88wxString ActionMessage[] = {
89 "", // UPDATE_REFDES
90 _( "(not updated)" ), // EMPTY_REFDES
91 _( "(unannotated; not updated)" ), // INVALID_REFDES
92 _( "(excluded)" ) // EXCLUDE_REFDES
93};
94
95
97 DIALOG_BOARD_REANNOTATE_BASE( aParentFrame ),
98 m_frame( aParentFrame ),
99 m_footprints( aParentFrame->GetBoard()->Footprints() )
100{
101 // Init bitmaps associated to some wxRadioButton
110
111 m_FrontRefDesStart->SetValidator( wxTextValidator( wxFILTER_DIGITS ) );
112 m_BackRefDesStart->SetValidator( wxTextValidator( wxFILTER_DIGITS ) );
113
114 SetupStandardButtons( { { wxID_OK, _( "Reannotate PCB" ) },
115 { wxID_CANCEL, _( "Close" ) } } );
116
117 wxArrayString gridslist;
118 GRID_MENU::BuildChoiceList( &gridslist, m_frame->GetWindowSettings( m_frame->config() ), aParentFrame );
119
120 m_GridChoice->Set( gridslist );
121
122 int gridIndex = m_frame->config()->m_Window.grid.last_size_idx;
123
124 if( gridIndex >= 0 && gridIndex < (int) m_GridChoice->GetCount() )
125 m_GridChoice->SetSelection( gridIndex );
126 else
127 m_GridChoice->SetSelection( 0 );
128
129 m_ExcludeList->SetToolTip( m_ExcludeListText->GetToolTipText() );
130 m_GridChoice->SetToolTip( m_SortGridText->GetToolTipText() );
131
132 m_MessageWindow->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
133
135}
136
137
138void DIALOG_BOARD_REANNOTATE::OnCloseClick( wxCommandEvent& event )
139{
140 EndDialog( wxID_OK );
141}
142
143
145{
146 PCB_SELECTION selection = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
147
148 if( !selection.Empty() )
149 m_AnnotateSelection->SetValue( true );
150
151 // Ensure m_GridChoice selection validity
152 // If not, the choice 0 is arbitrary
153 if( m_GridChoice->GetSelection() < 0 || m_GridChoice->GetSelection() >= (int)m_GridChoice->GetCount() )
154 m_GridChoice->SetSelection( 0 );
155
156 return true;
157}
158
159
160void DIALOG_BOARD_REANNOTATE::FilterPrefix( wxTextCtrl* aPrefix )
161{
162 std::string tmps = VALIDPREFIX;
163
164 if( aPrefix->GetValue().empty() )
165 return; //Should never happen
166
167 char lastc = aPrefix->GetValue().Last();
168
169 if( isalnum( (int) lastc ) )
170 return;
171
172 if( tmps.find( lastc ) != std::string::npos )
173 return;
174
175 tmps = aPrefix->GetValue();
176 aPrefix->Clear();
177 tmps.pop_back();
178 aPrefix->AppendText( tmps );
179}
180
181
183 int aStartRefDes )
184{
185 for( size_t i = 0; i < m_refDesPrefixInfos.size(); i++ ) // See if it is in the info array
186 {
187 if( m_refDesPrefixInfos[i].RefDesPrefix == aRefDesPrefix ) // Found it!
188 return &m_refDesPrefixInfos[i];
189 }
190
191 // Wasn't in the info array so add it
192 REFDES_PREFIX_INFO newtype;
193 newtype.RefDesPrefix = aRefDesPrefix;
194 newtype.LastUsedRefDes = std::max( aStartRefDes - 1, 0 );
195 m_refDesPrefixInfos.push_back( newtype );
196
197 return &m_refDesPrefixInfos.back();
198}
199
200
202{
204}
205
206
207void DIALOG_BOARD_REANNOTATE::FilterBackPrefix( wxCommandEvent& event )
208{
210}
211
212
213void DIALOG_BOARD_REANNOTATE::OnApplyClick( wxCommandEvent& event )
214{
215 m_MessageWindow->SetLazyUpdate( true );
216
217 if( ReannotateBoard() )
218 {
219 ShowReport( _( "PCB successfully reannotated" ), RPT_SEVERITY_ACTION );
220 ShowReport( _( "PCB annotation changes should be synchronized with schematic using "
221 "\"Update Schematic from PCB\"." ), RPT_SEVERITY_WARNING );
222 }
223
224 m_MessageWindow->SetLazyUpdate( false );
225 m_MessageWindow->Flush( false );
226 m_frame->GetCanvas()->Refresh(); // Redraw
227 m_frame->OnModify(); // Need to save file on exit.
228}
229
230
231int DIALOG_BOARD_REANNOTATE::RoundToGrid( int aCoord, int aGrid )
232{
233 if( 0 == aGrid )
234 aGrid = MINGRID;
235
236 int rounder;
237 rounder = aCoord % aGrid;
238 aCoord -= rounder;
239
240 if( abs( rounder ) > ( aGrid / 2 ) )
241 aCoord += ( aCoord < 0 ? -aGrid : aGrid );
242
243 return ( aCoord );
244}
245
246
249static bool ChangeArrayCompare( const REFDES_CHANGE& aA, const REFDES_CHANGE& aB )
250{
251 return ( StrNumCmp( aA.OldRefDesString, aB.OldRefDesString ) < 0 );
252}
253
254
257static bool FootprintCompare( const REFDES_INFO& aA, const REFDES_INFO& aB )
258{
259 int X0 = aA.roundedx, X1 = aB.roundedx, Y0 = aA.roundedy, Y1 = aB.roundedy;
260
261 if( g_SortYFirst ) //If sorting by Y then X, swap X and Y
262 {
263 std::swap( X0, Y0 );
264 std::swap( X1, Y1 );
265 }
266
267 // If descending, same compare just swap directions
269 std::swap( X0, X1 );
270
272 std::swap( Y0, Y1 );
273
274 if( X0 < X1 )
275 return true; // yes, it's smaller
276 else if( X0 > X1 )
277 return false; // no, it's not
278 else if( Y0 < Y1 )
279 return true;
280 else
281 return false;
282}
283
284
285wxString empty_str()
286{
287 return wxT( "<i>" ) + _( "unannotated footprint" ) + wxT( "</i>" );
288}
289
290
291wxString unknown_str()
292{
293 return wxT( "<i>" ) + _( "unknown" ) + wxT( "</i>" );
294}
295
296
298{
299 return wxString::Format( wxT( "%s, %s" ),
300 m_frame->MessageTextFromValue( aX ),
301 m_frame->MessageTextFromValue( aY ) );
302}
303
304
305void DIALOG_BOARD_REANNOTATE::ShowReport( const wxString& aMessage, SEVERITY aSeverity )
306{
307 wxStringTokenizer msgs( aMessage, "\n" );
308
309 while( msgs.HasMoreTokens() )
310 m_MessageWindow->Report( msgs.GetNextToken(), aSeverity );
311}
312
313
315{
316 wxString message;
317
318 message = _( "Reference Designator Prefixes in Use" );
319 message += wxT( "<br/>-------------------------------------------------------------<br/>" );
320
321 int i = 1;
322
323 for( const REFDES_PREFIX_INFO& info : m_refDesPrefixInfos ) // Show all the types of refdes
324 message += info.RefDesPrefix + ( ( i++ % 16 ) == 0 ? wxT( "<br/>" ) : wxS( " " ) );
325
326 message += wxT( "<br/>" );
327
328 if( !m_excludeArray.empty() )
329 {
330 wxString excludes;
331
332 for( wxString& exclude : m_excludeArray ) // Show the refdes we are excluding
333 excludes += exclude + wxS( " " );
334
335 message += wxString::Format( _( "(Excluding %s from reannotation.)" ), excludes );
336 }
337
338 ShowReport( message + wxT( "<br/>" ), RPT_SEVERITY_INFO );
339
340 message = _( "Change Log" );
341 message += wxT( "<br/>-------------------------------------------------------------<br/>" );
342
343 for( const REFDES_CHANGE& change : m_changeArray )
344 {
345 if( change.Action != UPDATE_REFDES )
346 {
347 message += wxString::Format( wxT( "%s <i>%s</i><br/>" ),
348 change.OldRefDesString.IsEmpty() ? empty_str() : change.OldRefDesString,
349 ActionMessage[change.Action] );
350 }
351 else
352 {
353 message += wxString::Format( wxT( "%s -> %s<br/>" ),
354 change.OldRefDesString.IsEmpty() ? empty_str() : change.OldRefDesString,
355 change.NewRefDes.IsEmpty() ? empty_str() : change.NewRefDes );
356 }
357 }
358
360}
361
362
363void DIALOG_BOARD_REANNOTATE::LogFootprints( const std::vector<REFDES_INFO>& aFootprints )
364{
365 wxString message = aFootprints.front().Front ? _( "Front Footprints" ) : _( "Back Footprints" );
366 message += ' ';
367
368 if( m_locationChoice->GetSelection() == 0 )
369 message += _( "(sorted by footprint location)" );
370 else
371 message += _( "(sorted by reference designator location)" );
372
373 message += wxT( "<br/>-------------------------------------------------------------" );
374
375 int i = 1;
376
377 for( const REFDES_INFO& fp : aFootprints )
378 {
379 message += wxString::Format( _( "<br/>%d %s at %s (rounded to %s)" ),
380 i++,
381 fp.RefDesString.IsEmpty() ? empty_str() : fp.RefDesString,
382 CoordTowxString( fp.x, fp.y ),
383 CoordTowxString( fp.roundedx, fp.roundedy ) );
384 }
385
386 ShowReport( message + wxT( "<br/>" ), RPT_SEVERITY_INFO );
387}
388
389
391{
392 std::vector<REFDES_INFO> BadRefDes;
393 wxString message1, message2, badrefdes;
394 STRING_FORMATTER stringformatter;
395 REFDES_CHANGE* newref;
397
398 if( !BuildFootprintList( BadRefDes ) )
399 {
400 ShowReport( _( "Selected options resulted in errors! Change them and try again." ), RPT_SEVERITY_ERROR );
401 return false;
402 }
403
404 if( !BadRefDes.empty() )
405 {
406 message1.Printf( _( "PCB has %d empty or invalid reference designations." ), (int) BadRefDes.size() );
407 message2.Printf( _( "You may wish to run DRC with 'Test for parity between PCB and schematic' checked." ) );
408
409 for( const REFDES_INFO& mod : BadRefDes )
410 {
411 badrefdes += wxString::Format( _( "<br/> RefDes: %s; footprint: %s at %s on PCB." ),
412 mod.RefDesString.IsEmpty() ? empty_str() : mod.RefDesString,
413 mod.FPID.IsValid() ? wxString( mod.FPID.Format().c_str() ) : unknown_str(),
414 CoordTowxString( mod.x, mod.y ) );
415 }
416
417 ShowReport( message1 + wxT( "<br/>" ) + message2 + badrefdes + wxT( "<br/>" ), RPT_SEVERITY_WARNING );
418
419 if( !IsOK( m_frame, message1 + "\n" + message2 + "\n \n" + _( "Reannotate anyway?" ) ) )
420 return false;
421 }
422
423 BOARD_COMMIT commit( m_frame );
424
425 for( FOOTPRINT* footprint : m_footprints )
426 {
427 newref = GetNewRefDes( footprint );
428
429 if( nullptr == newref )
430 return false;
431
432 commit.Modify( footprint ); // Make a copy for undo
433 footprint->SetReference( newref->NewRefDes ); // Update the PCB reference
434 m_frame->GetCanvas()->GetView()->Update( footprint ); // Touch the footprint
435 }
436
437 commit.Push( _( "Annotation" ) );
438 return true;
439}
440
441
442bool DIALOG_BOARD_REANNOTATE::BuildFootprintList( std::vector<REFDES_INFO>& aBadRefDes )
443{
444 bool annotateSelected = m_AnnotateSelection->GetValue();
445 bool annotateFront = m_AnnotateFront->GetValue();
446 bool annotateBack = m_AnnotateBack->GetValue();
447 bool skipLocked = m_ExcludeLocked->GetValue();
448
449 GRID sortGridMils = m_frame->config()->m_Window.grid.grids[ m_GridChoice->GetSelection() ];
450 int sortGridx = (int) EDA_UNIT_UTILS::UI::ValueFromString( pcbIUScale, EDA_UNITS::MILS, sortGridMils.x );
451 int sortGridy = (int) EDA_UNIT_UTILS::UI::ValueFromString( pcbIUScale, EDA_UNITS::MILS, sortGridMils.y );
452
453 int errorcount = 0;
454 size_t firstnum = 0;
455
456 m_frontFootprints.clear();
457 m_backFootprints.clear();
458 m_excludeArray.clear();
459 m_footprints = m_frame->GetBoard()->Footprints();
460
461 wxStringTokenizer tokenizer( m_ExcludeList->GetValue(), ", \t\r\n", wxTOKEN_STRTOK );
462
463 while( tokenizer.HasMoreTokens() )
464 m_excludeArray.push_back( tokenizer.GetNextToken() );
465
466 REFDES_INFO fpData;
467 bool useFPLocation = m_locationChoice->GetSelection() == 0;
468
469 for( FOOTPRINT* footprint : m_footprints )
470 {
471 fpData.Uuid = footprint->m_Uuid;
472 fpData.RefDesString = footprint->GetReference();
473 fpData.FPID = footprint->GetFPID();
474 fpData.x = useFPLocation ? footprint->GetPosition().x
475 : footprint->Reference().GetPosition().x;
476 fpData.y = useFPLocation ? footprint->GetPosition().y
477 : footprint->Reference().GetPosition().y;
478 fpData.roundedx = RoundToGrid( fpData.x, sortGridx ); // Round to sort
479 fpData.roundedy = RoundToGrid( fpData.y, sortGridy );
480 fpData.Front = footprint->GetLayer() == F_Cu;
481 fpData.Action = UPDATE_REFDES; // Usually good
482
483 if( fpData.RefDesString.IsEmpty() )
484 {
485 fpData.Action = EMPTY_REFDES;
486 }
487 else
488 {
489 firstnum = fpData.RefDesString.find_first_of( wxT( "0123456789" ) );
490
491 if( std::string::npos == firstnum )
492 fpData.Action = INVALID_REFDES;
493 }
494
495 // Get the type (R, C, etc)
496 fpData.RefDesPrefix = fpData.RefDesString.substr( 0, firstnum );
497
498 for( const wxString& excluded : m_excludeArray )
499 {
500 // If exclusion ends in *, apply it to entire refdes
501 if( excluded.EndsWith( '*' ) )
502 {
503 if( fpData.RefDesString.Matches( excluded ) )
504 {
505 fpData.Action = EXCLUDE_REFDES;
506 break;
507 }
508 }
509 else if( excluded == fpData.RefDesPrefix )
510 {
511 fpData.Action = EXCLUDE_REFDES;
512 break;
513 }
514 }
515
516 if( footprint->IsLocked() && skipLocked )
517 fpData.Action = EXCLUDE_REFDES;
518 else if( annotateSelected )
519 fpData.Action = footprint->IsSelected() ? UPDATE_REFDES : EXCLUDE_REFDES;
520 else if( annotateFront )
521 fpData.Action = fpData.Front ? UPDATE_REFDES : EXCLUDE_REFDES;
522 else if( annotateBack )
523 fpData.Action = fpData.Front ? EXCLUDE_REFDES : UPDATE_REFDES;
524
525 if( fpData.Front )
526 m_frontFootprints.push_back( fpData );
527 else
528 m_backFootprints.push_back( fpData );
529 }
530
531 int sortCode = 0; // Convert radio button to sort direction code
532
533 for( wxRadioButton* sortbuttons : m_sortButtons )
534 {
535 if( sortbuttons->GetValue() )
536 break;
537
538 sortCode++;
539 }
540
541 if( sortCode >= (int) m_sortButtons.size() )
542 sortCode = 0;
543
544 // Determine the sort order for the front.
546
547 // Sort the front footprints.
549
550 // Determine the sort order for the back.
552
553 // Sort the back footprints.
554 sort( m_backFootprints.begin(), m_backFootprints.end(), FootprintCompare );
555
556 m_refDesPrefixInfos.clear();
557 m_changeArray.clear();
558
560
561 if( !m_frontFootprints.empty() )
562 {
564 m_FrontPrefix->GetValue(), m_RemoveFrontPrefix->GetValue(), aBadRefDes );
565 }
566
567 if( !m_backFootprints.empty() )
568 {
570 m_BackPrefix->GetValue(), m_RemoveBackPrefix->GetValue(), aBadRefDes );
571 }
572
573 if( !m_changeArray.empty() )
574 sort( m_changeArray.begin(), m_changeArray.end(), ChangeArrayCompare );
575
577
578 size_t changearraysize = m_changeArray.size();
579
580 for( size_t i = 0; i < changearraysize; i++ ) // Scan through for duplicates if update or skip
581 {
582 if( m_changeArray[i].Action != EMPTY_REFDES && m_changeArray[i].Action != INVALID_REFDES )
583 {
584 for( size_t j = i + 1; j < changearraysize; j++ )
585 {
586 if( m_changeArray[i].NewRefDes == m_changeArray[j].NewRefDes )
587 {
588 ShowReport( wxString::Format( _( "Duplicate instances of %s" ), m_changeArray[j].NewRefDes ),
590
591 if( errorcount++ > MAXERROR )
592 {
593 ShowReport( _( "Aborted: too many errors" ), RPT_SEVERITY_ERROR );
594 break;
595 }
596 }
597 }
598 }
599
600 if( errorcount > MAXERROR )
601 break;
602 }
603
604 return ( errorcount == 0 );
605}
606
608{
609 std::vector<REFDES_INFO> excludedFootprints;
610
611 for( const REFDES_INFO& fpData : m_frontFootprints )
612 {
613 if( fpData.Action == EXCLUDE_REFDES )
614 excludedFootprints.push_back( fpData );
615 }
616
617 for( const REFDES_INFO& fpData : m_backFootprints )
618 {
619 if( fpData.Action == EXCLUDE_REFDES )
620 excludedFootprints.push_back( fpData );
621 }
622
623 for( const REFDES_INFO& fpData : excludedFootprints )
624 {
625 if( fpData.Action == EXCLUDE_REFDES )
626 {
627 REFDES_PREFIX_INFO* refDesInfo = GetOrBuildRefDesInfo( fpData.RefDesPrefix );
628 refDesInfo->UnavailableRefs.insert( UTIL::GetRefDesNumber( fpData.RefDesString ) );
629 }
630 }
631}
632
633
634void DIALOG_BOARD_REANNOTATE::BuildChangeArray( std::vector<REFDES_INFO>& aFootprints,
635 unsigned int aStartRefDes, const wxString& aPrefix,
636 bool aRemovePrefix, std::vector<REFDES_INFO>& aBadRefDes )
637{
638 size_t prefixsize = aPrefix.size();
639
640 bool haveprefix = ( 0 != prefixsize ); // Do I have a prefix?
641 bool addprefix = haveprefix & !aRemovePrefix; // Yes- and I'm not removing it
642 aRemovePrefix &= haveprefix; // Only remove if I have a prefix
643
644 bool prefixpresent; // Prefix found
645
646 LogFootprints( aFootprints );
647
648 if( aStartRefDes != 0 ) // Initialize the change array if present
649 {
650 for( REFDES_PREFIX_INFO& prefixInfo : m_refDesPrefixInfos )
651 prefixInfo.LastUsedRefDes = aStartRefDes - 1;
652 }
653
654 for( REFDES_INFO fpData : aFootprints )
655 {
656 REFDES_CHANGE change;
657
658 change.Uuid = fpData.Uuid;
659 change.Action = fpData.Action;
660 change.OldRefDesString = fpData.RefDesString;
661 change.NewRefDes = fpData.RefDesString;
662 change.Front = fpData.Front;
663
664 if( fpData.RefDesString.IsEmpty() )
665 fpData.Action = EMPTY_REFDES;
666
667 if( ( change.Action == EMPTY_REFDES ) || ( change.Action == INVALID_REFDES ) )
668 {
669 m_changeArray.push_back( change );
670 aBadRefDes.push_back( fpData );
671 continue;
672 }
673
674 if( change.Action == UPDATE_REFDES )
675 {
676 prefixpresent = ( fpData.RefDesPrefix.find( aPrefix ) == 0 );
677
678 if( addprefix && !prefixpresent )
679 fpData.RefDesPrefix.insert( 0, aPrefix ); // Add prefix once only
680
681 if( aRemovePrefix && prefixpresent ) // If there is a prefix remove it
682 fpData.RefDesPrefix.erase( 0, prefixsize );
683
684 REFDES_PREFIX_INFO* refDesInfo = GetOrBuildRefDesInfo( fpData.RefDesPrefix, aStartRefDes );
685 unsigned int newRefDesNumber = refDesInfo->LastUsedRefDes + 1;
686
687 while( refDesInfo->UnavailableRefs.count( newRefDesNumber ) )
688 newRefDesNumber++;
689
690 change.NewRefDes = refDesInfo->RefDesPrefix + std::to_string( newRefDesNumber );
691 refDesInfo->LastUsedRefDes = newRefDesNumber;
692 }
693
694 m_changeArray.push_back( change );
695 }
696}
697
698
700{
701 size_t i;
702
703 for( i = 0; i < m_changeArray.size(); i++ )
704 {
705 if( aFootprint->m_Uuid == m_changeArray[i].Uuid )
706 return ( &m_changeArray[i] );
707 }
708
709 ShowReport( _( "Footprint not found in changelist" ) + wxS( " " ) + aFootprint->GetReference(),
711
712 return nullptr; // Should never happen
713}
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:522
const wxString & GetReference() const
Definition footprint.h:751
static void BuildChoiceList(wxArrayString *aGridsList, WINDOW_SETTINGS *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:422
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