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
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 )
69{
70 int col = std::max( 0, aCol ); // Provide a stable order by sorting on first column if no
71 // sort column provided.
72
73 std::sort( m_hitlist.begin(), m_hitlist.end(),
74 [&]( const SCH_SEARCH_HIT& a, const SCH_SEARCH_HIT& b ) -> bool
75 {
76 // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
77 // to get the opposite sort. i.e. ~(a<b) != (a>b)
78 if( aAscending )
79 return StrNumCmp( getResultCell( a, col ), getResultCell( b, col ), true ) < 0;
80 else
81 return StrNumCmp( getResultCell( b, col ), getResultCell( a, col ), true ) < 0;
82 } );
83}
84
85
86void SCH_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
87{
88 EDA_ITEMS selectedItems;
89 std::vector<SCH_SEARCH_HIT> selectedHits;
90
92
93 for( long row : aItemRows )
94 {
95 if( row >= 0 && row < (long) m_hitlist.size() )
96 {
97 selectedHits.emplace_back( m_hitlist[row] );
98 selectedItems.emplace_back( m_hitlist[row].item );
99 }
100 }
101
102 if( selectedHits.empty() )
103 return;
104
105 bool allHitsOnSamePage = std::all_of( selectedHits.begin() + 1, selectedHits.end(),
106 [&]( const SCH_SEARCH_HIT& r )
107 {
108 return r.sheetPath == selectedHits.front().sheetPath;
109 } );
110
111 if( allHitsOnSamePage && !selectedHits.empty() )
112 {
113 if( m_frame->GetCurrentSheet() != *selectedHits.front().sheetPath )
114 {
115 m_frame->SetCurrentSheet( *selectedHits.front().sheetPath );
117 }
118
119 if( selectedItems.size() )
121
122 m_frame->GetCanvas()->Refresh( false );
123 }
124}
125
126
128 SCH_SEARCH_HANDLER( _HKI( "Symbols" ), aFrame )
129{
130 m_columns.emplace_back( _HKI( "Reference" ), 2, wxLIST_FORMAT_LEFT );
131 m_columns.emplace_back( _HKI( "Value" ), 6, wxLIST_FORMAT_LEFT );
132 m_columns.emplace_back( _HKI( "Footprint" ), 10, wxLIST_FORMAT_LEFT );
133 m_columns.emplace_back( _HKI( "Page" ), 1, wxLIST_FORMAT_CENTER );
134 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
135 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
136 m_columns.emplace_back( _HKI( "Excl. sim" ), 2, wxLIST_FORMAT_CENTER );
137 m_columns.emplace_back( _HKI( "Excl. BOM" ), 2, wxLIST_FORMAT_CENTER );
138 m_columns.emplace_back( _HKI( "Excl. board" ), 2, wxLIST_FORMAT_CENTER );
139 m_columns.emplace_back( _HKI( "DNP" ), 2, wxLIST_FORMAT_CENTER );
140}
141
142
143int SYMBOL_SEARCH_HANDLER::Search( const wxString& aQuery )
144{
145 m_hitlist.clear();
146
147 SCH_SEARCH_DATA frp;
148 frp.findString = aQuery;
149
150 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
151 frp.matchMode = EDA_SEARCH_MATCH_MODE::PERMISSIVE;
152 frp.searchCurrentSheetOnly = false;
153
154 auto search =
155 [frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
156 {
157 if( item && item->Type() == SCH_SYMBOL_T )
158 {
159 SCH_SYMBOL* sym = static_cast<SCH_SYMBOL*>( item );
160
161 // IsPower depends on non-missing lib symbol association
162 if( !sym->IsMissingLibSymbol() && sym->IsPower() )
163 return false;
164
165 for( SCH_FIELD& field : sym->GetFields() )
166 {
167 if( frp.findString.IsEmpty() || field.Matches( frp, sheet ) )
168 return true;
169 }
170 }
171
172 return false;
173 };
174
175 FindAll( search );
176
177 return (int) m_hitlist.size();
178}
179
180
182{
183 SCH_SYMBOL*sym = dynamic_cast<SCH_SYMBOL*>( aHit.item );
184
185 if( !sym )
186 return wxEmptyString;
187
188 if( aCol == 0 )
189 return sym->GetRef( aHit.sheetPath, true );
190 else if( aCol == 1 )
191 return sym->GetField( VALUE_FIELD )->GetShownText( aHit.sheetPath, false );
192 else if( aCol == 2 )
193 return sym->GetField( FOOTPRINT_FIELD )->GetShownText( aHit.sheetPath, false );
194 else if( aCol == 3 )
195 return aHit.sheetPath->GetPageNumber();
196 else if( aCol == 4 )
197 return m_frame->MessageTextFromValue( sym->GetPosition().x );
198 else if( aCol == 5 )
199 return m_frame->MessageTextFromValue( sym->GetPosition().y );
200 else if( aCol == 6 )
201 return sym->GetExcludedFromSim() ? wxS( "X" ) : wxS( " " );
202 else if( aCol == 7 )
203 return sym->GetExcludedFromBOM() ? wxS( "X" ) : wxS( " " );
204 else if( aCol == 8 )
205 return sym->GetExcludedFromBoard() ? wxS( "X" ) : wxS( " " );
206 else if( aCol == 9 )
207 return sym->GetDNP() ? wxS( "X" ) : wxS( " " );
208
209 return wxEmptyString;
210}
211
212
214 SCH_SEARCH_HANDLER( _HKI( "Text" ), aFrame )
215{
216 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
217 m_columns.emplace_back( _HKI( "Text" ), 12, wxLIST_FORMAT_LEFT );
218 m_columns.emplace_back( _HKI( "Page" ), 1, wxLIST_FORMAT_CENTER );
219 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
220 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
221}
222
223
224int TEXT_SEARCH_HANDLER::Search( const wxString& aQuery )
225{
226 m_hitlist.clear();
227
228 SCH_SEARCH_DATA frp;
229 frp.findString = aQuery;
230
231 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
232 frp.matchMode = EDA_SEARCH_MATCH_MODE::PERMISSIVE;
233 frp.searchCurrentSheetOnly = false;
234
235 auto search =
236 [frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
237 {
238 if( item->Type() == SCH_TEXT_T || item->Type() == SCH_TEXTBOX_T )
239 {
240 if( frp.findString.IsEmpty() || item->Matches( frp, sheet ) )
241 return true;
242 }
243
244 return false;
245 };
246
247 FindAll( search );
248
249 return (int) m_hitlist.size();
250}
251
252
253wxString TEXT_SEARCH_HANDLER::getResultCell( const SCH_SEARCH_HIT& aHit, int aCol )
254{
255 if( aHit.item->Type() == SCH_TEXT_T )
256 {
257 SCH_TEXT* txt = dynamic_cast<SCH_TEXT*>( aHit.item );
258
259 if( !txt )
260 return wxEmptyString;
261
262 if( aCol == 0 )
263 return _( "Text" );
264 else if( aCol == 1 )
265 return txt->GetShownText( false );
266 else if( aCol == 2 )
267 return aHit.sheetPath->GetPageNumber();
268 else if( aCol == 3 )
269 return m_frame->MessageTextFromValue( txt->GetPosition().x );
270 else if( aCol == 4 )
271 return m_frame->MessageTextFromValue( txt->GetPosition().y );
272 }
273 else if( aHit.item->Type() == SCH_TEXTBOX_T )
274 {
275 SCH_TEXTBOX* txt = dynamic_cast<SCH_TEXTBOX*>( aHit.item );
276
277 if( !txt )
278 return wxEmptyString;
279
280 if( aCol == 0 )
281 return _( "Text Box" );
282 else if( aCol == 1 )
283 return txt->GetShownText( false );
284 else if( aCol == 2 )
285 return aHit.sheetPath->GetPageNumber();
286 else if( aCol == 3 )
287 return m_frame->MessageTextFromValue( txt->GetPosition().x );
288 else if( aCol == 4 )
289 return m_frame->MessageTextFromValue( txt->GetPosition().y );
290 }
291
292
293 return wxEmptyString;
294}
295
296
298 SCH_SEARCH_HANDLER( _HKI( "Labels" ), aFrame )
299{
300 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
301 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
302 m_columns.emplace_back( _HKI( "Page" ), 2, wxLIST_FORMAT_CENTER );
303 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
304 m_columns.emplace_back( wxT( "Y" ), 3 , wxLIST_FORMAT_CENTER);
305}
306
307
308int LABEL_SEARCH_HANDLER::Search( const wxString& aQuery )
309{
310 m_hitlist.clear();
311
312 SCH_SEARCH_DATA frp;
313 frp.findString = aQuery;
314
315 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
316 frp.matchMode = EDA_SEARCH_MATCH_MODE::PERMISSIVE;
317 frp.searchCurrentSheetOnly = false;
318
319 auto search =
320 [frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
321 {
322 if( item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
323 {
324 SCH_LABEL_BASE* lbl = dynamic_cast<SCH_LABEL_BASE*>( item );
325
326 wxCHECK( lbl, false );
327
328 if( frp.findString.IsEmpty() || lbl->Matches( frp, sheet ) )
329 return true;
330 }
331
332 return false;
333 };
334
335 FindAll( search );
336
337 return (int) m_hitlist.size();
338}
339
340
342{
343 SCH_LABEL_BASE* lbl = dynamic_cast<SCH_LABEL_BASE*>( aHit.item );
344
345 if( !lbl )
346 return wxEmptyString;
347
348 if (aCol == 0)
349 {
350 if(lbl->Type() == SCH_LABEL_T)
351 return _HKI( "Local" );
352 else if( lbl->Type() == SCH_GLOBAL_LABEL_T )
353 return _HKI( "Global" );
354 else if( lbl->Type() == SCH_HIER_LABEL_T )
355 return _HKI( "Hierarchical" );
356 else if( lbl->Type() == SCH_DIRECTIVE_LABEL_T )
357 return _HKI( "Directive" );
358 }
359 else if( aCol == 1 )
360 return lbl->GetShownText( false );
361 else if( aCol == 2 )
362 return aHit.sheetPath->GetPageNumber();
363 else if( aCol == 3 )
364 return m_frame->MessageTextFromValue( lbl->GetPosition().x );
365 else if( aCol == 4 )
366 return m_frame->MessageTextFromValue( lbl->GetPosition().y );
367
368 return wxEmptyString;
369}
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition: eda_item.h:375
static TOOL_ACTION properties
Definition: ee_actions.h:126
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:51
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_field.cpp:197
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:172
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition: sch_item.h:187
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const override
Definition: sch_label.cpp:892
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
Definition: sch_label.cpp:924
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:704
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:78
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:108
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:923
bool GetExcludedFromBOM() const
Definition: sch_symbol.h:837
bool IsMissingLibSymbol() const
Check to see if the library symbol is set to the dummy library symbol.
Definition: sch_symbol.cpp:240
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:772
bool GetExcludedFromSim() const override
Definition: sch_symbol.h:834
bool GetExcludedFromBoard() const
Definition: sch_symbol.h:840
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
Definition: sch_symbol.cpp:971
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
Definition: sch_symbol.cpp:724
bool IsPower() const override
bool GetDNP() const
Definition: sch_symbol.h:843
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
VECTOR2I GetPosition() const override
Definition: sch_text.h:132
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_text.cpp:250
std::vector< std::tuple< wxString, int, wxListColumnFormat > > m_columns
Definition: search_pane.h:53
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) 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:532
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:160
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:158
@ SCH_LABEL_T
Definition: typeinfo.h:155
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:157
@ SCH_TEXT_T
Definition: typeinfo.h:152
@ SCH_TEXTBOX_T
Definition: typeinfo.h:151
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:156