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 (C) 2022-2023 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 <ee_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}
38
39
40void SCH_SEARCH_HANDLER::FindAll( const std::function<bool( SCH_ITEM*, SCH_SHEET_PATH* )>& aCollector )
41{
42 SCH_SCREENS screens( m_frame->Schematic().Root() );
43 std::vector<SCH_SHEET_PATH*> paths;
44
45 m_hitlist.clear();
46
48
49 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
50 {
51 for( SCH_SHEET_PATH& sheet : screen->GetClientSheetPaths() )
52 paths.push_back( &sheet );
53 }
54
55 for( SCH_SHEET_PATH* sheet : paths )
56 {
57 for( SCH_ITEM* item : sheet->LastScreen()->Items() )
58 {
59 if( aCollector( item, sheet ) )
60 m_hitlist.push_back( { item, sheet } );
61 }
62 }
63}
64
65
66void SCH_SEARCH_HANDLER::Sort( int aCol, bool aAscending )
67{
68 std::sort( m_hitlist.begin(), m_hitlist.end(),
69 [&]( const SCH_SEARCH_HIT& a, const SCH_SEARCH_HIT& b ) -> bool
70 {
71 // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
72 // to get the opposite sort. i.e. ~(a<b) != (a>b)
73 if( aAscending )
74 return StrNumCmp( getResultCell( a, aCol ), getResultCell( b, aCol ), true ) < 0;
75 else
76 return StrNumCmp( getResultCell( b, aCol ), getResultCell( a, aCol ), true ) < 0;
77 } );
78}
79
80
81void SCH_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
82{
83 EDA_ITEMS selectedItems;
84 std::vector<SCH_SEARCH_HIT> selectedHits;
85
87
88 for( long row : aItemRows )
89 {
90 if( row >= 0 && row < (long) m_hitlist.size() )
91 {
92 selectedHits.emplace_back( m_hitlist[row] );
93 selectedItems.emplace_back( m_hitlist[row].item );
94 }
95 }
96
97 if( selectedHits.empty() )
98 return;
99
100 bool allHitsOnSamePage = std::all_of( selectedHits.begin() + 1, selectedHits.end(),
101 [&]( const SCH_SEARCH_HIT& r )
102 {
103 return r.sheetPath == selectedHits.front().sheetPath;
104 } );
105
106 if( allHitsOnSamePage && !selectedHits.empty() )
107 {
108 if( m_frame->GetCurrentSheet() != *selectedHits.front().sheetPath )
109 {
110 m_frame->SetCurrentSheet( *selectedHits.front().sheetPath );
112 }
113
114 if( selectedItems.size() )
116
117 m_frame->GetCanvas()->Refresh( false );
118 }
119}
120
121
123 SCH_SEARCH_HANDLER( wxT( "Symbols" ), aFrame )
124{
125 m_columns.emplace_back( wxT( "Reference" ), 1 );
126 m_columns.emplace_back( wxT( "Value" ), 3 );
127 m_columns.emplace_back( wxT( "Footprint" ), 3 );
128 m_columns.emplace_back( wxT( "Page" ), 1 );
129 m_columns.emplace_back( wxT( "X" ), 2 );
130 m_columns.emplace_back( wxT( "Y" ), 2 );
131}
132
133
134int SYMBOL_SEARCH_HANDLER::Search( const wxString& aQuery )
135{
136 m_hitlist.clear();
137
138 SCH_SEARCH_DATA frp;
139 frp.findString = aQuery;
140
141 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
142 frp.matchMode = EDA_SEARCH_MATCH_MODE::PERMISSIVE;
143 frp.searchCurrentSheetOnly = false;
144
145 auto search =
146 [frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
147 {
148 if( item->Type() == SCH_SYMBOL_T )
149 {
150 SCH_SYMBOL* sym = dynamic_cast<SCH_SYMBOL*>( item );
151
152 if( sym->IsPower() )
153 return false;
154
155 for( SCH_FIELD& field : sym->GetFields() )
156 {
157 if( frp.findString.IsEmpty() || field.Matches( frp, sheet ) )
158 return true;
159 }
160 }
161
162 return false;
163 };
164
165 FindAll( search );
166
167 return (int) m_hitlist.size();
168}
169
170
172{
173 SCH_SYMBOL*sym = dynamic_cast<SCH_SYMBOL*>( aHit.item );
174
175 if( !sym )
176 return wxEmptyString;
177
178 if( aCol == 0 )
179 return sym->GetRef( aHit.sheetPath, true );
180 else if( aCol == 1 )
181 return sym->GetField( VALUE_FIELD )->GetShownText( aHit.sheetPath, false );
182 else if( aCol == 2 )
183 return sym->GetField( FOOTPRINT_FIELD )->GetShownText( aHit.sheetPath, false );
184 else if( aCol == 3 )
185 return aHit.sheetPath->GetPageNumber();
186 else if( aCol == 4 )
187 return m_frame->MessageTextFromValue( sym->GetPosition().x );
188 else if( aCol == 5 )
189 return m_frame->MessageTextFromValue( sym->GetPosition().y );
190
191
192 return wxEmptyString;
193}
194
195
197 SCH_SEARCH_HANDLER( wxT( "Text" ), aFrame )
198{
199 m_columns.emplace_back( wxT( "Type" ), 1 );
200 m_columns.emplace_back( wxT( "Text" ), 5 );
201 m_columns.emplace_back( wxT( "Page" ), 1 );
202 m_columns.emplace_back( wxT( "X" ), 2 );
203 m_columns.emplace_back( wxT( "Y" ), 2 );
204}
205
206
207int TEXT_SEARCH_HANDLER::Search( const wxString& aQuery )
208{
209 m_hitlist.clear();
210
211 SCH_SEARCH_DATA frp;
212 frp.findString = aQuery;
213
214 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
215 frp.matchMode = EDA_SEARCH_MATCH_MODE::PERMISSIVE;
216 frp.searchCurrentSheetOnly = false;
217
218 auto search =
219 [frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
220 {
221 if( item->Type() == SCH_TEXT_T || item->Type() == SCH_TEXTBOX_T )
222 {
223 if( frp.findString.IsEmpty() || item->Matches( frp, sheet ) )
224 return true;
225 }
226
227 return false;
228 };
229
230 FindAll( search );
231
232 return (int) m_hitlist.size();
233}
234
235
236wxString TEXT_SEARCH_HANDLER::getResultCell( const SCH_SEARCH_HIT& aHit, int aCol )
237{
238 if( aHit.item->Type() == SCH_TEXT_T )
239 {
240 SCH_TEXT* txt = dynamic_cast<SCH_TEXT*>( aHit.item );
241
242 if( !txt )
243 return wxEmptyString;
244
245 if( aCol == 0 )
246 return wxS( "Text" );
247 else if( aCol == 1 )
248 return txt->GetShownText( false );
249 else if( aCol == 2 )
250 return aHit.sheetPath->GetPageNumber();
251 else if( aCol == 3 )
252 return m_frame->MessageTextFromValue( txt->GetPosition().x );
253 else if( aCol == 4 )
254 return m_frame->MessageTextFromValue( txt->GetPosition().y );
255 }
256 else if( aHit.item->Type() == SCH_TEXTBOX_T )
257 {
258 SCH_TEXTBOX* txt = dynamic_cast<SCH_TEXTBOX*>( aHit.item );
259
260 if( !txt )
261 return wxEmptyString;
262
263 if( aCol == 0 )
264 return wxS( "Text" );
265 else if( aCol == 1 )
266 return txt->GetShownText( false );
267 else if( aCol == 2 )
268 return aHit.sheetPath->GetPageNumber();
269 else if( aCol == 3 )
270 return m_frame->MessageTextFromValue( txt->GetPosition().x );
271 else if( aCol == 4 )
272 return m_frame->MessageTextFromValue( txt->GetPosition().y );
273 }
274
275
276 return wxEmptyString;
277}
278
279
281 SCH_SEARCH_HANDLER( wxT( "Labels" ), aFrame )
282{
283 m_columns.emplace_back( wxT( "Type" ), 1 );
284 m_columns.emplace_back( wxT( "Name" ), 4 );
285 m_columns.emplace_back( wxT( "Page" ), 1 );
286 m_columns.emplace_back( wxT( "X" ), 2 );
287 m_columns.emplace_back( wxT( "Y" ), 2 );
288}
289
290
291int LABEL_SEARCH_HANDLER::Search( const wxString& aQuery )
292{
293 m_hitlist.clear();
294
295 SCH_SEARCH_DATA frp;
296 frp.findString = aQuery;
297
298 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
299 frp.matchMode = EDA_SEARCH_MATCH_MODE::PERMISSIVE;
300 frp.searchCurrentSheetOnly = false;
301
302 auto search =
303 [frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
304 {
305 if( item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
306 {
307 SCH_LABEL_BASE* lbl = dynamic_cast<SCH_LABEL_BASE*>( item );
308
309 wxCHECK( lbl, false );
310
311 if( frp.findString.IsEmpty() || lbl->Matches( frp, sheet ) )
312 return true;
313 }
314
315 return false;
316 };
317
318 FindAll( search );
319
320 return (int) m_hitlist.size();
321}
322
323
325{
326 SCH_LABEL_BASE* lbl = dynamic_cast<SCH_LABEL_BASE*>( aHit.item );
327
328 if( !lbl )
329 return wxEmptyString;
330
331 if (aCol == 0)
332 {
333 if(lbl->Type() == SCH_LABEL_T)
334 return wxS( "Local" );
335 else if( lbl->Type() == SCH_GLOBAL_LABEL_T )
336 return wxS( "Global" );
337 else if( lbl->Type() == SCH_HIER_LABEL_T )
338 return wxS( "Hierarchical" );
339 else if( lbl->Type() == SCH_DIRECTIVE_LABEL_T )
340 return wxS( "Directive" );
341 }
342 else if( aCol == 1 )
343 return lbl->GetShownText( false );
344 else if( aCol == 2 )
345 return aHit.sheetPath->GetPageNumber();
346 else if( aCol == 3 )
347 return m_frame->MessageTextFromValue( lbl->GetPosition().x );
348 else if( aCol == 4 )
349 return m_frame->MessageTextFromValue( lbl->GetPosition().y );
350
351 return wxEmptyString;
352}
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition: eda_item.h:372
static TOOL_ACTION addItemsToSel
Selects a list of items (specified as the event parameter)
Definition: ee_actions.h:63
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
LABEL_SEARCH_HANDLER(SCH_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
wxString getResultCell(const SCH_SEARCH_HIT &hit, int aCol) override
SCH_SHEET & Root() const
Definition: schematic.h:105
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.
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:52
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_field.cpp:188
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:150
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition: sch_item.h:165
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const override
Definition: sch_label.cpp:831
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
Definition: sch_label.cpp:863
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:673
SCH_SCREEN * GetNext()
SCH_SCREEN * GetFirst()
void BuildClientSheetPathList()
built 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) override
void ActivateItem(long aItemRow) override
VECTOR2I GetPosition() const override
Definition: sch_shape.h:77
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:81
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:720
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:913
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:703
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
Definition: sch_symbol.cpp:973
bool IsPower() const
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
VECTOR2I GetPosition() const override
Definition: sch_text.h:126
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_text.cpp:266
std::vector< std::pair< wxString, int > > m_columns
Definition: search_pane.h:49
wxString getResultCell(const SCH_SEARCH_HIT &aHit, int aCol) override
SYMBOL_SEARCH_HANDLER(SCH_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
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:145
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A lower-precision version of StringFromValue().
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:513
EDA_SEARCH_MATCH_MODE matchMode
@ FOOTPRINT_FIELD
Field Name Module PCB, i.e. "16DIP300".
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ SCH_SYMBOL_T
Definition: typeinfo.h:155
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:153
@ SCH_LABEL_T
Definition: typeinfo.h:150
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:152
@ SCH_TEXT_T
Definition: typeinfo.h:149
@ SCH_TEXTBOX_T
Definition: typeinfo.h:148
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:151