Hi, The attached patch pulls the footprint filtering logic out of cvpcb's GUI code. It adds a FOOTPRINT_FILTER class in common/ that provides an iterable filtered view onto a collection of footprints. This refactor is necessary to enable footprint selection within eeschema.
-- Chris
>From 76a8578dc2b4b0fae3f5243e40f262f0ddfc5ef2 Mon Sep 17 00:00:00 2001 From: Chris Pavlina <pavlina.ch...@gmail.com> Date: Sat, 11 Mar 2017 12:28:51 -0500 Subject: [PATCH] Refactor: split footprint filter data model out of cvpcb --- common/CMakeLists.txt | 1 + common/footprint_filter.cpp | 162 +++++++++++++++++++++++++++++++++++++ cvpcb/class_footprints_listbox.cpp | 59 ++------------ cvpcb/cvpcb_mainframe.cpp | 34 ++++---- cvpcb/listview_classes.h | 13 +-- include/footprint_filter.h | 118 +++++++++++++++++++++++++++ include/footprint_info.h | 3 +- 7 files changed, 310 insertions(+), 80 deletions(-) create mode 100644 common/footprint_filter.cpp create mode 100644 include/footprint_filter.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index b0b3b66ff..d7f38222e 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -344,6 +344,7 @@ set( PCB_COMMON_SRCS class_page_info.cpp lset.cpp footprint_info.cpp + footprint_filter.cpp ../pcbnew/basepcbframe.cpp ../pcbnew/class_board.cpp ../pcbnew/class_board_connected_item.cpp diff --git a/common/footprint_filter.cpp b/common/footprint_filter.cpp new file mode 100644 index 000000000..9ea19d0e3 --- /dev/null +++ b/common/footprint_filter.cpp @@ -0,0 +1,162 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 Chris Pavlina <pavlina.ch...@gmail.com> + * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#include <footprint_filter.h> +#include <pcb_netlist.h> +#include <stdexcept> + +using FOOTPRINT_FILTER_IT = FOOTPRINT_FILTER::ITERATOR; + + +FOOTPRINT_FILTER::ITERATOR::ITERATOR(): + m_pos( 0 ), + m_filter( nullptr ) +{} + + +FOOTPRINT_FILTER::ITERATOR::ITERATOR( FOOTPRINT_FILTER_IT const& aOther ): + m_pos( aOther.m_pos ), + m_filter( aOther.m_filter ) +{} + + +FOOTPRINT_FILTER::ITERATOR::ITERATOR( FOOTPRINT_FILTER& aFilter ): + m_pos( (size_t) -1 ), + m_filter( &aFilter ) +{ + increment(); +} + + +FOOTPRINT_FILTER::FOOTPRINT_FILTER( + FOOTPRINT_LIST& aList, + const wxString& aLibName, COMPONENT* aComponent, const wxString& aPattern, + int aFilterType ): + m_list( &aList ), + m_lib_name( aLibName ), + m_filter_pattern( aPattern ), + m_component( aComponent ), + m_filter_type( aFilterType ) +{ + m_filter.SetPattern( aPattern.Lower() ); +} + + +void FOOTPRINT_FILTER_IT::increment() +{ + bool found = false; + + if( !m_filter || !m_filter->m_list || m_filter->m_list->GetCount() == 0 ) + { + m_pos = 0; + return; + } + + auto filter_type = m_filter->m_filter_type; + auto list = m_filter->m_list; + auto& lib_name = m_filter->m_lib_name; + auto& filter_pattern = m_filter->m_filter_pattern; + auto component = m_filter->m_component; + auto &filter = m_filter->m_filter; + + for( ++m_pos; m_pos < list->GetCount() && !found; ++m_pos ) + { + found = true; + + if( ( filter_type & FOOTPRINT_FILTER::FILTERING_BY_LIBRARY ) && + !lib_name.IsEmpty() && + !list->GetItem( m_pos ).InLibrary( lib_name ) ) + found = false; + + if( ( filter_type & FOOTPRINT_FILTER::FILTERING_BY_COMPONENT_KEYWORD ) && + component && + !component->MatchesFootprintFilters( + list->GetItem( m_pos ).GetNickname(), + list->GetItem( m_pos ).GetFootprintName() ) ) + found = false; + + if( ( filter_type & FOOTPRINT_FILTER::FILTERING_BY_PIN_COUNT ) && + component && + component->GetNetCount() != list->GetItem( m_pos ).GetUniquePadCount() ) + found = false; + + if( ( filter_type & FOOTPRINT_FILTER::FILTERING_BY_NAME ) && + !filter_pattern.IsEmpty() ) + { + wxString currname; + + // If the search string contains a ':' character, + // include the library name in the search string + // e.g. LibName:FootprintName + if( filter_pattern.Contains( ":" ) ) + currname = list->GetItem( m_pos ).GetNickname().Lower() + ":"; + + currname += list->GetItem( m_pos ).GetFootprintName().Lower(); + + if( filter.Find( currname ) == EDA_PATTERN_NOT_FOUND ) + found = false; + } + + if( filter_type == FOOTPRINT_FILTER::UNFILTERED_FP_LIST ) + { + // override + found = true; + } + } + + // for loop will stop one past the correct item + if( found ) + --m_pos; +} + + +bool FOOTPRINT_FILTER_IT::equal( FOOTPRINT_FILTER_IT const& aOther ) const +{ + // Invalid iterators are always equal + return + ( m_pos == aOther.m_pos ) && + ( m_filter == aOther.m_filter || m_pos == -1 ); +} + + +FOOTPRINT_INFO& FOOTPRINT_FILTER_IT::dereference() const +{ + if( m_filter && m_filter->m_list && m_pos < m_filter->m_list->GetCount() ) + return m_filter->m_list->GetItem( m_pos ); + else + throw std::out_of_range( "Attempt to dereference past FOOTPRINT_FILTER::end()" ); +} + + + +FOOTPRINT_FILTER_IT FOOTPRINT_FILTER::begin() +{ + return FOOTPRINT_FILTER_IT( *this ); +} + + +FOOTPRINT_FILTER_IT FOOTPRINT_FILTER::end() +{ + FOOTPRINT_FILTER_IT end_it( *this ); + end_it.m_pos = m_list->GetCount(); + return end_it; +} + diff --git a/cvpcb/class_footprints_listbox.cpp b/cvpcb/class_footprints_listbox.cpp index 4d3f5b0b5..ec5faac96 100644 --- a/cvpcb/class_footprints_listbox.cpp +++ b/cvpcb/class_footprints_listbox.cpp @@ -29,12 +29,14 @@ #include <fctsys.h> #include <wxstruct.h> +#include <wx/wupdlock.h> #include <cvpcb.h> #include <cvpcb_mainframe.h> #include <listview_classes.h> #include <cvpcb_id.h> #include <eda_pattern_match.h> +#include <footprint_filter.h> FOOTPRINTS_LISTBOX::FOOTPRINTS_LISTBOX( CVPCB_MAINFRAME* parent, @@ -133,62 +135,16 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a wxString msg; wxString oldSelection; - EDA_PATTERN_MATCH_WILDCARD patternFilter; - patternFilter.SetPattern( aFootPrintFilterPattern.Lower() ); // Use case insensitive search + FOOTPRINT_FILTER filter( aList, aLibName, aComponent, aFootPrintFilterPattern, aFilterType ); if( GetSelection() >= 0 && GetSelection() < (int)m_footprintList.GetCount() ) oldSelection = m_footprintList[ GetSelection() ]; - for( unsigned ii = 0; ii < aList.GetCount(); ii++ ) + for( auto& i: filter ) { - if( aFilterType == UNFILTERED_FP_LIST ) - { - msg.Printf( wxT( "%3d %s:%s" ), int( newList.GetCount() + 1 ), - GetChars( aList.GetItem( ii ).GetNickname() ), - GetChars( aList.GetItem( ii ).GetFootprintName() ) ); - newList.Add( msg ); - continue; - } - - // Filter footprints by selected library - if( (aFilterType & FILTERING_BY_LIBRARY) && !aLibName.IsEmpty() - && !aList.GetItem( ii ).InLibrary( aLibName ) ) - continue; - - // Filter footprints by symbol fp-filters - if( (aFilterType & FILTERING_BY_COMPONENT_KEYWORD) && aComponent - && !aComponent->MatchesFootprintFilters( aList.GetItem( ii ).GetNickname(), aList.GetItem( ii ).GetFootprintName() ) ) - continue; - - // Filter footprints by symbol pin-count - if( (aFilterType & FILTERING_BY_PIN_COUNT) && aComponent - && aComponent->GetNetCount() != aList.GetItem( ii ).GetUniquePadCount() ) - continue; - - // Filter footprints by text-input - if( (aFilterType & FILTERING_BY_NAME ) && !aFootPrintFilterPattern.IsEmpty() ) - { - wxString currname = ""; - - // If the search string contains a ':' character, - // include the library name in the search string - // e.g. LibName:FootprintName - if( aFootPrintFilterPattern.Contains( ":" ) ) - { - currname = aList.GetItem( ii ).GetNickname().Lower() + ":"; - } - - currname += aList.GetItem( ii ).GetFootprintName().Lower(); - - if( patternFilter.Find( currname ) == EDA_PATTERN_NOT_FOUND ) - { - continue; - } - } - - msg.Printf( wxT( "%3d %s:%s" ), int( newList.GetCount() + 1 ), - GetChars( aList.GetItem( ii ).GetNickname() ), - GetChars( aList.GetItem( ii ).GetFootprintName() ) ); + msg.Printf( "%3d %s:%s", int( newList.GetCount() + 1 ), + GetChars( i.GetNickname() ), + GetChars( i.GetFootprintName() ) ); newList.Add( msg ); } @@ -202,6 +158,7 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a if( selection == wxNOT_FOUND ) selection = 0; + wxWindowUpdateLocker freeze( this ); DeleteAllItems(); if( m_footprintList.GetCount() ) diff --git a/cvpcb/cvpcb_mainframe.cpp b/cvpcb/cvpcb_mainframe.cpp index af25c93c2..3defcf53c 100644 --- a/cvpcb/cvpcb_mainframe.cpp +++ b/cvpcb/cvpcb_mainframe.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2011-2016 Wayne Stambaugh <stambau...@verizon.net> - * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.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 @@ -216,7 +216,7 @@ void CVPCB_MAINFRAME::LoadSettings( wxConfigBase* aCfg ) aCfg->Read( KeepCvpcbOpenEntry, &m_keepCvpcbOpen, true ); aCfg->Read( FootprintDocFileEntry, &m_DocModulesFileName, DEFAULT_FOOTPRINTS_LIST_FILENAME ); - aCfg->Read( FilterFootprintEntry, &m_filteringOptions, FOOTPRINTS_LISTBOX::UNFILTERED_FP_LIST ); + aCfg->Read( FilterFootprintEntry, &m_filteringOptions, FOOTPRINT_FILTER::UNFILTERED_FP_LIST ); } @@ -551,20 +551,20 @@ void CVPCB_MAINFRAME::OnSelectFilteringFootprint( wxCommandEvent& event ) switch( event.GetId() ) { case ID_CVPCB_FOOTPRINT_DISPLAY_FILTERED_LIST: - option = FOOTPRINTS_LISTBOX::FILTERING_BY_COMPONENT_KEYWORD; + option = FOOTPRINT_FILTER::FILTERING_BY_COMPONENT_KEYWORD; break; case ID_CVPCB_FOOTPRINT_DISPLAY_PIN_FILTERED_LIST: - option = FOOTPRINTS_LISTBOX::FILTERING_BY_PIN_COUNT; + option = FOOTPRINT_FILTER::FILTERING_BY_PIN_COUNT; break; case ID_CVPCB_FOOTPRINT_DISPLAY_BY_LIBRARY_LIST: - option = FOOTPRINTS_LISTBOX::FILTERING_BY_LIBRARY; + option = FOOTPRINT_FILTER::FILTERING_BY_LIBRARY; break; case ID_CVPCB_FOOTPRINT_DISPLAY_BY_NAME: m_currentSearchPattern = m_tcFilterString->GetValue(); - option = FOOTPRINTS_LISTBOX::FILTERING_BY_NAME; + option = FOOTPRINT_FILTER::FILTERING_BY_NAME; break; } @@ -586,37 +586,37 @@ void CVPCB_MAINFRAME::OnUpdateKeepOpenOnSave( wxUpdateUIEvent& event ) void CVPCB_MAINFRAME::OnFilterFPbyKeywords( wxUpdateUIEvent& event ) { - event.Check( m_filteringOptions & FOOTPRINTS_LISTBOX::FILTERING_BY_COMPONENT_KEYWORD ); + event.Check( m_filteringOptions & FOOTPRINT_FILTER::FILTERING_BY_COMPONENT_KEYWORD ); } void CVPCB_MAINFRAME::OnFilterFPbyPinCount( wxUpdateUIEvent& event ) { - event.Check( m_filteringOptions & FOOTPRINTS_LISTBOX::FILTERING_BY_PIN_COUNT ); + event.Check( m_filteringOptions & FOOTPRINT_FILTER::FILTERING_BY_PIN_COUNT ); } void CVPCB_MAINFRAME::OnFilterFPbyLibrary( wxUpdateUIEvent& event ) { - event.Check( m_filteringOptions & FOOTPRINTS_LISTBOX::FILTERING_BY_LIBRARY ); + event.Check( m_filteringOptions & FOOTPRINT_FILTER::FILTERING_BY_LIBRARY ); } void CVPCB_MAINFRAME::OnFilterFPbyKeyName( wxUpdateUIEvent& event ) { - event.Check( m_filteringOptions & FOOTPRINTS_LISTBOX::FILTERING_BY_NAME ); + event.Check( m_filteringOptions & FOOTPRINT_FILTER::FILTERING_BY_NAME ); } void CVPCB_MAINFRAME::OnEnterFilteringText( wxCommandEvent& aEvent ) { // Called when changing the filter string in main toolbar. - // If the option FOOTPRINTS_LISTBOX::FILTERING_BY_NAME is set, update the list of + // If the option FOOTPRINT_FILTER::FILTERING_BY_NAME is set, update the list of // available footprints which match the filter m_currentSearchPattern = m_tcFilterString->GetValue(); - if( ( m_filteringOptions & FOOTPRINTS_LISTBOX::FILTERING_BY_NAME ) == 0 ) + if( ( m_filteringOptions & FOOTPRINT_FILTER::FILTERING_BY_NAME ) == 0 ) return; OnSelectFilteringFootprint( aEvent ); @@ -674,10 +674,10 @@ void CVPCB_MAINFRAME::DisplayStatus() if( m_footprintListBox ) { - if( ( m_filteringOptions & FOOTPRINTS_LISTBOX::FILTERING_BY_COMPONENT_KEYWORD ) ) + if( ( m_filteringOptions & FOOTPRINT_FILTER::FILTERING_BY_COMPONENT_KEYWORD ) ) filters = _( "key words" ); - if( ( m_filteringOptions & FOOTPRINTS_LISTBOX::FILTERING_BY_PIN_COUNT ) ) + if( ( m_filteringOptions & FOOTPRINT_FILTER::FILTERING_BY_PIN_COUNT ) ) { if( !filters.IsEmpty() ) filters += wxT( "+" ); @@ -685,7 +685,7 @@ void CVPCB_MAINFRAME::DisplayStatus() filters += _( "pin count" ); } - if( ( m_filteringOptions & FOOTPRINTS_LISTBOX::FILTERING_BY_LIBRARY ) ) + if( ( m_filteringOptions & FOOTPRINT_FILTER::FILTERING_BY_LIBRARY ) ) { if( !filters.IsEmpty() ) filters += wxT( "+" ); @@ -693,7 +693,7 @@ void CVPCB_MAINFRAME::DisplayStatus() filters += _( "library" ); } - if( ( m_filteringOptions & FOOTPRINTS_LISTBOX::FILTERING_BY_NAME ) ) + if( ( m_filteringOptions & FOOTPRINT_FILTER::FILTERING_BY_NAME ) ) { if( !filters.IsEmpty() ) filters += wxT( "+" ); @@ -863,7 +863,7 @@ void CVPCB_MAINFRAME::BuildFOOTPRINTS_LISTBOX() } m_footprintListBox->SetFootprints( m_FootprintsList, wxEmptyString, NULL, - wxEmptyString, FOOTPRINTS_LISTBOX::UNFILTERED_FP_LIST ); + wxEmptyString, FOOTPRINT_FILTER::UNFILTERED_FP_LIST ); DisplayStatus(); } diff --git a/cvpcb/listview_classes.h b/cvpcb/listview_classes.h index 0cb429037..0abe7a6eb 100644 --- a/cvpcb/listview_classes.h +++ b/cvpcb/listview_classes.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.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 @@ -29,7 +29,7 @@ #define CVSTRUCT_H #include <wx/listctrl.h> - +#include <footprint_filter.h> /* Forward declarations of all top-level window classes. */ class CVPCB_MAINFRAME; @@ -90,15 +90,6 @@ private: wxArrayString m_footprintList; public: - // OR'ed mask to manage footprint filtering options - enum FP_FILTER_T - { - UNFILTERED_FP_LIST = 0, - FILTERING_BY_COMPONENT_KEYWORD = 0x0001, - FILTERING_BY_PIN_COUNT = 0x0002, - FILTERING_BY_LIBRARY = 0x0004, - FILTERING_BY_NAME = 0x0008 - }; FOOTPRINTS_LISTBOX( CVPCB_MAINFRAME* parent, wxWindowID id, const wxPoint& loc, const wxSize& size ); diff --git a/include/footprint_filter.h b/include/footprint_filter.h new file mode 100644 index 000000000..09f50b946 --- /dev/null +++ b/include/footprint_filter.h @@ -0,0 +1,118 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 Chris Pavlina <pavlina.ch...@gmail.com> + * Copyright (C) 2017 KiCad Developers, see AUTHORS.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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef FOOTPRINT_FILTER_H +#define FOOTPRINT_FILTER_H + +#include <boost/iterator/iterator_facade.hpp> +#include <footprint_info.h> +#include <eda_pattern_match.h> + +class COMPONENT; + +/** + * Footprint display filter. Takes a list of footprints and filtering settings, + * and provides an iterable view of the filtered data. + */ +class FOOTPRINT_FILTER +{ +public: + + /** + * Filter setting constants. The filter type is a bitwise OR of these flags, + * and only footprints matching all selected filter types are shown. + */ + enum FP_FILTER_T: int + { + UNFILTERED_FP_LIST = 0, + FILTERING_BY_COMPONENT_KEYWORD = 0x0001, + FILTERING_BY_PIN_COUNT = 0x0002, + FILTERING_BY_LIBRARY = 0x0004, + FILTERING_BY_NAME = 0x0008 + }; + + /** + * Construct a filter. + * + * @param aList - unfiltered list of footprints + * @param aLibName - library name to filter on, don't care if not + * FILTERING_BY_LIBRARY + * @param aComponent - component to compare to, don't care if neither + * FILTERING_BY_COMPONENT_KEYWORD nor + * FILTERING_BY_PIN_COUNT + * @param aPattern - pattern, including wildcards and optionally a + * colon-delimited library name; don't care if not + * FILTERING_BY_NAME + * @param aFilterType - bitwise OR of flags from FP_FILTER_T + */ + FOOTPRINT_FILTER( + FOOTPRINT_LIST& aList, + const wxString& aLibName, COMPONENT* aComponent, const wxString& aPattern, + int aFilterType ); + + /** + * Inner iterator class returned by begin() and end(). + */ + class ITERATOR: + public boost::iterator_facade< + ITERATOR, + FOOTPRINT_INFO, + boost::forward_traversal_tag> + { + public: + ITERATOR(); + ITERATOR( ITERATOR const& aOther ); + ITERATOR( FOOTPRINT_FILTER& aFilter ); + + private: + friend class boost::iterator_core_access; + friend class FOOTPRINT_FILTER; + + void increment(); + bool equal( ITERATOR const& aOther ) const; + FOOTPRINT_INFO& dereference() const; + + size_t m_pos; + FOOTPRINT_FILTER* m_filter; + }; + + /** + * Get an iterator to the beginning of the filtered view. + */ + ITERATOR begin(); + + /** + * Get an iterator to the end of the filtered view. The end iterator is + * invalid and may not be dereferenced, only compared against. + */ + ITERATOR end(); + +private: + + FOOTPRINT_LIST* m_list; + + wxString m_lib_name; + wxString m_filter_pattern; + COMPONENT* m_component; + int m_filter_type; + EDA_PATTERN_MATCH_WILDCARD m_filter; +}; + +#endif // FOOTPRINT_FILTER_H diff --git a/include/footprint_info.h b/include/footprint_info.h index 2559752f0..7feb75ebc 100644 --- a/include/footprint_info.h +++ b/include/footprint_info.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2011 Jean-Pierre Charras, <jp.char...@wanadoo.fr> - * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.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 @@ -33,6 +33,7 @@ #include <boost/ptr_container/ptr_vector.hpp> #include <ki_mutex.h> +#include <ki_exception.h> #include <kicad_string.h> -- 2.12.0
_______________________________________________ Mailing list: https://launchpad.net/~kicad-developers Post to : kicad-developers@lists.launchpad.net Unsubscribe : https://launchpad.net/~kicad-developers More help : https://help.launchpad.net/ListHelp