kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #28625
[PATCH] Refactor: split footprint filter data model out of cvpcb
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.chris@xxxxxxxxx>
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.chris@xxxxxxxxx>
+ * 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 <stambaughw@xxxxxxxxxxx>
- * 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.chris@xxxxxxxxx>
+ * 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.charras@xxxxxxxxxx>
- * 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
Follow ups