7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 16:53:44 +00:00

Update search dialog

Allow regular expression in search and replace
Allow searching netnames including nets contained in buses

Fixes https://gitlab.com/kicad/code/kicad/-/issues/12156

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17102
This commit is contained in:
Seth Hillbrand 2025-03-03 16:55:11 -08:00
parent 1e9cf4e3d7
commit aff0ad971f
9 changed files with 212 additions and 25 deletions

View File

@ -32,6 +32,7 @@
#include <wx/log.h>
#include <wx/fdrepdlg.h>
#include <wx/regex.h>
#include <eda_pattern_match.h>
EDA_ITEM::EDA_ITEM( EDA_ITEM* parent, KICAD_T idType, bool isSCH_ITEM, bool isBOARD_ITEM ) :
@ -179,6 +180,21 @@ bool EDA_ITEM::Matches( const wxString& aText, const EDA_SEARCH_DATA& aSearchDat
{
return text.Matches( searchText );
}
else if( aSearchData.matchMode == EDA_SEARCH_MATCH_MODE::REGEX )
{
if( aSearchData.regex_string != searchText || !aSearchData.regex.IsValid() )
{
int flag = aSearchData.matchCase ? 0 : wxRE_ICASE;
wxLogNull noLogs;
if( !aSearchData.regex.Compile( searchText, flag ) )
return false;
aSearchData.regex_string = searchText;
}
return aSearchData.regex.Matches( text );
}
else
{
return text.Find( searchText ) != wxNOT_FOUND;
@ -193,6 +209,26 @@ bool EDA_ITEM::Replace( const EDA_SEARCH_DATA& aSearchData, wxString& aText )
wxString result;
bool replaced = false;
if( aSearchData.matchMode == EDA_SEARCH_MATCH_MODE::REGEX )
{
if( aSearchData.regex_string != searchText || !aSearchData.regex.IsValid() )
{
int flag = aSearchData.matchCase ? 0 : wxRE_ICASE;
wxLogNull noLogs;
if( !aSearchData.regex.Compile( searchText, flag ) )
return false;
aSearchData.regex_string = searchText;
}
if( !aSearchData.regex.Replace( &text, aSearchData.replaceString ) )
return false;
aText = text;
return true;
}
if( !aSearchData.matchCase )
{
text = text.Upper();

View File

@ -48,13 +48,12 @@ DIALOG_SCH_FIND::DIALOG_SCH_FIND( SCH_EDIT_FRAME* aParent, SCH_SEARCH_DATA* aDat
m_comboReplace->Show( true );
m_checkSelectedOnly->Show( true );
m_checkReplaceReferences->Show( true );
m_checkWildcardMatch->Show( false ); // Wildcard replace is not implemented.
m_checkRegexMatch->Show( true );
}
m_checkMatchCase->SetValue( m_findReplaceData->matchCase );
m_checkWholeWord->SetValue( m_findReplaceData->matchMode == EDA_SEARCH_MATCH_MODE::WHOLEWORD );
m_checkWildcardMatch->SetValue( m_findReplaceData->matchMode
== EDA_SEARCH_MATCH_MODE::WILDCARD );
m_checkRegexMatch->SetValue( m_findReplaceData->matchMode == EDA_SEARCH_MATCH_MODE::REGEX );
m_checkAllFields->SetValue( m_findReplaceData->searchAllFields );
m_checkReplaceReferences->SetValue( m_findReplaceData->replaceReferences );
@ -62,6 +61,7 @@ DIALOG_SCH_FIND::DIALOG_SCH_FIND( SCH_EDIT_FRAME* aParent, SCH_SEARCH_DATA* aDat
m_checkCurrentSheetOnly->SetValue( m_findReplaceData->searchCurrentSheetOnly );
m_checkCurrentSheetOnly->Enable( !m_findReplaceData->searchSelectedOnly );
m_checkSelectedOnly->SetValue( m_findReplaceData->searchSelectedOnly );
m_checkConnections->SetValue( m_findReplaceData->searchNetNames );
if( int hotkey = ACTIONS::showSearch.GetHotKey() )
{
@ -225,11 +225,12 @@ void DIALOG_SCH_FIND::updateFlags()
m_findReplaceData->searchAllPins = m_checkAllPins->GetValue();
m_findReplaceData->searchCurrentSheetOnly = m_checkCurrentSheetOnly->GetValue();
m_findReplaceData->replaceReferences = m_checkReplaceReferences->GetValue();
m_findReplaceData->searchNetNames = m_checkConnections->GetValue();
if( m_checkWholeWord->GetValue() )
m_findReplaceData->matchMode = EDA_SEARCH_MATCH_MODE::WHOLEWORD;
else if( m_checkWildcardMatch->IsShown() && m_checkWildcardMatch->GetValue() )
m_findReplaceData->matchMode = EDA_SEARCH_MATCH_MODE::WILDCARD;
else if( m_checkRegexMatch->IsShown() && m_checkRegexMatch->GetValue() )
m_findReplaceData->matchMode = EDA_SEARCH_MATCH_MODE::REGEX;
else
m_findReplaceData->matchMode = EDA_SEARCH_MATCH_MODE::PLAIN;

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a-dirty)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -87,11 +87,11 @@ DIALOG_SCH_FIND_BASE::DIALOG_SCH_FIND_BASE( wxWindow* parent, wxWindowID id, con
m_checkWholeWord->SetValue(true);
gbSizer2->Add( m_checkWholeWord, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
m_checkWildcardMatch = new wxCheckBox( this, wxID_ANY, _("Wi&ldcards"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_checkWildcardMatch, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
m_checkRegexMatch = new wxCheckBox( this, wxID_ANY, _("Regular Expression"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_checkRegexMatch, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
m_checkAllPins = new wxCheckBox( this, wxID_ANY, _("Search pin &names and numbers"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_checkAllPins, wxGBPosition( 2, 0 ), wxGBSpan( 1, 3 ), wxBOTTOM|wxRIGHT|wxLEFT, 5 );
gbSizer2->Add( m_checkAllPins, wxGBPosition( 2, 0 ), wxGBSpan( 1, 2 ), wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_checkAllFields = new wxCheckBox( this, wxID_ANY, _("Search &hidden fields"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_checkAllFields, wxGBPosition( 3, 0 ), wxGBSpan( 1, 3 ), wxBOTTOM|wxRIGHT|wxLEFT, 5 );
@ -107,6 +107,9 @@ DIALOG_SCH_FIND_BASE::DIALOG_SCH_FIND_BASE( wxWindow* parent, wxWindowID id, con
gbSizer2->Add( m_checkReplaceReferences, wxGBPosition( 6, 0 ), wxGBSpan( 1, 3 ), wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_checkConnections = new wxCheckBox( this, wxID_ANY, _("Search &net names"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_checkConnections, wxGBPosition( 2, 2 ), wxGBSpan( 1, 1 ), wxBOTTOM|wxLEFT|wxRIGHT, 5 );
leftSizer->Add( gbSizer2, 1, wxEXPAND|wxTOP, 5 );
@ -172,11 +175,12 @@ DIALOG_SCH_FIND_BASE::DIALOG_SCH_FIND_BASE( wxWindow* parent, wxWindowID id, con
m_comboReplace->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateDrcUI ), NULL, this );
m_checkMatchCase->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkWholeWord->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkWildcardMatch->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkRegexMatch->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkAllPins->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkAllFields->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkCurrentSheetOnly->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkSelectedOnly->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkConnections->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_buttonFind->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnFind ), NULL, this );
m_buttonReplace->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnReplace ), NULL, this );
m_buttonReplace->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateReplaceUI ), NULL, this );
@ -201,11 +205,12 @@ DIALOG_SCH_FIND_BASE::~DIALOG_SCH_FIND_BASE()
m_comboReplace->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateDrcUI ), NULL, this );
m_checkMatchCase->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkWholeWord->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkWildcardMatch->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkRegexMatch->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkAllPins->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkAllFields->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkCurrentSheetOnly->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkSelectedOnly->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_checkConnections->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnOptions ), NULL, this );
m_buttonFind->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnFind ), NULL, this );
m_buttonReplace->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnReplace ), NULL, this );
m_buttonReplace->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateReplaceUI ), NULL, this );

