KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbnew/widgets/search_handlers.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) 2023 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "search_handlers.h"
22
23#include <board.h>
24#include <footprint.h>
25#include <pcb_edit_frame.h>
26#include <pcb_marker.h>
27#include <pcb_painter.h>
28#include <pcb_group.h>
29#include <pcb_textbox.h>
30#include <pcb_text.h>
31#include <pcb_dimension.h>
32#include <pcbnew_settings.h>
34#include <string_utils.h>
35#include <tool/tool_manager.h>
36#include <tools/pcb_actions.h>
37#include <zone.h>
38#include <pad.h>
39#include <pcb_track.h>
40
41
43{
44 std::vector<long> item = { aItemRow };
45 SelectItems( item );
46
47 m_frame->GetToolManager()->RunAction( PCB_ACTIONS::properties );
48}
49
50
51wxString PCB_SEARCH_HANDLER::GetResultCell( int aRow, int aCol )
52{
53 if( m_frame->IsClosing() )
54 return wxEmptyString;
55
56 if( aRow >= static_cast<int>(m_hitlist.size() ) )
57 return wxEmptyString;
58
59 BOARD_ITEM* item = m_hitlist[aRow];
60
61 if( !item )
62 return wxEmptyString;
63
64 return getResultCell( item, aCol );
65}
66
67
68void PCB_SEARCH_HANDLER::Sort( int aCol, bool aAscending, std::vector<long>* aSelection )
69{
70 std::vector<BOARD_ITEM*> selection;
71
72 for( long i = 0; i < (long) m_hitlist.size(); ++i )
73 {
74 if( alg::contains( *aSelection, i ) )
75 selection.push_back( m_hitlist[i] );
76 }
77
78 int col = std::max( 0, aCol ); // Provide a stable order by sorting on first column if no
79 // sort column provided.
80
81 std::sort( m_hitlist.begin(), m_hitlist.end(),
82 [&]( BOARD_ITEM* a, BOARD_ITEM* b ) -> bool
83 {
84 // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
85 // to get the opposite sort. i.e. ~(a<b) != (a>b)
86 if( aAscending )
87 return StrNumCmp( getResultCell( a, col ), getResultCell( b, col ), true ) < 0;
88 else
89 return StrNumCmp( getResultCell( b, col ), getResultCell( a, col ), true ) < 0;
90 } );
91
92
93 aSelection->clear();
94
95 for( long i = 0; i < (long) m_hitlist.size(); ++i )
96 {
97 if( alg::contains( selection, m_hitlist[i] ) )
98 aSelection->push_back( i );
99 }
100}
101
102
103void PCB_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
104{
105 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
106 std::vector<EDA_ITEM*> selectedItems;
107
108 for( long row : aItemRows )
109 {
110 if( row >= 0 && row < (long) m_hitlist.size() )
111 selectedItems.push_back( m_hitlist[row] );
112 }
113
114 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
115
116 if( selectedItems.size() )
117 {
118 m_frame->GetToolManager()->RunAction( ACTIONS::selectItems, &selectedItems );
119
120 switch( settings.selection_zoom )
121 {
123 m_frame->GetToolManager()->RunAction( ACTIONS::centerSelection );
124 break;
126 m_frame->GetToolManager()->RunAction( ACTIONS::zoomFitSelection );
127 break;
129 break;
130 }
131 }
132
133 m_frame->GetCanvas()->Refresh( false );
134}
135
136
138 PCB_SEARCH_HANDLER( _HKI( "Footprints" ), aFrame )
139{
140 m_columns.emplace_back( _HKI( "Reference" ), 2, wxLIST_FORMAT_LEFT );
141 m_columns.emplace_back( _HKI( "Value" ), 6, wxLIST_FORMAT_LEFT );
142 m_columns.emplace_back( _HKI( "Layer" ), 2, wxLIST_FORMAT_CENTER );
143 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
144 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
145 m_columns.emplace_back( _HKI( "Library Link" ), 8, wxLIST_FORMAT_LEFT );
146 m_columns.emplace_back( _HKI( "Library Description" ), 10, wxLIST_FORMAT_LEFT );
147}
148
149
150int FOOTPRINT_SEARCH_HANDLER::Search( const wxString& aQuery )
151{
152 m_hitlist.clear();
153 BOARD* board = m_frame->GetBoard();
154
155 if( board == nullptr )
156 return 0;
157
158 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
159 EDA_SEARCH_DATA frp;
160
162 frp.searchMetadata = settings.search_metadata;
163 frp.findString = aQuery;
164
165 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
167
168 for( FOOTPRINT* fp : board->Footprints() )
169 {
170 bool found = false;
171
172 if( frp.findString.IsEmpty() )
173 found = true;
174
175 if( !found && fp->Matches( frp, nullptr ) )
176 found = true;
177
178 if( !found )
179 {
180 for( PCB_FIELD* field : fp->GetFields() )
181 {
182 wxCHECK2( field, continue );
183
184 if( field->Matches( frp, nullptr ) )
185 {
186 found = true;
187 break;
188 }
189 }
190 }
191
192 if( found )
193 m_hitlist.push_back( fp );
194 }
195
196 return (int) m_hitlist.size();
197}
198
199
201{
202 FOOTPRINT* fp = static_cast<FOOTPRINT*>( aItem );
203
204 if( aCol == 0 )
205 return fp->GetReference();
206 else if( aCol == 1 )
207 return UnescapeString( fp->GetValue() );
208 else if( aCol == 2 )
209 return fp->GetLayerName();
210 else if( aCol == 3 )
211 return m_frame->MessageTextFromCoord( fp->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
212 else if( aCol == 4 )
213 return m_frame->MessageTextFromCoord( fp->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
214 else if( aCol == 5 )
215 return fp->GetFPID().Format();
216 else if( aCol == 6 )
217 return fp->GetLibDescription();
218
219 return wxEmptyString;
220}
221
222
224 PCB_SEARCH_HANDLER( _HKI( "Zones" ), aFrame )
225{
226 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
227 m_columns.emplace_back( _HKI( "Net" ), 6, wxLIST_FORMAT_LEFT);
228 m_columns.emplace_back( _HKI( "Layer" ), 3, wxLIST_FORMAT_CENTER );
229 m_columns.emplace_back( _HKI( "Priority" ), 2, wxLIST_FORMAT_CENTER );
230 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
231 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
232 m_columns.emplace_back( _HKI( "Area" ), 3, wxLIST_FORMAT_RIGHT );
233}
234
235
236int ZONE_SEARCH_HANDLER::Search( const wxString& aQuery )
237{
238 m_hitlist.clear();
239 BOARD* board = m_frame->GetBoard();
240
241 if( !board )
242 return 0;
243
244 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
245 EDA_SEARCH_DATA frp;
246
248 frp.searchMetadata = settings.search_metadata;
249 frp.findString = aQuery;
250
251 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
253
254 for( BOARD_ITEM* item : board->Zones() )
255 {
256 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
257 m_hitlist.push_back( item );
258 }
259
260 return (int) m_hitlist.size();
261}
262
263
265{
266 ZONE* zone = static_cast<ZONE*>( aItem );
267
268 if( aCol == 0 )
269 return zone->GetZoneName();
270 else if( aCol == 1 )
271 return UnescapeString( zone->GetNetname() );
272 else if( aCol == 2 )
273 {
274 BOARD* board = m_frame->GetBoard();
275
276 if( !board )
277 return wxEmptyString;
278
279 wxArrayString layers;
280
281 // Make sure we don't show layers from Rule Areas that aren't actually on the board,
282 // since they have all copper areas by default.
283 LSET dialogLayers = LSET::AllNonCuMask()
285
286 for( PCB_LAYER_ID layer : dialogLayers.UIOrder() )
287 {
288 if( zone->IsOnLayer( layer ) )
289 layers.Add( board->GetLayerName( layer ) );
290 }
291
292 return wxJoin( layers, ',' );
293 }
294 else if( aCol == 3 )
295 return wxString::Format( "%d", zone->GetAssignedPriority() );
296 else if( aCol == 4 )
297 return m_frame->MessageTextFromCoord( zone->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
298 else if( aCol == 5 )
299 return m_frame->MessageTextFromCoord( zone->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
300 else if( aCol == 6 )
301 {
302 return m_frame->MessageTextFromValue( zone->GetIsRuleArea() ? zone->GetOutlineArea() : zone->GetFilledArea(),
303 true, EDA_DATA_TYPE::AREA );
304 }
305
306
307 return wxEmptyString;
308}
309
310
312 PCB_SEARCH_HANDLER( _HKI( "Text" ), aFrame )
313{
314 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
315 m_columns.emplace_back( _HKI( "Text" ), 12, wxLIST_FORMAT_LEFT );
316 m_columns.emplace_back( _HKI( "Layer" ), 3, wxLIST_FORMAT_CENTER );
317 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
318 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
319}
320
321
322int TEXT_SEARCH_HANDLER::Search( const wxString& aQuery )
323{
324 m_hitlist.clear();
325 BOARD* board = m_frame->GetBoard();
326
327 if( !board )
328 return 0;
329
331 EDA_SEARCH_DATA frp;
332
334 frp.searchMetadata = settings.search_metadata;
335 frp.findString = aQuery;
336
337 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
339
340 for( BOARD_ITEM* item : board->Drawings() )
341 {
342 if( item->Type() == PCB_TEXT_T
343 || BaseType( item->Type() ) == PCB_DIMENSION_T
344 || item->Type() == PCB_TEXTBOX_T
345 || item->Type() == PCB_TABLECELL_T )
346 {
347 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
348 m_hitlist.push_back( item );
349 }
350 }
351
352 return (int) m_hitlist.size();
353}
354
355
357{
358 if( aCol == 0 )
359 {
360 if( PCB_TEXT::ClassOf( aItem ) )
361 return _( "Text" );
362 else if( PCB_TEXTBOX::ClassOf( aItem ) )
363 return _( "Textbox" );
364 else if( dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) )
365 return _( "Dimension" );
366 }
367 else if( aCol == 1 )
368 {
369 if( PCB_TEXT::ClassOf( aItem ) )
370 return UnescapeString( static_cast<PCB_TEXT*>( aItem )->GetText() );
371 else if( PCB_TEXTBOX::ClassOf( aItem ) )
372 return UnescapeString( static_cast<PCB_TEXTBOX*>( aItem )->GetText() );
373 else if( PCB_DIMENSION_BASE* dimension = dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) )
374 return UnescapeString( dimension->GetText() );
375 }
376 else if( aCol == 2 )
377 return aItem->GetLayerName();
378 else if( aCol == 3 )
379 return m_frame->MessageTextFromCoord( aItem->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
380 else if( aCol == 4 )
381 return m_frame->MessageTextFromCoord( aItem->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
382
383 return wxEmptyString;
384}
385
386
388 PCB_SEARCH_HANDLER( _HKI( "Groups" ), aFrame )
389{
390 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
391 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
392 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
393 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
394}
395
396
397int GROUP_SEARCH_HANDLER::Search( const wxString& aQuery )
398{
399 m_hitlist.clear();
400 BOARD* board = m_frame->GetBoard();
401
402 if( !board )
403 return 0;
404
406 EDA_SEARCH_DATA frp;
407
409 frp.searchMetadata = settings.search_metadata;
410 frp.findString = aQuery;
411
412 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
414
415 for( BOARD_ITEM* item : board->Groups() )
416 {
417 // Skip generators, they are for internal use, not user-facing grouping
418 if( item->Type() == PCB_GENERATOR_T )
419 continue;
420
421 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
422 m_hitlist.push_back( item );
423 }
424
425 return (int) m_hitlist.size();
426}
427
428
430{
431 if( aCol == 0 )
432 {
433 if( aItem->Type() == PCB_GROUP_T )
434 return _( "Group" );
435 else if( aItem->Type() == PCB_GENERATOR_T )
436 return _( "Generator" );
437 }
438 else if( aCol == 1 )
439 return static_cast<PCB_GROUP*>( aItem )->GetName();
440 else if( aCol == 2 )
441 return m_frame->MessageTextFromCoord( aItem->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
442 else if( aCol == 3 )
443 return m_frame->MessageTextFromCoord( aItem->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
444
445 return wxEmptyString;
446}
447
448
450 PCB_SEARCH_HANDLER( _HKI( "Nets" ), aFrame )
451{
452 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
453 m_columns.emplace_back( _HKI( "Class" ), 6, wxLIST_FORMAT_LEFT );
454}
455
456
457int NETS_SEARCH_HANDLER::Search( const wxString& aQuery )
458{
459 m_hitlist.clear();
460
461 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
462 EDA_SEARCH_DATA frp;
463
465 frp.searchMetadata = settings.search_metadata;
466 frp.findString = aQuery;
467
468 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
470
471 BOARD* board = m_frame->GetBoard();
472
473 if( !board )
474 return 0;
475
476 for( NETINFO_ITEM* net : board->GetNetInfo() )
477 {
478 if( net && ( aQuery.IsEmpty() || net->Matches( frp, nullptr ) ) )
479 m_hitlist.push_back( net );
480 }
481
482 return (int) m_hitlist.size();
483}
484
485
487{
488 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem );
489
490 if( net->GetNetCode() == 0 )
491 {
492 if( aCol == 0 )
493 return _( "No Net" );
494 else if( aCol == 1 )
495 return wxT( "" );
496 }
497
498 if( aCol == 0 )
499 return UnescapeString( net->GetNetname() );
500 else if( aCol == 1 )
501 return net->GetNetClass()->GetName();
502
503 return wxEmptyString;
504}
505
506
507void NETS_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
508{
509 RENDER_SETTINGS* ps = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
510 ps->SetHighlight( false );
511
512 std::vector<NETINFO_ITEM*> selectedItems;
513
514 for( long row : aItemRows )
515 {
516 if( row >= 0 && row < (long) m_hitlist.size() )
517 {
518 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( m_hitlist[row] );
519
520 ps->SetHighlight( true, net->GetNetCode(), true );
521 }
522 }
523
524 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
525 m_frame->GetCanvas()->Refresh();
526}
527
528
530{
531 m_frame->ShowBoardSetupDialog( _( "Net Classes" ) );
532}
533
534
536 PCB_SEARCH_HANDLER( _HKI( "Ratsnest" ), aFrame )
537{
538 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
539 m_columns.emplace_back( _HKI( "Class" ), 6, wxLIST_FORMAT_LEFT );
540}
541
542
543int RATSNEST_SEARCH_HANDLER::Search( const wxString& aQuery )
544{
545 m_hitlist.clear();
546
547 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
548 EDA_SEARCH_DATA frp;
549
551 frp.searchMetadata = settings.search_metadata;
552 frp.findString = aQuery;
553
554 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
556
557 BOARD* board = m_frame->GetBoard();
558
559 if( !board )
560 return 0;
561
562 for( NETINFO_ITEM* net : board->GetNetInfo() )
563 {
564 if( net == nullptr || !net->Matches( frp, nullptr ) )
565 continue;
566
567 RN_NET* rn = board->GetConnectivity()->GetRatsnestForNet( net->GetNetCode() );
568
569 if( rn && !rn->GetEdges().empty() )
570 m_hitlist.push_back( net );
571 }
572
573 return (int) m_hitlist.size();
574}
575
576
578{
579 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem );
580
581 if( net->GetNetCode() == 0 )
582 {
583 if( aCol == 0 )
584 return _( "No Net" );
585 else if( aCol == 1 )
586 return wxT( "" );
587 }
588
589 if( aCol == 0 )
590 return UnescapeString( net->GetNetname() );
591 else if( aCol == 1 )
592 return net->GetNetClass()->GetName();
593
594 return wxEmptyString;
595}
596
597
598void RATSNEST_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
599{
600 RENDER_SETTINGS* ps = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
601 ps->SetHighlight( false );
602
603 std::vector<NETINFO_ITEM*> selectedItems;
604
605 for( long row : aItemRows )
606 {
607 if( row >= 0 && row < (long) m_hitlist.size() )
608 {
609 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( m_hitlist[row] );
610
611 ps->SetHighlight( true, net->GetNetCode(), true );
612 }
613 }
614
615 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
616 m_frame->GetCanvas()->Refresh();
617}
618
619
621{
622 m_frame->ShowBoardSetupDialog( _( "Net Classes" ) );
623}
624
625
627 PCB_SEARCH_HANDLER( _HKI( "Drills" ), aFrame ),
628 m_frame( aFrame )
629{
630 m_columns.emplace_back( _HKI( "Count" ), 2, wxLIST_FORMAT_RIGHT );
631 m_columns.emplace_back( _HKI( "Shape" ), 3, wxLIST_FORMAT_LEFT );
632 m_columns.emplace_back( _HKI( "X Size" ), 3, wxLIST_FORMAT_CENTER );
633 m_columns.emplace_back( _HKI( "Y Size" ), 3, wxLIST_FORMAT_CENTER );
634 m_columns.emplace_back( _HKI( "Plated" ), 2, wxLIST_FORMAT_CENTER );
635 m_columns.emplace_back( _HKI( "Via/Pad" ), 2, wxLIST_FORMAT_CENTER );
636 m_columns.emplace_back( _HKI( "Start Layer" ), 4, wxLIST_FORMAT_CENTER );
637 m_columns.emplace_back( _HKI( "Stop Layer" ), 4, wxLIST_FORMAT_CENTER );
638}
639
640
641int DRILL_SEARCH_HANDLER::Search( const wxString& aQuery )
642{
643 BOARD* board = m_frame->GetBoard();
644
645 if( !board )
646 return 0;
647
648 m_drills.clear();
649 m_ptrToDrill.clear();
650 m_hitlist.clear();
651
652 auto addEntryOrIncrement = [&]( const DRILL_LINE_ITEM& d, BOARD_ITEM* rep )
653 {
654 for( DRILL_ROW& g : m_drills )
655 {
656 if( g.entry == d )
657 {
658 g.entry.m_Qty++;
659 return;
660 }
661 }
662
663 DRILL_ROW g = { .entry = d, .item = rep, };
664 g.entry.m_Qty = 1;
665
666 m_drills.push_back( g );
667 };
668
669 // Collect from pads
670 for( FOOTPRINT* fp : board->Footprints() )
671 {
672 for( PAD* pad : fp->Pads() )
673 {
674 if( !pad->HasHole() )
675 continue;
676
677 int xs = pad->GetDrillSize().x;
678 int ys = pad->GetDrillSize().y;
679 if( xs <= 0 || ys <= 0 )
680 continue;
681
682 PCB_LAYER_ID top, bottom;
683
684 if( pad->GetLayerSet().CuStack().empty() )
685 {
687 bottom = UNDEFINED_LAYER;
688 }
689 else
690 {
691 top = pad->GetLayerSet().CuStack().front();
692 bottom = pad->GetLayerSet().CuStack().back();
693 }
694
695 DRILL_LINE_ITEM d( xs, ys, pad->GetDrillShape(),
696 pad->GetAttribute() != PAD_ATTRIB::NPTH,
697 true, top, bottom );
698
699 addEntryOrIncrement( d, pad );
700 }
701 }
702
703 // Collect from vias
704 for( PCB_TRACK* t : board->Tracks() )
705 {
706 if( t->Type() != PCB_VIA_T )
707 continue;
708
709 PCB_VIA* via = static_cast<PCB_VIA*>( t );
710 int dmm = via->GetDrillValue();
711 if( dmm <= 0 )
712 continue;
713
714 DRILL_LINE_ITEM d( dmm, dmm, PAD_DRILL_SHAPE::CIRCLE, true,
715 false, via->TopLayer(), via->BottomLayer() );
716 addEntryOrIncrement( d, via );
717 }
718
719 std::sort( m_drills.begin(), m_drills.end(),
720 []( const DRILL_ROW& a, const DRILL_ROW& b )
721 {
722 DRILL_LINE_ITEM::COMPARE cmp( DRILL_LINE_ITEM::COL_COUNT, false );
723 return cmp( a.entry, b.entry );
724 } );
725
726 // Apply filter and populate display list
727 for( size_t i = 0; i < m_drills.size(); ++i )
728 {
729 if( aQuery.IsEmpty() || rowMatchesQuery( m_drills[i].entry, aQuery.Lower() ) )
730 {
731 m_hitlist.push_back( m_drills[i].item );
732 m_ptrToDrill[m_drills[i].item] = (int) i;
733 }
734 }
735
736 return (int) m_hitlist.size();
737}
738
739
741{
742 auto it = m_ptrToDrill.find( aItem );
743
744 if( it == m_ptrToDrill.end() )
745 return wxEmptyString;
746
747 const auto& e = m_drills[it->second].entry;
748
749 return cellText( e, aCol );
750}
751
752
753void DRILL_SEARCH_HANDLER::Sort( int aCol, bool aAscending, std::vector<long>* aSelection )
754{
755 // Preserve current selection pointers
756 std::vector<BOARD_ITEM*> selPtrs;
757
758 if( aSelection )
759 {
760 for( long row : *aSelection )
761 {
762 if( row >= 0 && row < (long) m_hitlist.size() )
763 selPtrs.push_back( m_hitlist[row] );
764 }
765 }
766
767 auto cmpPtr = [&]( BOARD_ITEM* pa, BOARD_ITEM* pb )
768 {
769 auto itA = m_ptrToDrill.find( pa );
770 auto itB = m_ptrToDrill.find( pb );
771
772 bool validA = ( itA != m_ptrToDrill.end() && itA->second >= 0
773 && itA->second < static_cast<int>( m_drills.size() ) );
774 bool validB = ( itB != m_ptrToDrill.end() && itB->second >= 0
775 && itB->second < static_cast<int>( m_drills.size() ) );
776
777 if( !validA || !validB )
778 {
779 if( validA != validB )
780 return validA;
781
782 return pa < pb;
783 }
784
785 const auto& a = m_drills[itA->second].entry;
786 const auto& b = m_drills[itB->second].entry;
787
788 int col = aCol < 0 ? 0 : aCol;
789 DRILL_LINE_ITEM::COMPARE cmp( static_cast<DRILL_LINE_ITEM::COL_ID>( col ), aAscending );
790
791 return cmp( a, b );
792 };
793
794 std::sort( m_hitlist.begin(), m_hitlist.end(), cmpPtr );
795
796 // Rebuild selection rows from pointers
797 if( aSelection )
798 {
799 aSelection->clear();
800
801 for( long row = 0; row < (long) m_hitlist.size(); ++row )
802 {
803 if( alg::contains( selPtrs, m_hitlist[row] ) )
804 aSelection->push_back( row );
805 }
806 }
807}
808
809
810void DRILL_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
811{
812 BOARD* board = m_frame->GetBoard();
813
814 if( !board )
815 return;
816
817 std::vector<EDA_ITEM*> selectedItems;
818 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
819
820 // Collect matching items
821 for( long row : aItemRows )
822 {
823 if( row < 0 || row >= (long) m_hitlist.size() )
824 continue;
825
826 BOARD_ITEM* rep = m_hitlist[row];
827 auto it = m_ptrToDrill.find( rep );
828
829 if( it == m_ptrToDrill.end() )
830 continue;
831
832 const auto* target = &m_drills[it->second].entry;
833
834 // Pads
835 for( FOOTPRINT* fp : board->Footprints() )
836 {
837 for( PAD* pad : fp->Pads() )
838 {
839 if( !pad->HasHole() )
840 continue;
841
842 int xs = pad->GetDrillSize().x;
843 int ys = pad->GetDrillSize().y;
844 PCB_LAYER_ID top, bottom;
845
846 if( pad->GetLayerSet().CuStack().empty() )
847 {
849 bottom = UNDEFINED_LAYER;
850 }
851 else
852 {
853 top = pad->GetLayerSet().CuStack().front();
854 bottom = pad->GetLayerSet().CuStack().back();
855 }
856
857 DRILL_LINE_ITEM e( xs, ys, pad->GetDrillShape(), pad->GetAttribute() != PAD_ATTRIB::NPTH, true,
858 top, bottom );
859
860 if( e == *target )
861 selectedItems.push_back( pad );
862 }
863 }
864
865 // Vias
866 for( PCB_TRACK* t : board->Tracks() )
867 {
868 if( t->Type() != PCB_VIA_T )
869 continue;
870
871 PCB_VIA* via = static_cast<PCB_VIA*>( t );
872 DRILL_LINE_ITEM e( via->GetDrillValue(), via->GetDrillValue(), PAD_DRILL_SHAPE::CIRCLE, true,
873 false, via->TopLayer(), via->BottomLayer() );
874
875 if( e == *target )
876 selectedItems.push_back( via );
877 }
878 }
879
880
881 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
882
883 if( selectedItems.size() )
884 {
885 m_frame->GetToolManager()->RunAction( ACTIONS::selectItems, &selectedItems );
886
887 switch( settings.selection_zoom )
888 {
890 m_frame->GetToolManager()->RunAction( ACTIONS::centerSelection );
891 break;
893 m_frame->GetToolManager()->RunAction( ACTIONS::zoomFitSelection );
894 break;
896 break;
897 }
898 }
899
900 m_frame->GetCanvas()->Refresh( false );
901}
902
903
904wxString DRILL_SEARCH_HANDLER::cellText( const DRILL_LINE_ITEM& e, int col ) const
905{
906 BOARD* board = m_frame->GetBoard();
907
908 if( !board )
909 return wxEmptyString;
910
911 switch( col )
912 {
913 case 0: return wxString::Format( "%d", e.m_Qty );
914 case 1: return e.shape == PAD_DRILL_SHAPE::CIRCLE ? _( "Round" ) : _( "Slot" );
915 case 2: return m_frame->MessageTextFromValue( e.xSize );
916 case 3: return m_frame->MessageTextFromValue( e.ySize );
917 case 4: return e.isPlated ? _( "PTH" ) : _( "NPTH" );
918 case 5: return e.isPad ? _( "Pad" ) : _( "Via" );
919 case 6: return ( e.startLayer == UNDEFINED_LAYER ) ? _( "N/A" ) : board->GetLayerName( e.startLayer );
920 case 7: return ( e.stopLayer == UNDEFINED_LAYER ) ? _( "N/A" ) : board->GetLayerName( e.stopLayer );
921 default: return wxEmptyString;
922 }
923}
924
925
926bool DRILL_SEARCH_HANDLER::rowMatchesQuery( const DRILL_LINE_ITEM& e, const wxString& aQuery ) const
927{
928 if( aQuery.IsEmpty() )
929 return true;
930
931 for( int col = 0; col < 8; ++col )
932 {
933 if( cellText( e, col ).Lower().Contains( aQuery ) )
934 return true;
935 }
936
937 return false;
938}
static TOOL_ACTION zoomFitSelection
Definition actions.h:144
static TOOL_ACTION centerSelection
Definition actions.h:150
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:232
SEARCH_PANE m_SearchPane
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
int GetY() const
Definition board_item.h:125
int GetX() const
Definition board_item.h:119
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:323
const NETINFO_LIST & GetNetInfo() const
Definition board.h:1004
const ZONES & Zones() const
Definition board.h:368
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:390
int GetCopperLayerCount() const
Definition board.cpp:928
const FOOTPRINTS & Footprints() const
Definition board.h:364
const TRACKS & Tracks() const
Definition board.h:362
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:737
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:571
const DRAWINGS & Drawings() const
Definition board.h:366
RN_NET * GetRatsnestForNet(int aNet)
Function GetRatsnestForNet() Returns the ratsnest, expressed as a set of graph edges for a given net.
wxString cellText(const DRILL_LINE_ITEM &e, int col) const
std::unordered_map< BOARD_ITEM *, int > m_ptrToDrill
void SelectItems(std::vector< long > &aItemRows) override
int Search(const wxString &aQuery) override
bool rowMatchesQuery(const DRILL_LINE_ITEM &e, const wxString &aQuery) const
DRILL_SEARCH_HANDLER(PCB_EDIT_FRAME *aFrame)
void Sort(int aCol, bool aAscending, std::vector< long > *aSelection) override
std::vector< DRILL_ROW > m_drills
wxString getResultCell(BOARD_ITEM *aItem, int aCol) override
virtual APP_SETTINGS_BASE * config() const
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
FOOTPRINT_SEARCH_HANDLER(PCB_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
wxString getResultCell(BOARD_ITEM *aItem, int aCol) override
wxString GetLibDescription() const
Definition footprint.h:388
const LIB_ID & GetFPID() const
Definition footprint.h:371
const wxString & GetValue() const
Definition footprint.h:793
const wxString & GetReference() const
Definition footprint.h:771
wxString getResultCell(const SCH_SEARCH_HIT &hit, int aCol) override
int Search(const wxString &aQuery) override
GROUP_SEARCH_HANDLER(SCH_EDIT_FRAME *aFrame)
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
UTF8 Format() const
Definition lib_id.cpp:119
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:608
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:743
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:627
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
Definition netclass.cpp:328
Handle the data for a net.
Definition netinfo.h:50
const wxString & GetNetname() const
Definition netinfo.h:103
NETCLASS * GetNetClass()
Definition netinfo.h:95
int GetNetCode() const
Definition netinfo.h:97
void ActivateItem(long aItemRow) override
int Search(const wxString &aQuery) override
NETS_SEARCH_HANDLER(PCB_EDIT_FRAME *aFrame)
wxString getResultCell(BOARD_ITEM *aItem, int aCol) override
void SelectItems(std::vector< long > &aItemRows) override
Definition pad.h:55
static TOOL_ACTION properties
Activation of the edit tool.
Abstract dimension API.
The main frame for Pcbnew.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:53
void ActivateItem(long aItemRow) override
PCB_SEARCH_HANDLER(const wxString &aName, PCB_EDIT_FRAME *aFrame)
wxString GetResultCell(int aRow, int aCol) override
void Sort(int aCol, bool aAscending, std::vector< long > *aSelection) override
void SelectItems(std::vector< long > &aItemRows) override
std::vector< BOARD_ITEM * > m_hitlist
virtual wxString getResultCell(BOARD_ITEM *aItem, int aCol)=0
static bool ClassOf(const EDA_ITEM *aItem)
Definition pcb_textbox.h:48
static bool ClassOf(const EDA_ITEM *aItem)
Definition pcb_text.h:67
wxString getResultCell(BOARD_ITEM *aItem, int aCol) override
RATSNEST_SEARCH_HANDLER(PCB_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
void SelectItems(std::vector< long > &aItemRows) override
void ActivateItem(long aItemRow) override
Describe ratsnest for a single net.
const std::vector< CN_EDGE > & GetEdges() const
std::vector< SCH_SEARCH_HIT > m_hitlist
std::vector< std::tuple< wxString, int, wxListColumnFormat > > m_columns
Definition search_pane.h:61
wxString GetName() const
Definition search_pane.h:45
TEXT_SEARCH_HANDLER(SCH_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
wxString getResultCell(const SCH_SEARCH_HIT &hit, int aCol) override
ZONE_SEARCH_HANDLER(PCB_EDIT_FRAME *aFrame)
wxString getResultCell(BOARD_ITEM *aItem, int aCol) override
int Search(const wxString &aQuery) override
Handle a list of polygons defining a copper zone.
Definition zone.h:74
double GetOutlineArea()
This area is cached from the most recent call to CalculateOutlineArea().
Definition zone.h:276
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:716
double GetFilledArea()
This area is cached from the most recent call to CalculateFilledArea().
Definition zone.h:266
const wxString & GetZoneName() const
Definition zone.h:164
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition zone.cpp:644
unsigned GetAssignedPriority() const
Definition zone.h:126
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ UNDEFINED_LAYER
Definition layer_ids.h:61
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
#define _HKI(x)
Definition page_info.cpp:44
Class to handle a set of BOARD_ITEMs.
Class that computes missing connections on a PCB.
wxString UnescapeString(const wxString &aSource)
PCB_LAYER_ID stopLayer
PAD_DRILL_SHAPE shape
PCB_LAYER_ID startLayer
EDA_SEARCH_MATCH_MODE matchMode
KIBIS top(path, &reporter)
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition typeinfo.h:251
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:94
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:108
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:90
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:89
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:92
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:97