KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eeschema/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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <sch_actions.h>
21#include <sch_edit_frame.h>
22#include <sch_painter.h>
23#include <sch_symbol.h>
24#include <sch_label.h>
25#include <sch_text.h>
26#include <sch_textbox.h>
27#include <schematic.h>
28#include <string_utils.h>
29#include <tool/tool_manager.h>
30#include "search_handlers.h"
31
32
34{
35 std::vector<long> item = { aItemRow };
36 SelectItems( item );
37
39}
40
41
42void SCH_SEARCH_HANDLER::FindAll( const std::function<bool( SCH_ITEM*, SCH_SHEET_PATH* )>& aCollector )
43{
44 SCH_SCREENS screens( m_frame->Schematic().Root() );
45 std::vector<SCH_SHEET_PATH*> paths;
46
47 m_hitlist.clear();
48
50
51 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
52 {
53 for( SCH_SHEET_PATH& sheet : screen->GetClientSheetPaths() )
54 paths.push_back( &sheet );
55 }
56
57 for( SCH_SHEET_PATH* sheet : paths )
58 {
59 for( SCH_ITEM* item : sheet->LastScreen()->Items() )
60 {
61 if( aCollector( item, sheet ) )
62 m_hitlist.push_back( { item, sheet } );
63 }
64 }
65}
66
67
68void SCH_SEARCH_HANDLER::Sort( int aCol, bool aAscending, std::vector<long>* aSelection )
69{
70 std::vector<SCH_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].item );
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 [&]( const SCH_SEARCH_HIT& a, const SCH_SEARCH_HIT& 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 aSelection->clear();
93
94 for( long i = 0; i < (long) m_hitlist.size(); ++i )
95 {
96 if( alg::contains( selection, m_hitlist[i].item ) )
97 aSelection->push_back( i );
98 }
99}
100
101
102void SCH_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
103{
104 EDA_ITEMS selectedItems;
105 std::vector<SCH_SEARCH_HIT> selectedHits;
106
108
109 for( long row : aItemRows )
110 {
111 if( row >= 0 && row < (long) m_hitlist.size() )
112 {
113 selectedHits.emplace_back( m_hitlist[row] );
114 selectedItems.emplace_back( m_hitlist[row].item );
115 }
116 }
117
118 if( selectedHits.empty() )
119 return;
120
121 bool allHitsOnSamePage = std::all_of( selectedHits.begin() + 1, selectedHits.end(),
122 [&]( const SCH_SEARCH_HIT& r )
123 {
124 return r.sheetPath == selectedHits.front().sheetPath;
125 } );
126
128
129 if( allHitsOnSamePage && !selectedHits.empty() )
130 {
131 if( m_frame->GetCurrentSheet() != *selectedHits.front().sheetPath )
132 {
133 m_frame->SetCurrentSheet( *selectedHits.front().sheetPath );
135 }
136
137 if( selectedItems.size() )
139
140 switch( settings.selection_zoom )
141 {
144 break;
147 break;
149 break;
150 }
151
152 m_frame->GetCanvas()->Refresh( false );
153 }
154}
155
156
158 SCH_SEARCH_HANDLER( _HKI( "Symbols" ), aFrame )
159{
160 m_columns.emplace_back( _HKI( "Reference" ), 2, wxLIST_FORMAT_LEFT );
161 m_columns.emplace_back( _HKI( "Value" ), 6, wxLIST_FORMAT_LEFT );
162 m_columns.emplace_back( _HKI( "Footprint" ), 10, wxLIST_FORMAT_LEFT );
163 m_columns.emplace_back( _HKI( "Page" ), 1, wxLIST_FORMAT_CENTER );
164 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
165 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
166 m_columns.emplace_back( _HKI( "Excl. sim" ), 2, wxLIST_FORMAT_CENTER );
167 m_columns.emplace_back( _HKI( "Excl. BOM" ), 2, wxLIST_FORMAT_CENTER );
168 m_columns.emplace_back( _HKI( "Excl. board" ), 2, wxLIST_FORMAT_CENTER );
169 m_columns.emplace_back( _HKI( "DNP" ), 2, wxLIST_FORMAT_CENTER );
170}
171
172
173int SYMBOL_SEARCH_HANDLER::Search( const wxString& aQuery )
174{
175 m_hitlist.clear();
176
177 SCH_SEARCH_DATA frp;
178 frp.searchAllFields = true;
179 frp.findString = aQuery;
180
181 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
182 frp.matchMode = EDA_SEARCH_MATCH_MODE::PERMISSIVE;
183 frp.searchCurrentSheetOnly = false;
184
185 auto search =
186 [&frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
187 {
188 if( item && item->Type() == SCH_SYMBOL_T )
189 {
190 SCH_SYMBOL* sym = static_cast<SCH_SYMBOL*>( item );
191
192 // IsPower depends on non-missing lib symbol association
193 if( !sym->IsMissingLibSymbol() && sym->IsPower() )
194 return false;
195
196 for( SCH_FIELD& field : sym->GetFields() )
197 {
198 if( frp.findString.IsEmpty() || field.Matches( frp, sheet ) )
199 return true;
200 }
201 }
202
203 return false;
204 };
205
206 FindAll( search );
207
208 return (int) m_hitlist.size();
209}
210
211
213{
214 SCH_SYMBOL*sym = dynamic_cast<SCH_SYMBOL*>( aHit.item );
215
216 if( !sym )
217 return wxEmptyString;
218
219 if( aCol == 0 )
220 return sym->GetRef( aHit.sheetPath, true );
221 else if( aCol == 1 )
222 return sym->GetField( FIELD_T::VALUE )->GetShownText( aHit.sheetPath, false );
223 else if( aCol == 2 )
224 return sym->GetField( FIELD_T::FOOTPRINT )->GetShownText( aHit.sheetPath, false );
225 else if( aCol == 3 )
226 return aHit.sheetPath->GetPageNumber();
227 else if( aCol == 4 )
228 return m_frame->MessageTextFromValue( sym->GetPosition().x );
229 else if( aCol == 5 )
230 return m_frame->MessageTextFromValue( sym->GetPosition().y );
231 else if( aCol == 6 )
232 return sym->GetExcludedFromSim() ? wxS( "X" ) : wxS( " " );
233 else if( aCol == 7 )
234 return sym->GetExcludedFromBOM() ? wxS( "X" ) : wxS( " " );
235 else if( aCol == 8 )
236 return sym->GetExcludedFromBoard() ? wxS( "X" ) : wxS( " " );
237 else if( aCol == 9 )
238 return sym->GetDNP() ? wxS( "X" ) : wxS( " " );
239
240 return wxEmptyString;
241}
242
243
245 SCH_SEARCH_HANDLER( _HKI( "Power" ), aFrame )
246{
247 m_columns.emplace_back( _HKI( "Reference" ), 2, wxLIST_FORMAT_LEFT );
248 m_columns.emplace_back( _HKI( "Value" ), 6, wxLIST_FORMAT_LEFT );
249 m_columns.emplace_back( _HKI( "Page" ), 1, wxLIST_FORMAT_CENTER );
250 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
251 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
252}
253
254
255int POWER_SEARCH_HANDLER::Search( const wxString& aQuery )
256{
257 m_hitlist.clear();
258
259 SCH_SEARCH_DATA frp;
260 frp.searchAllFields = true;
261 frp.findString = aQuery;
262
263 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
264 frp.matchMode = EDA_SEARCH_MATCH_MODE::PERMISSIVE;
265 frp.searchCurrentSheetOnly = false;
266
267 auto search =
268 [&frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
269 {
270 if( item && item->Type() == SCH_SYMBOL_T )
271 {
272 SCH_SYMBOL* sym = static_cast<SCH_SYMBOL*>( item );
273
274 // IsPower depends on non-missing lib symbol association
275 if( sym->IsMissingLibSymbol() || !sym->IsPower() )
276 return false;
277
278 for( SCH_FIELD& field : sym->GetFields() )
279 {
280 if( frp.findString.IsEmpty() || field.Matches( frp, sheet ) )
281 return true;
282 }
283 }
284
285 return false;
286 };
287
288 FindAll( search );
289
290 return (int) m_hitlist.size();
291}
292
293
295{
296 SCH_SYMBOL* sym = dynamic_cast<SCH_SYMBOL*>( aHit.item );
297
298 if( !sym )
299 return wxEmptyString;
300
301 if( aCol == 0 )
302 return sym->GetRef( aHit.sheetPath, true );
303 else if( aCol == 1 )
304 return sym->GetField( FIELD_T::VALUE )->GetShownText( aHit.sheetPath, false );
305 else if( aCol == 2 )
306 return aHit.sheetPath->GetPageNumber();
307 else if( aCol == 3 )
308 return m_frame->MessageTextFromValue( sym->GetPosition().x );
309 else if( aCol == 4 )
310 return m_frame->MessageTextFromValue( sym->GetPosition().y );
311
312 return wxEmptyString;
313}
314
315
317 SCH_SEARCH_HANDLER( _HKI( "Text" ), aFrame )
318{
319 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
320 m_columns.emplace_back( _HKI( "Text" ), 12, wxLIST_FORMAT_LEFT );
321 m_columns.emplace_back( _HKI( "Page" ), 1, wxLIST_FORMAT_CENTER );
322 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
323 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
324}
325
326
327int TEXT_SEARCH_HANDLER::Search( const wxString& aQuery )
328{
329 m_hitlist.clear();
330
331 SCH_SEARCH_DATA frp;
332 frp.searchAllFields = true;
333 frp.findString = aQuery;
334
335 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
336 frp.matchMode = EDA_SEARCH_MATCH_MODE::PERMISSIVE;
337 frp.searchCurrentSheetOnly = false;
338
339 auto search =
340 [&frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
341 {
342 if( item->Type() == SCH_TEXT_T || item->Type() == SCH_TEXTBOX_T )
343 {
344 if( frp.findString.IsEmpty() || item->Matches( frp, sheet ) )
345 return true;
346 }
347
348 return false;
349 };
350
351 FindAll( search );
352
353 return (int) m_hitlist.size();
354}
355
356
357wxString TEXT_SEARCH_HANDLER::getResultCell( const SCH_SEARCH_HIT& aHit, int aCol )
358{
359 if( aHit.item->Type() == SCH_TEXT_T )
360 {
361 SCH_TEXT* txt = dynamic_cast<SCH_TEXT*>( aHit.item );
362
363 if( !txt )
364 return wxEmptyString;
365
366 if( aCol == 0 )
367 return _( "Text" );
368 else if( aCol == 1 )
369 return txt->GetShownText( false );
370 else if( aCol == 2 )
371 return aHit.sheetPath->GetPageNumber();
372 else if( aCol == 3 )
373 return m_frame->MessageTextFromValue( txt->GetPosition().x );
374 else if( aCol == 4 )
375 return m_frame->MessageTextFromValue( txt->GetPosition().y );
376 }
377 else if( aHit.item->Type() == SCH_TEXTBOX_T )
378 {
379 SCH_TEXTBOX* txt = dynamic_cast<SCH_TEXTBOX*>( aHit.item );
380
381 if( !txt )
382 return wxEmptyString;
383
384 if( aCol == 0 )
385 return _( "Text Box" );
386 else if( aCol == 1 )
387 return txt->GetShownText( false );
388 else if( aCol == 2 )
389 return aHit.sheetPath->GetPageNumber();
390 else if( aCol == 3 )
391 return m_frame->MessageTextFromValue( txt->GetPosition().x );
392 else if( aCol == 4 )
393 return m_frame->MessageTextFromValue( txt->GetPosition().y );
394 }
395
396
397 return wxEmptyString;
398}
399
400
402 SCH_SEARCH_HANDLER( _HKI( "Labels" ), aFrame )
403{
404 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
405 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
406 m_columns.emplace_back( _HKI( "Page" ), 2, wxLIST_FORMAT_CENTER );
407 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
408 m_columns.emplace_back( wxT( "Y" ), 3 , wxLIST_FORMAT_CENTER);
409}
410
411
412int LABEL_SEARCH_HANDLER::Search( const wxString& aQuery )
413{
414 m_hitlist.clear();
415
416 SCH_SEARCH_DATA frp;
417 frp.searchAllFields = true;
418 frp.findString = aQuery;
419
420 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
421 frp.matchMode = EDA_SEARCH_MATCH_MODE::PERMISSIVE;
422 frp.searchCurrentSheetOnly = false;
423
424 auto search =
425 [&frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
426 {
427 if( item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
428 {
429 SCH_LABEL_BASE* lbl = dynamic_cast<SCH_LABEL_BASE*>( item );
430
431 wxCHECK( lbl, false );
432
433 if( frp.findString.IsEmpty() || lbl->Matches( frp, sheet ) )
434 return true;
435 }
436
437 return false;
438 };
439
440 FindAll( search );
441
442 return (int) m_hitlist.size();
443}
444
445
447{
448 SCH_LABEL_BASE* lbl = dynamic_cast<SCH_LABEL_BASE*>( aHit.item );
449
450 if( !lbl )
451 return wxEmptyString;
452
453 if (aCol == 0)
454 {
455 if(lbl->Type() == SCH_LABEL_T)
456 return _HKI( "Local" );
457 else if( lbl->Type() == SCH_GLOBAL_LABEL_T )
458 return _HKI( "Global" );
459 else if( lbl->Type() == SCH_HIER_LABEL_T )
460 return _HKI( "Hierarchical" );
461 else if( lbl->Type() == SCH_DIRECTIVE_LABEL_T )
462 return _HKI( "Directive" );
463 }
464 else if( aCol == 1 )
465 return lbl->GetShownText( false );
466 else if( aCol == 2 )
467 return aHit.sheetPath->GetPageNumber();
468 else if( aCol == 3 )
469 return m_frame->MessageTextFromValue( lbl->GetPosition().x );
470 else if( aCol == 4 )
471 return m_frame->MessageTextFromValue( lbl->GetPosition().y );
472
473 return wxEmptyString;
474}
static TOOL_ACTION zoomFitSelection
Definition: actions.h:136
static TOOL_ACTION centerSelection
Definition: actions.h:142
SEARCH_PANE m_SearchPane
Definition: app_settings.h:207
virtual APP_SETTINGS_BASE * config() const
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition: eda_item.h:376
LABEL_SEARCH_HANDLER(SCH_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
wxString getResultCell(const SCH_SEARCH_HIT &hit, int aCol) override
int Search(const wxString &aQuery) override
POWER_SEARCH_HANDLER(SCH_EDIT_FRAME *aFrame)
wxString getResultCell(const SCH_SEARCH_HIT &aHit, int aCol) override
SCH_SHEET & Root() const
Definition: schematic.h:117
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: sch_actions.h:57
static TOOL_ACTION properties
Definition: sch_actions.h:137
static TOOL_ACTION addItemsToSel
Selects a list of items (specified as the event parameter)
Definition: sch_actions.h:64
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Schematic editor (Eeschema) main window.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void SetCurrentSheet(const SCH_SHEET_PATH &aSheet)
void DisplayCurrentSheet()
Draw the current sheet on the display.
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_field.cpp:192
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:167
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition: sch_item.h:182
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const override
Definition: sch_label.cpp:825
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
Definition: sch_label.cpp:853
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:734
SCH_SCREEN * GetNext()
SCH_SCREEN * GetFirst()
void BuildClientSheetPathList()
Build the list of sheet paths sharing a screen for each screen in use.
std::vector< SCH_SEARCH_HIT > m_hitlist
void SelectItems(std::vector< long > &aItemRows) override
void FindAll(const std::function< bool(SCH_ITEM *, SCH_SHEET_PATH *)> &aCollector)
void Sort(int aCol, bool aAscending, std::vector< long > *aSelection) override
void ActivateItem(long aItemRow) override
VECTOR2I GetPosition() const override
Definition: sch_shape.h:83
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
wxString GetPageNumber() const
Schematic symbol object.
Definition: sch_symbol.h:75
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
Definition: sch_symbol.cpp:841
bool IsMissingLibSymbol() const
Check to see if the library symbol is set to the dummy library symbol.
Definition: sch_symbol.cpp:209
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:773
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
Definition: sch_symbol.cpp:611
bool IsPower() const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:813
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
VECTOR2I GetPosition() const override
Definition: sch_text.h:141
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_text.cpp:320
std::vector< std::tuple< wxString, int, wxListColumnFormat > > m_columns
Definition: search_pane.h:61
wxString getResultCell(const SCH_SEARCH_HIT &aHit, int aCol) override
SYMBOL_SEARCH_HANDLER(SCH_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
bool GetExcludedFromBoard() const
Definition: symbol.h:187
bool GetExcludedFromBOM() const
Definition: symbol.h:181
bool GetDNP() const
Set or clear the 'Do Not Populate' flag.
Definition: symbol.h:192
bool GetExcludedFromSim() const override
Definition: symbol.h:175
TEXT_SEARCH_HANDLER(SCH_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
wxString getResultCell(const SCH_SEARCH_HIT &hit, int aCol) override
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
#define _HKI(x)
#define _(s)
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:537
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:100
EDA_SEARCH_MATCH_MODE matchMode
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:171
@ SCH_LABEL_T
Definition: typeinfo.h:167
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:169
@ SCH_TEXT_T
Definition: typeinfo.h:151
@ SCH_TEXTBOX_T
Definition: typeinfo.h:152
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:168