View File

@ -759,7 +759,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Wi&amp;ldcards</property>
<property name="label">Regular Expression</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
@ -767,7 +767,7 @@
<property name="minimize_button">0</property>
<property name="minimum_size">-1,-1</property>
<property name="moveable">1</property>
<property name="name">m_checkWildcardMatch</property>
<property name="name">m_checkRegexMatch</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
@ -793,7 +793,7 @@
</object>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">3</property>
<property name="colspan">2</property>
<property name="column">0</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="row">2</property>
@ -1135,6 +1135,75 @@
<property name="window_style"></property>
</object>
</object>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">2</property>
<property name="flag">wxBOTTOM|wxLEFT|wxRIGHT</property>
<property name="row">2</property>
<property name="rowspan">1</property>
<object class="wxCheckBox" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Search &amp;net names</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_checkConnections</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCheckBox">OnOptions</event>
</object>
</object>
</object>
</object>
</object>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a-dirty)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -49,12 +49,13 @@ class DIALOG_SCH_FIND_BASE : public DIALOG_SHIM
wxRadioButton* m_radioBackward;
wxCheckBox* m_checkMatchCase;
wxCheckBox* m_checkWholeWord;
wxCheckBox* m_checkWildcardMatch;
wxCheckBox* m_checkRegexMatch;
wxCheckBox* m_checkAllPins;
wxCheckBox* m_checkAllFields;
wxCheckBox* m_checkCurrentSheetOnly;
wxCheckBox* m_checkSelectedOnly;
wxCheckBox* m_checkReplaceReferences;
wxCheckBox* m_checkConnections;
wxButton* m_buttonFind;
wxButton* m_buttonReplace;
wxButton* m_buttonReplaceAll;

