1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
23  */
24 
25 #include <footprint_filter.h>
26 #include <tool/tool_manager.h>
27 #include <trace_helpers.h>
28 #include <wx/log.h>
29 #include <wx/wupdlock.h>
30 
31 #include <cvpcb_id.h>
32 #include <cvpcb_mainframe.h>
33 #include <listboxes.h>
34 #include <tools/cvpcb_actions.h>
35 
FOOTPRINTS_LISTBOX(CVPCB_MAINFRAME * parent,wxWindowID id)36 FOOTPRINTS_LISTBOX::FOOTPRINTS_LISTBOX( CVPCB_MAINFRAME* parent, wxWindowID id ) :
37     ITEMS_LISTBOX_BASE( parent, id, wxDefaultPosition, wxDefaultSize, wxLC_SINGLE_SEL|wxNO_BORDER )
38 {
39 }
40 
41 
~FOOTPRINTS_LISTBOX()42 FOOTPRINTS_LISTBOX::~FOOTPRINTS_LISTBOX()
43 {
44 }
45 
46 
GetCount()47 int FOOTPRINTS_LISTBOX::GetCount()
48 {
49     return m_footprintList.Count();
50 }
51 
52 
SetString(unsigned linecount,const wxString & text)53 void FOOTPRINTS_LISTBOX::SetString( unsigned linecount, const wxString& text )
54 {
55     unsigned count = m_footprintList.Count();
56     if( count > 0 )
57     {
58         if( linecount >= count )
59             linecount = count - 1;
60 
61         m_footprintList[linecount] = text;
62     }
63     UpdateWidth( linecount );
64 }
65 
66 
GetSelectedFootprint()67 wxString FOOTPRINTS_LISTBOX::GetSelectedFootprint()
68 {
69     wxString footprintName;
70     int      ii = GetFirstSelected();
71 
72     if( ii >= 0 )
73     {
74         wxString msg = m_footprintList[ii];
75         msg.Trim( true );
76         msg.Trim( false );
77         footprintName = msg.AfterFirst( wxChar( ' ' ) );
78     }
79 
80     return footprintName;
81 }
82 
83 
AppendLine(const wxString & text)84 void FOOTPRINTS_LISTBOX::AppendLine( const wxString& text )
85 {
86     m_footprintList.Add( text );
87     int lines = m_footprintList.Count();
88     SetItemCount( lines );
89     UpdateWidth( lines - 1 );
90 }
91 
92 
OnGetItemText(long item,long column) const93 wxString FOOTPRINTS_LISTBOX::OnGetItemText( long item, long column ) const
94 {
95     if( item < 0 || item >= (long)m_footprintList.GetCount() )
96         return wxEmptyString;
97 
98     return m_footprintList.Item( item );
99 }
100 
101 
SetSelection(int index,bool State)102 void FOOTPRINTS_LISTBOX::SetSelection( int index, bool State )
103 {
104     if( index >= GetCount() )
105         index = GetCount() - 1;
106 
107     if( (index >= 0)  && (GetCount() > 0) )
108     {
109         Select( index, State );
110         EnsureVisible( index );
111         Refresh();
112     }
113 }
114 
115 
SetSelectedFootprint(const LIB_ID & aFPID)116 void FOOTPRINTS_LISTBOX::SetSelectedFootprint( const LIB_ID& aFPID )
117 {
118     wxString id = aFPID.Format().wx_str();
119 
120     for( int i = 0; i < GetCount(); ++i )
121     {
122         wxString candidate = m_footprintList.Item( i ).substr( 4 );
123 
124         if( candidate.CmpNoCase( id ) == 0 )
125         {
126             SetSelection( i, true );
127             return;
128         }
129     }
130 }
131 
132 
SetFootprints(FOOTPRINT_LIST & aList,const wxString & aLibName,COMPONENT * aComponent,const wxString & aFootPrintFilterPattern,int aFilterType)133 void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& aLibName,
134                                         COMPONENT* aComponent,
135                                         const wxString &aFootPrintFilterPattern,
136                                         int aFilterType )
137 {
138     wxArrayString   newList;
139     wxString        msg;
140     wxString        oldSelection;
141 
142     FOOTPRINT_FILTER filter( aList );
143 
144     if( aFilterType & FILTERING_BY_COMPONENT_FP_FILTERS && aComponent )
145         filter.FilterByFootprintFilters( aComponent->GetFootprintFilters() );
146 
147     if( aFilterType & FILTERING_BY_PIN_COUNT && aComponent )
148         filter.FilterByPinCount( aComponent->GetPinCount() );
149 
150     if( aFilterType & FILTERING_BY_LIBRARY )
151         filter.FilterByLibrary( aLibName );
152 
153     if( !aFootPrintFilterPattern.IsEmpty() )
154         filter.FilterByTextPattern( aFootPrintFilterPattern );
155 
156     if( GetSelection() >= 0 && GetSelection() < (int)m_footprintList.GetCount() )
157         oldSelection = m_footprintList[ GetSelection() ];
158 
159     for( auto& i: filter )
160     {
161         msg.Printf( "%3d %s:%s",
162                     int( newList.GetCount() + 1 ),
163                     i.GetLibNickname(),
164                     i.GetFootprintName() );
165         newList.Add( msg );
166     }
167 
168     if( newList == m_footprintList )
169         return;
170 
171     m_footprintList = newList;
172 
173     int selection = m_footprintList.Index( oldSelection );
174 
175     if( selection == wxNOT_FOUND )
176         selection = 0;
177 
178     DeselectAll();
179     wxSafeYield();
180     wxWindowUpdateLocker freeze( this );
181     DeleteAllItems();
182 
183     if( m_footprintList.GetCount() )
184     {
185         SetItemCount( m_footprintList.GetCount() );
186         SetSelection( selection, true );
187         RefreshItems( 0L, m_footprintList.GetCount()-1 );
188         UpdateWidth();
189     }
190 }
191 
192 
BEGIN_EVENT_TABLE(FOOTPRINTS_LISTBOX,ITEMS_LISTBOX_BASE)193 BEGIN_EVENT_TABLE( FOOTPRINTS_LISTBOX, ITEMS_LISTBOX_BASE )
194     EVT_CHAR( FOOTPRINTS_LISTBOX::OnChar )
195     EVT_LIST_ITEM_SELECTED( ID_CVPCB_FOOTPRINT_LIST, FOOTPRINTS_LISTBOX::OnLeftClick )
196     EVT_LIST_ITEM_ACTIVATED( ID_CVPCB_FOOTPRINT_LIST, FOOTPRINTS_LISTBOX::OnLeftDClick )
197 END_EVENT_TABLE()
198 
199 
200 void FOOTPRINTS_LISTBOX::OnLeftClick( wxListEvent& event )
201 {
202     if( m_footprintList.IsEmpty() )
203         return;
204 
205     // On some plateforms (OSX) the focus is lost when the viewers (fp and 3D viewers)
206     // are opened and refreshed when a new footprint is selected.
207     // If the listbox has the focus before selecting a new footprint, it will be forced
208     // after selection.
209     bool hasFocus = HasFocus();
210 
211     // If the footprint view window is displayed, update the footprint.
212     if( GetParent()->GetFootprintViewerFrame() )
213         GetParent()->GetToolManager()->RunAction( CVPCB_ACTIONS::showFootprintViewer, true );
214 
215     GetParent()->DisplayStatus();
216 
217     if( hasFocus )
218         SetFocus();
219 }
220 
221 
OnLeftDClick(wxListEvent & event)222 void FOOTPRINTS_LISTBOX::OnLeftDClick( wxListEvent& event )
223 {
224     GetParent()->GetToolManager()->RunAction( CVPCB_ACTIONS::associate, true );
225 }
226 
227 
OnChar(wxKeyEvent & event)228 void FOOTPRINTS_LISTBOX::OnChar( wxKeyEvent& event )
229 {
230     wxLogTrace( kicadTraceKeyEvent, "FOOTPRINTS_LISTBOX::OnChar %s", dump( event ) );
231 
232     int key = event.GetKeyCode();
233 
234     switch( key )
235     {
236     case WXK_HOME:
237     case WXK_END:
238     case WXK_UP:
239     case WXK_DOWN:
240     case WXK_PAGEUP:
241     case WXK_PAGEDOWN:
242         event.Skip();
243         return;
244 
245     default:
246         break;
247     }
248 
249     // Search for an item name starting by the key code:
250     key = toupper( key );
251 
252     for( unsigned ii = 0; ii < m_footprintList.GetCount(); ii++ )
253     {
254         wxString text = m_footprintList.Item( ii );
255 
256         // Search for the start char of the footprint name. Skip the line number.
257         text.Trim( false );      // Remove leading spaces in line
258         unsigned jj = 0;
259 
260         for( ; jj < text.Len(); jj++ )
261         {
262             // skip line number
263             if( text[jj] == ' ' )
264                 break;
265         }
266 
267         for( ; jj < text.Len(); jj++ )
268         {   // skip blanks
269             if( text[jj] != ' ' )
270                 break;
271         }
272 
273         int start_char = toupper( text[jj] );
274 
275         if( key == start_char )
276         {
277             SetSelection( ii, true );   // Ensure visible
278             break;
279         }
280     }
281 
282     event.Skip();
283 }
284