← Back to team overview

kicad-developers team mailing list archive

[PATCH] Eeschema: add wildcard and regex support to component chooser

 

As discussed earlier today, this patch adds support for both wildcard 
and regular expression search to the eeschema component chooser. An 
option is added to eeschema options to select the "Component search 
method", which defaults to "Simple" (the original behavior). Regular 
expression search was added as a "bonus", as it was used as a stepping 
stone to wildcard search.

The existing behavior of Henner's component chooser wasn't changed, just 
the matching function it uses.

Following Wayne's suggestion, an EDA_PATTERN_MATCH base class is defined 
in include/eda_pattern_match.h, and then:

- EDA_PATTERN_MATCH_SUBSTR implements EDA_PATTERN_MATCH with the old 
  behavior

- EDA_PATTERN_MATCH_REGEX implements EDA_PATTERN_MATCH providing regex 
  search via wxRegEx and wxRE_ADVANCED.

- EDA_PATTERN_MATCH_WILDCARD extends EDA_PATTERN_MATCH_REGEX, 
  translating a wildcard string to a regular expression and then loading 
  it into the latter. This allows the nice, fast, wxString-compatible, 
  and well tested regex search to be reused for wildcard search.

--
Chris
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 2726718..45a5a24 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -201,6 +201,7 @@ set( COMMON_SRCS
     dsnlexer.cpp
     eda_dde.cpp
     eda_doc.cpp
+    eda_pattern_match.cpp
     filter_reader.cpp
 #    findkicadhelppath.cpp.notused      deprecated, use searchhelpfilefullpath.cpp
     gestfich.cpp
diff --git a/common/eda_pattern_match.cpp b/common/eda_pattern_match.cpp
new file mode 100644
index 0000000..53492b7
--- /dev/null
+++ b/common/eda_pattern_match.cpp
@@ -0,0 +1,179 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Chris Pavlina <pavlina.chris@xxxxxxxxx>
+ * Copyright (C) 2015 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include <eda_pattern_match.h>
+#include <wx/log.h>
+#include <climits>
+
+void EDA_PATTERN_MATCH_SUBSTR::SetPattern( const wxString& aPattern )
+{
+    m_pattern = aPattern;
+}
+
+
+int EDA_PATTERN_MATCH_SUBSTR::Find( const wxString& aCandidate )
+{
+    int loc = aCandidate.Find( m_pattern );
+
+    return ( loc == wxNOT_FOUND ) ? EDA_PATTERN_NOT_FOUND : loc;
+}
+
+
+/**
+ * Context class to set wx loglevel for a block, and always restore it at the end.
+ */
+class WX_LOGLEVEL_CONTEXT
+{
+    wxLogLevel m_old_level;
+
+public:
+    WX_LOGLEVEL_CONTEXT( wxLogLevel level )
+    {
+        m_old_level = wxLog::GetLogLevel();
+        wxLog::SetLogLevel( level );
+    }
+
+    ~WX_LOGLEVEL_CONTEXT()
+    {
+        wxLog::SetLogLevel( m_old_level );
+    }
+};
+
+
+void EDA_PATTERN_MATCH_REGEX::SetPattern( const wxString& aPattern )
+{
+    m_pattern = aPattern;
+
+    // Evil and undocumented: wxRegEx::Compile calls wxLogError on error, even
+    // though it promises to just return false. Silence the error.
+    WX_LOGLEVEL_CONTEXT ctx( wxLOG_FatalError );
+
+    m_regex.Compile( aPattern, wxRE_ADVANCED );
+}
+
+
+int EDA_PATTERN_MATCH_REGEX::Find( const wxString& aCandidate )
+{
+    if( m_regex.IsValid() )
+    {
+        if( m_regex.Matches( aCandidate ) )
+        {
+            size_t start, len;
+            m_regex.GetMatch( &start, &len, 0 );
+            return ( start > INT_MAX ) ? INT_MAX : start;
+        }
+        else
+        {
+            return EDA_PATTERN_NOT_FOUND;
+        }
+    }
+    else
+    {
+        int loc = aCandidate.Find( m_pattern );
+        return ( loc == wxNOT_FOUND ) ? EDA_PATTERN_NOT_FOUND : loc;
+    }
+}
+
+
+void EDA_PATTERN_MATCH_WILDCARD::SetPattern( const wxString& aPattern )
+{
+    // Compile the wildcard string to a regular expression
+    wxString regex;
+    regex.Alloc( 2 * aPattern.Length() );   // no need to keep resizing, we know the size roughly
+
+    const wxString to_replace = wxT( ".*+?^${}()|[]/\\" );
+
+    for( wxString::const_iterator it = aPattern.begin(); it < aPattern.end(); ++it )
+    {
+        wxUniChar c = *it;
+        if( c == '?' )
+        {
+            regex += wxT( "." );
+        }
+        else if( c == '*' )
+        {
+            regex += wxT( ".*" );
+        }
+        else if( to_replace.Find( c ) != wxNOT_FOUND )
+        {
+            regex += "\\";
+            regex += c;
+        }
+        else
+        {
+            regex += c;
+        }
+    }
+
+    EDA_PATTERN_MATCH_REGEX::SetPattern( regex );
+}
+
+
+int EDA_PATTERN_MATCH_WILDCARD::Find( const wxString& aCandidate )
+{
+    return EDA_PATTERN_MATCH_REGEX::Find( aCandidate );
+}
+
+void EDA_PATTERN_MATCH::GetPatternMatcherIds( std::vector<wxString>& aList )
+{
+    aList.push_back( wxT( "SUBSTR" ) );
+    aList.push_back( wxT( "WILDCARD" ) );
+    aList.push_back( wxT( "REGEX" ) );
+}
+
+wxString EDA_PATTERN_MATCH::GetPatternMatcherName( const wxString& aId )
+{
+    if( aId == wxT( "SUBSTR" ) || aId == wxEmptyString )
+        return _( "Simple" );
+
+    else if( aId == wxT( "WILDCARD" ) )
+        return _( "Wildcard" );
+
+    else if( aId == wxT( "REGEX" ) )
+        return _( "Regular expression" );
+
+    else
+    {
+        wxFAIL_MSG( "Invalid pattern matcher ID" );
+        return wxEmptyString;
+    }
+}
+
+EDA_PATTERN_MATCH* EDA_PATTERN_MATCH::CreatePatternMatcher( const wxString& aId )
+{
+    if( aId == wxT( "SUBSTR" ) || aId == wxEmptyString )
+        return new EDA_PATTERN_MATCH_SUBSTR();
+
+    else if( aId == wxT( "WILDCARD" ) )
+        return new EDA_PATTERN_MATCH_WILDCARD();
+
+    else if( aId == wxT( "REGEX" ) )
+        return new EDA_PATTERN_MATCH_REGEX();
+
+    else
+    {
+        wxFAIL_MSG( "Invalid pattern matcher ID" );
+        return new EDA_PATTERN_MATCH_SUBSTR();
+    }
+}
diff --git a/eeschema/component_tree_search_container.cpp b/eeschema/component_tree_search_container.cpp
index c3061f9..d9e38a3 100644
--- a/eeschema/component_tree_search_container.cpp
+++ b/eeschema/component_tree_search_container.cpp
@@ -26,6 +26,7 @@
 #include <algorithm>
 #include <boost/foreach.hpp>
 #include <set>
+#include <memory>
 
 #include <wx/string.h>
 #include <wx/tokenzr.h>
@@ -35,6 +36,10 @@
 #include <class_library.h>
 #include <macros.h>
 
+#include <kiface_i.h>
+#include <eeschema_config.h>
+#include <eda_pattern_match.h>
+
 // Each node gets this lowest score initially, without any matches applied. Matches
 // will then increase this score depending on match quality.
 // This way, an empty search string will result in all components being displayed as they
@@ -259,6 +264,10 @@ void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch
     unsigned starttime =  GetRunningMicroSecs();
 #endif
 
+    wxString m_id;
+    Kiface().KifaceSettings()->Read( COMPONENT_SEARCH_METHOD_KEY, &m_id, wxEmptyString );
+    std::auto_ptr<EDA_PATTERN_MATCH> matcher( EDA_PATTERN_MATCH::CreatePatternMatcher( m_id ) );
+
     // We score the list by going through it several time, essentially with a complexity
     // of O(n). For the default library of 2000+ items, this typically takes less than 5ms
     // on an i5. Good enough, no index needed.
@@ -286,6 +295,7 @@ void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch
     while ( tokenizer.HasMoreTokens() )
     {
         const wxString term = tokenizer.GetNextToken().Lower();
+        matcher->SetPattern( term );
 
         BOOST_FOREACH( TREE_NODE* node, m_nodes )
         {
@@ -302,14 +312,14 @@ void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch
 
             if( term == node->MatchName )
                 node->MatchScore += 1000;  // exact match. High score :)
-            else if( (found_pos = node->MatchName.Find( term ) ) != wxNOT_FOUND )
+            else if( (found_pos = matcher->Find( node->MatchName ) ) != EDA_PATTERN_NOT_FOUND )
             {
                 // Substring match. The earlier in the string the better.  score += 20..40
                 node->MatchScore += matchPosScore( found_pos, 20 ) + 20;
             }
-            else if( node->Parent->MatchName.Find( term ) != wxNOT_FOUND )
+            else if( matcher->Find( node->Parent->MatchName ) != EDA_PATTERN_NOT_FOUND )
                 node->MatchScore += 19;   // parent name matches.         score += 19
-            else if( ( found_pos = node->SearchText.Find( term ) ) != wxNOT_FOUND )
+            else if( ( found_pos = matcher->Find( node->SearchText ) ) != EDA_PATTERN_NOT_FOUND )
             {
                 // If we have a very short search term (like one or two letters), we don't want
                 // to accumulate scores if they just happen to be in keywords or description as
diff --git a/eeschema/dialogs/dialog_eeschema_options.cpp b/eeschema/dialogs/dialog_eeschema_options.cpp
index 6ee6480..5f051ca 100644
--- a/eeschema/dialogs/dialog_eeschema_options.cpp
+++ b/eeschema/dialogs/dialog_eeschema_options.cpp
@@ -161,6 +161,38 @@ void DIALOG_EESCHEMA_OPTIONS::SetGridSizes( const GRIDS& aGridSizes, int aGridId
 }
 
 
+wxString DIALOG_EESCHEMA_OPTIONS::GetComponentSearchMethod()
+{
+    int sel = m_choiceComponentSearchMethod->GetSelection();
+
+    if( sel == wxNOT_FOUND )
+        return wxEmptyString;
+
+    wxClientData* cd_raw = m_choiceComponentSearchMethod->GetClientObject( sel );
+    wxStringClientData* clientdata = static_cast<wxStringClientData*>( cd_raw );
+    return clientdata->GetData();
+}
+
+
+void DIALOG_EESCHEMA_OPTIONS::SetComponentSearchMethods( const std::vector<wxString>& aIds,
+        const std::vector<wxString>& aNames, const wxString& aId )
+{
+    wxASSERT( aIds.size() > 0 );
+    wxASSERT( aIds.size() == aNames.size() );
+
+    int select = 0;
+
+    for( size_t i = 0; i < aIds.size(); ++i )
+    {
+        m_choiceComponentSearchMethod->Append( aNames[i], new wxStringClientData( aIds[i] ) );
+        if( aIds[i] == aId )
+            select = i;
+    }
+
+    m_choiceComponentSearchMethod->SetSelection( select );
+}
+
+
 void DIALOG_EESCHEMA_OPTIONS::RefreshTemplateFieldView( void )
 {
     // Loop through the template fieldnames and add them to the list control
diff --git a/eeschema/dialogs/dialog_eeschema_options.h b/eeschema/dialogs/dialog_eeschema_options.h
index 71d575b..54e7ed2 100644
--- a/eeschema/dialogs/dialog_eeschema_options.h
+++ b/eeschema/dialogs/dialog_eeschema_options.h
@@ -191,6 +191,23 @@ public:
     void SetGridSizes( const GRIDS& aGridSizes, int aGridId );
 
     /**
+     * Function GetComponentSearchMethod
+     * Returns the current component search method selected in the dialog
+     */
+    wxString GetComponentSearchMethod();
+
+    /**
+     * Function SetComponentSearchMethods
+     * Sets the available component search methods and select the current option.
+     *
+     * @param aIds - list of search method IDs
+     * @param aNames - list of search method names
+     * @param aId - ID of selected method
+     */
+    void SetComponentSearchMethods( const std::vector<wxString>& aIds,
+            const std::vector<wxString>& aNames, const wxString& aId );
+
+    /**
      * Function GetBusWidth
      * Get the current bus width setting from the dialog
      */
diff --git a/eeschema/dialogs/dialog_eeschema_options_base.cpp b/eeschema/dialogs/dialog_eeschema_options_base.cpp
index 78e06d9..cce68bb 100644
--- a/eeschema/dialogs/dialog_eeschema_options_base.cpp
+++ b/eeschema/dialogs/dialog_eeschema_options_base.cpp
@@ -175,6 +175,18 @@ DIALOG_EESCHEMA_OPTIONS_BASE::DIALOG_EESCHEMA_OPTIONS_BASE( wxWindow* parent, wx
 	
 	fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 );
 	
+	m_staticText22 = new wxStaticText( m_panel1, wxID_ANY, _("Component search method:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticText22->Wrap( -1 );
+	fgSizer1->Add( m_staticText22, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 3 );
+	
+	wxArrayString m_choiceComponentSearchMethodChoices;
+	m_choiceComponentSearchMethod = new wxChoice( m_panel1, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceComponentSearchMethodChoices, 0 );
+	m_choiceComponentSearchMethod->SetSelection( 0 );
+	fgSizer1->Add( m_choiceComponentSearchMethod, 0, wxALL|wxEXPAND, 3 );
+	
+	
+	fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 );
+	
 	
 	bSizer3->Add( fgSizer1, 0, wxEXPAND, 0 );
 	
diff --git a/eeschema/dialogs/dialog_eeschema_options_base.fbp b/eeschema/dialogs/dialog_eeschema_options_base.fbp
index 2783a55..fa8fe36 100644
--- a/eeschema/dialogs/dialog_eeschema_options_base.fbp
+++ b/eeschema/dialogs/dialog_eeschema_options_base.fbp
@@ -187,7 +187,7 @@
                                 <object class="notebookpage" expanded="1">
                                     <property name="bitmap"></property>
                                     <property name="label">General Options</property>
-                                    <property name="select">0</property>
+                                    <property name="select">1</property>
                                     <object class="wxPanel" expanded="1">
                                         <property name="BottomDockable">1</property>
                                         <property name="LeftDockable">1</property>
@@ -2867,6 +2867,187 @@
                                                                     <property name="width">0</property>
                                                                 </object>
                                                             </object>
+                                                            <object class="sizeritem" expanded="1">
+                                                                <property name="border">3</property>
+                                                                <property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</property>
+                                                                <property name="proportion">0</property>
+                                                                <object class="wxStaticText" expanded="1">
+                                                                    <property name="BottomDockable">1</property>
+                                                                    <property name="LeftDockable">1</property>
+                                                                    <property name="RightDockable">1</property>
+                                                                    <property name="TopDockable">1</property>
+                                                                    <property name="aui_layer"></property>
+                                                                    <property name="aui_name"></property>
+                                                                    <property name="aui_position"></property>
+                                                                    <property name="aui_row"></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="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="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">Component search method:</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_staticText22</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"></property>
+                                                                    <property name="toolbar_pane">0</property>
+                                                                    <property name="tooltip"></property>
+                                                                    <property name="window_extra_style"></property>
+                                                                    <property name="window_name"></property>
+                                                                    <property name="window_style"></property>
+                                                                    <property name="wrap">-1</property>
+                                                                    <event name="OnChar"></event>
+                                                                    <event name="OnEnterWindow"></event>
+                                                                    <event name="OnEraseBackground"></event>
+                                                                    <event name="OnKeyDown"></event>
+                                                                    <event name="OnKeyUp"></event>
+                                                                    <event name="OnKillFocus"></event>
+                                                                    <event name="OnLeaveWindow"></event>
+                                                                    <event name="OnLeftDClick"></event>
+                                                                    <event name="OnLeftDown"></event>
+                                                                    <event name="OnLeftUp"></event>
+                                                                    <event name="OnMiddleDClick"></event>
+                                                                    <event name="OnMiddleDown"></event>
+                                                                    <event name="OnMiddleUp"></event>
+                                                                    <event name="OnMotion"></event>
+                                                                    <event name="OnMouseEvents"></event>
+                                                                    <event name="OnMouseWheel"></event>
+                                                                    <event name="OnPaint"></event>
+                                                                    <event name="OnRightDClick"></event>
+                                                                    <event name="OnRightDown"></event>
+                                                                    <event name="OnRightUp"></event>
+                                                                    <event name="OnSetFocus"></event>
+                                                                    <event name="OnSize"></event>
+                                                                    <event name="OnUpdateUI"></event>
+                                                                </object>
+                                                            </object>
+                                                            <object class="sizeritem" expanded="1">
+                                                                <property name="border">3</property>
+                                                                <property name="flag">wxALL|wxEXPAND</property>
+                                                                <property name="proportion">0</property>
+                                                                <object class="wxChoice" expanded="1">
+                                                                    <property name="BottomDockable">1</property>
+                                                                    <property name="LeftDockable">1</property>
+                                                                    <property name="RightDockable">1</property>
+                                                                    <property name="TopDockable">1</property>
+                                                                    <property name="aui_layer"></property>
+                                                                    <property name="aui_name"></property>
+                                                                    <property name="aui_position"></property>
+                                                                    <property name="aui_row"></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="choices"></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="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="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_choiceComponentSearchMethod</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="selection">0</property>
+                                                                    <property name="show">1</property>
+                                                                    <property name="size"></property>
+                                                                    <property name="style"></property>
+                                                                    <property name="subclass"></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="OnChar"></event>
+                                                                    <event name="OnChoice"></event>
+                                                                    <event name="OnEnterWindow"></event>
+                                                                    <event name="OnEraseBackground"></event>
+                                                                    <event name="OnKeyDown"></event>
+                                                                    <event name="OnKeyUp"></event>
+                                                                    <event name="OnKillFocus"></event>
+                                                                    <event name="OnLeaveWindow"></event>
+                                                                    <event name="OnLeftDClick"></event>
+                                                                    <event name="OnLeftDown"></event>
+                                                                    <event name="OnLeftUp"></event>
+                                                                    <event name="OnMiddleDClick"></event>
+                                                                    <event name="OnMiddleDown"></event>
+                                                                    <event name="OnMiddleUp"></event>
+                                                                    <event name="OnMotion"></event>
+                                                                    <event name="OnMouseEvents"></event>
+                                                                    <event name="OnMouseWheel"></event>
+                                                                    <event name="OnPaint"></event>
+                                                                    <event name="OnRightDClick"></event>
+                                                                    <event name="OnRightDown"></event>
+                                                                    <event name="OnRightUp"></event>
+                                                                    <event name="OnSetFocus"></event>
+                                                                    <event name="OnSize"></event>
+                                                                    <event name="OnUpdateUI"></event>
+                                                                </object>
+                                                            </object>
+                                                            <object class="sizeritem" expanded="1">
+                                                                <property name="border">5</property>
+                                                                <property name="flag">wxEXPAND</property>
+                                                                <property name="proportion">1</property>
+                                                                <object class="spacer" expanded="1">
+                                                                    <property name="height">0</property>
+                                                                    <property name="permission">protected</property>
+                                                                    <property name="width">0</property>
+                                                                </object>
+                                                            </object>
                                                         </object>
                                                     </object>
                                                     <object class="sizeritem" expanded="1">
@@ -3937,7 +4118,7 @@
                                 <object class="notebookpage" expanded="1">
                                     <property name="bitmap"></property>
                                     <property name="label">Template Field Names</property>
-                                    <property name="select">1</property>
+                                    <property name="select">0</property>
                                     <object class="wxPanel" expanded="1">
                                         <property name="BottomDockable">1</property>
                                         <property name="LeftDockable">1</property>
@@ -4132,6 +4313,7 @@
                                                     <property name="minimum_size"></property>
                                                     <property name="name">fieldSizer</property>
                                                     <property name="orient">wxVERTICAL</property>
+                                                    <property name="parent">1</property>
                                                     <property name="permission">none</property>
                                                     <event name="OnUpdateUI"></event>
                                                     <object class="sizeritem" expanded="1">
diff --git a/eeschema/dialogs/dialog_eeschema_options_base.h b/eeschema/dialogs/dialog_eeschema_options_base.h
index b3f2dd2..0e62e7d 100644
--- a/eeschema/dialogs/dialog_eeschema_options_base.h
+++ b/eeschema/dialogs/dialog_eeschema_options_base.h
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Mar 13 2015)
+// C++ code generated with wxFormBuilder (version Dec 16 2015)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -100,6 +100,8 @@ class DIALOG_EESCHEMA_OPTIONS_BASE : public DIALOG_SHIM
 		wxStaticText* m_stMaxUndoItemsUnit;
 		wxStaticText* m_staticText26;
 		wxChoice* m_choiceSeparatorRefId;
+		wxStaticText* m_staticText22;
+		wxChoice* m_choiceComponentSearchMethod;
 		wxStaticLine* m_staticline1;
 		wxCheckBox* m_checkShowGrid;
 		wxCheckBox* m_checkShowHiddenPins;
diff --git a/eeschema/eeschema_config.cpp b/eeschema/eeschema_config.cpp
index 1b585db..a908ea7 100644
--- a/eeschema/eeschema_config.cpp
+++ b/eeschema/eeschema_config.cpp
@@ -54,6 +54,8 @@
 
 #include <wildcards_and_files_ext.h>
 
+#include <eda_pattern_match.h>
+
 #define FR_HISTORY_LIST_CNT     10   ///< Maximum number of find and replace strings.
 
 
@@ -309,6 +311,16 @@ void SCH_EDIT_FRAME::OnPreferencesOptions( wxCommandEvent& event )
     GRIDS grid_list = GetScreen()->GetGrids();
     bool saveProjectConfig = false;
 
+    std::vector<wxString> search_method_ids;
+    std::vector<wxString> search_method_names;
+
+    EDA_PATTERN_MATCH::GetPatternMatcherIds( search_method_ids );
+    for( size_t i = 0; i < search_method_ids.size(); ++i )
+    {
+        const wxString& id = search_method_ids[i];
+        search_method_names.push_back( EDA_PATTERN_MATCH::GetPatternMatcherName( id ) );
+    }
+
     DIALOG_EESCHEMA_OPTIONS dlg( this );
 
     units.Add( GetUnitsLabel( INCHES ) );
@@ -316,6 +328,7 @@ void SCH_EDIT_FRAME::OnPreferencesOptions( wxCommandEvent& event )
 
     dlg.SetUnits( units, g_UserUnit );
     dlg.SetGridSizes( grid_list, GetScreen()->GetGridCmdId() );
+    dlg.SetComponentSearchMethods( search_method_ids, search_method_names, m_componentSearchMethod );
     dlg.SetBusWidth( GetDefaultBusThickness() );
     dlg.SetLineWidth( GetDefaultLineThickness() );
     dlg.SetTextSize( GetDefaultTextSize() );
@@ -389,6 +402,7 @@ void SCH_EDIT_FRAME::OnPreferencesOptions( wxCommandEvent& event )
     m_autoplaceFields = dlg.GetAutoplaceFields();
     m_autoplaceJustify = dlg.GetAutoplaceJustify();
     m_autoplaceAlign = dlg.GetAutoplaceAlign();
+    m_componentSearchMethod = dlg.GetComponentSearchMethod();
 
     // Delete all template fieldnames and then restore them using the template field data from
     // the options dialog
@@ -512,6 +526,7 @@ void SCH_EDIT_FRAME::SaveProjectSettings( bool aAskForSave )
 static const wxChar AutoplaceFieldsEntry[] =        wxT( "AutoplaceFields" );
 static const wxChar AutoplaceJustifyEntry[] =       AUTOPLACE_JUSTIFY_KEY;
 static const wxChar AutoplaceAlignEntry[] =         AUTOPLACE_ALIGN_KEY;
+static const wxChar ComponentSearchMethodEntry[] =  COMPONENT_SEARCH_METHOD_KEY;
 static const wxChar DefaultBusWidthEntry[] =        wxT( "DefaultBusWidth" );
 static const wxChar DefaultDrawLineWidthEntry[] =   wxT( "DefaultDrawLineWidth" );
 static const wxChar ShowHiddenPinsEntry[] =         wxT( "ShowHiddenPins" );
@@ -598,6 +613,7 @@ void SCH_EDIT_FRAME::LoadSettings( wxConfigBase* aCfg )
     aCfg->Read( AutoplaceFieldsEntry, &m_autoplaceFields, true );
     aCfg->Read( AutoplaceJustifyEntry, &m_autoplaceJustify, true );
     aCfg->Read( AutoplaceAlignEntry, &m_autoplaceAlign, false );
+    aCfg->Read( ComponentSearchMethodEntry, &m_componentSearchMethod, wxT( "" ) );
 
     // Load print preview window session settings.
     aCfg->Read( PreviewFramePositionXEntry, &tmp, -1 );
@@ -691,6 +707,7 @@ void SCH_EDIT_FRAME::SaveSettings( wxConfigBase* aCfg )
     aCfg->Write( AutoplaceFieldsEntry, m_autoplaceFields );
     aCfg->Write( AutoplaceJustifyEntry, m_autoplaceJustify );
     aCfg->Write( AutoplaceAlignEntry, m_autoplaceAlign );
+    aCfg->Write( ComponentSearchMethodEntry, m_componentSearchMethod );
 
     // Save print preview window session settings.
     aCfg->Write( PreviewFramePositionXEntry, m_previewPosition.x );
diff --git a/eeschema/eeschema_config.h b/eeschema/eeschema_config.h
index e82f5df..e4b6646 100644
--- a/eeschema/eeschema_config.h
+++ b/eeschema/eeschema_config.h
@@ -14,4 +14,6 @@
 #define AUTOPLACE_JUSTIFY_KEY wxT("AutoplaceJustify")
 #define AUTOPLACE_ALIGN_KEY wxT("AutoplaceAlign")
 
+#define COMPONENT_SEARCH_METHOD_KEY wxT("ComponentSearchMethod")
+
 #endif      // EESCHEMA_CONFIG_H
diff --git a/eeschema/schframe.h b/eeschema/schframe.h
index f7309bc..ce057e3 100644
--- a/eeschema/schframe.h
+++ b/eeschema/schframe.h
@@ -150,6 +150,8 @@ private:
     bool                    m_autoplaceJustify;   ///< allow autoplace to change justification
     bool                    m_autoplaceAlign;     ///< align autoplaced fields to the grid
 
+    wxString                m_componentSearchMethod;    ///< selected component search method ID
+
     /// An index to the last find item in the found items list #m_foundItems.
     int         m_foundItemIndex;
 
diff --git a/include/eda_pattern_match.h b/include/eda_pattern_match.h
new file mode 100644
index 0000000..6906a54
--- /dev/null
+++ b/include/eda_pattern_match.h
@@ -0,0 +1,144 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Chris Pavlina <pavlina.chris@xxxxxxxxx>
+ * Copyright (C) 2015 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+/**
+ * @file eda_pattern_match.h
+ * @brief Abstract pattern-matching tool and implementations.
+ */
+
+#ifndef EDA_PATTERN_MATCH_H
+#define EDA_PATTERN_MATCH_H
+
+#include <vector>
+#include <wx/wx.h>
+#include <wx/string.h>
+#include <wx/regex.h>
+
+static const int EDA_PATTERN_NOT_FOUND = wxNOT_FOUND;
+
+class EDA_PATTERN_MATCH_SUBSTR;
+class EDA_PATTERN_MATCH_REGEX;
+class EDA_PATTERN_MATCH_WILDCARD;
+
+class EDA_PATTERN_MATCH
+{
+public:
+    /**
+     * Set the pattern against which candidates will be matched.
+     */
+    virtual void SetPattern( const wxString& aPattern ) = 0;
+
+    /**
+     * Return the location of a match iff a given candidate string matches the set pattern.
+     * Otherwise, return EDA_PATTERN_NOT_FOUND.
+     */
+    virtual int Find( const wxString& aCandidate ) = 0;
+
+    /**
+     * Populate a list of (non-translated) pattern matcher IDs
+     */
+    static void GetPatternMatcherIds( std::vector<wxString>& aList );
+
+    /**
+     * Get the translated name for a pattern matcher ID.
+     */
+    static wxString GetPatternMatcherName( const wxString& aId );
+
+    /**
+     * Return a new pattern matcher given an ID.
+     */
+    static EDA_PATTERN_MATCH* CreatePatternMatcher( const wxString& aID );
+};
+
+
+class EDA_PATTERN_MATCH_SUBSTR : public EDA_PATTERN_MATCH
+{
+public:
+    /**
+     * Construct an EDA_PATTERN_MATCH_SUBSTR
+     */
+    EDA_PATTERN_MATCH_SUBSTR() {}
+
+    /**
+     * Set the pattern against which candidates will be matched.
+     */
+    virtual void SetPattern( const wxString& aPattern );
+
+    /**
+     * Return the location of a match iff a given candidate string contains the set
+     * substring. Otherwise, return EDA_PATTERN_NOT_FOUND.
+     */
+    virtual int Find( const wxString& aCandidate );
+
+protected:
+    wxString m_pattern;
+};
+
+
+class EDA_PATTERN_MATCH_REGEX : public EDA_PATTERN_MATCH
+{
+public:
+    /**
+     * Construct an EDA_PATTERN_MATCH_REGEX
+     */
+    EDA_PATTERN_MATCH_REGEX() {}
+
+    /**
+     * Set the pattern against which candidates will be matched.
+     */
+    virtual void SetPattern( const wxString& aPattern );
+
+    /**
+     * Return the location of a match iff a given candidate string contains the set
+     * substring with wildcards. Otherwise, return EDA_PATTERN_NOT_FOUND.
+     */
+    virtual int Find( const wxString& aCandidate );
+
+protected:
+    wxString m_pattern;
+    wxRegEx m_regex;
+};
+
+
+class EDA_PATTERN_MATCH_WILDCARD : public EDA_PATTERN_MATCH_REGEX
+{
+public:
+    /**
+     * Construct an EDA_PATTERN_MATCH_WILDCARD
+     */
+    EDA_PATTERN_MATCH_WILDCARD() {}
+
+    /**
+     * Set the pattern against which candidates will be matched.
+     */
+    virtual void SetPattern( const wxString& aPattern );
+
+    /**
+     * Return the location of a match iff a given candidate string contains the set
+     * substring with wildcards. Otherwise, return EDA_PATTERN_NOT_FOUND.
+     */
+    virtual int Find( const wxString& aCandidate );
+};
+
+#endif  // EDA_PATTERN_MATCH_H

Follow ups