View File

@ -856,7 +856,43 @@ void SCH_LABEL_BASE::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFun
bool SCH_LABEL_BASE::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
{
return SCH_ITEM::Matches( UnescapeString( GetText() ), aSearchData );
if( SCH_ITEM::Matches( UnescapeString( GetText() ), aSearchData ) )
{
return true;
}
const SCH_SEARCH_DATA* searchData = dynamic_cast<const SCH_SEARCH_DATA*>( &aSearchData );
SCH_CONNECTION* connection = nullptr;
SCH_SHEET_PATH* sheetPath = reinterpret_cast<SCH_SHEET_PATH*>( aAuxData );
if( searchData && searchData->searchNetNames && sheetPath
&& ( connection = Connection( sheetPath ) ) )
{
if( connection->IsBus() )
{
auto allMembers = connection->AllMembers();
std::set<wxString> netNames;
for( std::shared_ptr<SCH_CONNECTION> member : allMembers )
netNames.insert( member->GetNetName() );
for( const wxString& netName : netNames )
{
if( EDA_ITEM::Matches( netName, aSearchData ) )
return true;
}
return false;
}
wxString netName = connection->GetNetName();
if( EDA_ITEM::Matches( netName, aSearchData ) )
return true;
}
return false;
}

View File

@ -447,11 +447,25 @@ bool SCH_PIN::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) cons
const SCH_SEARCH_DATA& schSearchData =
dynamic_cast<const SCH_SEARCH_DATA&>( aSearchData );
if( !schSearchData.searchAllPins )
return false;
if( schSearchData.searchAllPins
&& ( EDA_ITEM::Matches( GetName(), aSearchData )
|| EDA_ITEM::Matches( GetNumber(), aSearchData ) ) )
{
return true;
}
return EDA_ITEM::Matches( GetName(), aSearchData )
|| EDA_ITEM::Matches( GetNumber(), aSearchData );
SCH_CONNECTION* connection = nullptr;
SCH_SHEET_PATH* sheetPath = reinterpret_cast<SCH_SHEET_PATH*>( aAuxData );
if( schSearchData.searchNetNames && sheetPath && ( connection = Connection( sheetPath ) ) )
{
wxString netName = connection->GetNetName();
if( EDA_ITEM::Matches( netName, aSearchData ) )
return true;
}
return false;
}

