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