View File

@ -182,7 +182,7 @@ int SYMBOL_SEARCH_HANDLER::Search( const wxString& aQuery )
frp.searchCurrentSheetOnly = false;
auto search =
[frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
[&frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
{
if( item && item->Type() == SCH_SYMBOL_T )
{
@ -263,7 +263,7 @@ int POWER_SEARCH_HANDLER::Search( const wxString& aQuery )
frp.searchCurrentSheetOnly = false;
auto search =
[frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
[&frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
{
if( item && item->Type() == SCH_SYMBOL_T )
{
@ -334,7 +334,7 @@ int TEXT_SEARCH_HANDLER::Search( const wxString& aQuery )
frp.searchCurrentSheetOnly = false;
auto search =
[frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
[&frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
{
if( item->Type() == SCH_TEXT_T || item->Type() == SCH_TEXTBOX_T )
{
@ -418,7 +418,7 @@ int LABEL_SEARCH_HANDLER::Search( const wxString& aQuery )
frp.searchCurrentSheetOnly = false;
auto search =
[frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
[&frp]( SCH_ITEM* item, SCH_SHEET_PATH* sheet )
{
if( item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
{

View File

@ -24,6 +24,8 @@
#ifndef EDA_ITEM_SEARCH_H
#define EDA_ITEM_SEARCH_H
#include <wx/log.h>
#include <wx/regex.h>
#include <wx/string.h>
enum class EDA_SEARCH_MATCH_MODE
@ -31,6 +33,7 @@ enum class EDA_SEARCH_MATCH_MODE
PLAIN,
WHOLEWORD,
WILDCARD,
REGEX,
PERMISSIVE
};
@ -39,6 +42,9 @@ struct EDA_SEARCH_DATA
wxString findString;
wxString replaceString;
mutable wxRegEx regex;
mutable wxString regex_string;
bool searchAndReplace;
bool matchCase;
@ -55,6 +61,23 @@ struct EDA_SEARCH_DATA
{
}
// Need an explicit copy constructor because wxRegEx is not copyable
EDA_SEARCH_DATA( const EDA_SEARCH_DATA& other ) :
findString( other.findString ),
replaceString( other.replaceString ),
regex_string( other.regex_string ),
searchAndReplace( other.searchAndReplace ),
matchCase( other.matchCase ),
markersOnly( other.markersOnly ),
matchMode( other.matchMode )
{
if( matchMode == EDA_SEARCH_MATCH_MODE::REGEX )
{
wxLogNull noLogs;
regex.Compile( findString, matchCase ? wxRE_DEFAULT : wxRE_ICASE );
}
}
virtual ~EDA_SEARCH_DATA() {}
};
@ -64,6 +87,7 @@ struct SCH_SEARCH_DATA : public EDA_SEARCH_DATA
bool searchAllPins;
bool searchCurrentSheetOnly;
bool searchSelectedOnly;
bool searchNetNames;
bool replaceReferences;
@ -73,6 +97,7 @@ struct SCH_SEARCH_DATA : public EDA_SEARCH_DATA
searchAllPins( false ),
searchCurrentSheetOnly( false ),
searchSelectedOnly( false ),
searchNetNames( false ),
replaceReferences( false )
{
}