NCBI C++ ToolKit
auto_complete_combo.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: auto_complete_combo.cpp 47479 2023-05-02 13:24:02Z ucko $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Andrey Yazhuk
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
35 
37 
38 #include <wx/textctrl.h>
39 
40 
42 
43 BEGIN_EVENT_TABLE(CAutoCompleteCombo, wxComboBox)
46  EVT_KEY_DOWN( CAutoCompleteCombo::OnKeyDown )
47  EVT_IDLE( CAutoCompleteCombo::OnIdle )
48 # ifndef __WXMSW__
49  EVT_TIMER(-1, CAutoCompleteCombo::x_OnTimer)
50 # endif
51 
53 
54 
55 CAutoCompleteCombo::CAutoCompleteCombo( wxWindow* parent, wxWindowID id )
56 # ifndef __WXMSW__
57  : m_Timer( this )
58 # endif
59 {
60  Init();
61 
62  wxArrayString choices;
63  Create(
64  parent, id, wxT(""), wxDefaultPosition, wxDefaultSize,
65  choices, wxCB_DROPDOWN
66  );
67 }
68 
70  wxWindow* parent,
71  wxWindowID id,
72  const wxString& value,
73  const wxPoint& pos,
74  const wxSize& size,
75  const wxArrayString& choices,
76  long style,
77  const wxValidator& validator,
78  const wxString& name
79 )
80 # ifndef __WXMSW__
81  : m_Timer( this )
82 # endif
83 {
84  Init();
85  Create( parent, id, value, pos, size, choices, style | wxCB_DROPDOWN, validator, name );
86 }
87 
89 {
90 }
91 
93 {
94  m_IgnoreCase = false;
97  m_DoBackspace = false;
98  m_Filtered = false;
99  m_MatchedOnly = false;
100  m_AutoOff = false;
101 
102  m_PrevValue = wxT("");
103  m_PrevCursor = 0;
104 }
105 
107  wxWindow* parent,
108  wxWindowID id,
109  const wxString& value,
110  const wxPoint& pos,
111  const wxSize& size,
112  const wxArrayString& choices,
113  long style,
114  const wxValidator& validator,
115  const wxString& name
116 ){
117  m_BaseChoices = choices;
118  m_PrevArray = choices;
119 
120  wxComboBox::Create( parent, id, value, pos, size, choices, style, validator, name );
121 }
122 
123 void CAutoCompleteCombo::SetBaseItems( const wxArrayString& choices )
124 {
125  if (m_BaseChoices == choices)
126  return;
127 
128  m_BaseChoices = choices;
129 
130  Clear();
131  Append( choices );
132 }
133 
134 void CAutoCompleteCombo::GetBaseItems( wxArrayString& choices )
135 {
136  choices = m_BaseChoices;
137 }
138 
140 {
141  wxString value = GetValue();
142  if (m_BaseChoices.Index(value) != wxNOT_FOUND) {
143  return;
144  }
145 
146  while (GetCount() >= DICTIONARY_MAX_SIZE) {
147  if (GetCount()) Delete(0);
148  m_BaseChoices.RemoveAt(m_BaseChoices.GetCount() - 1);
149  }
150  m_BaseChoices.Insert(value, 0);
151  Append(value);
152 }
153 
154 void CAutoCompleteCombo::OnTextChanged( wxCommandEvent& event )
155 {
156  _TRACE("CAutoCompleteCombo::OnTextChanged " << ToStdString(event.GetString()));
158  event.Skip();
159  return;
160  }
161 
163 
164  if( !m_MatchedOnly &&
165  (event.GetString().length() <= m_PrevValue.length()) ){
166  m_PrevValue = event.GetString();
167  m_PrevCursor = GetInsertionPoint();
168  event.Skip();
169  return;
170  }
171 
172 
173  if( m_MatchedOnly ){
174  wxString cur_value = event.GetString();
175  long cur_pt = GetInsertionPoint();
176 
177  if( m_DoBackspace ){
178  cur_value = cur_value.Mid( 0, cur_value.Len() -1 );
179  cur_pt -= 1;
180  m_DoBackspace = false;
181  }
182 
183  if( m_PrevValue == cur_value ){
184  SetValue( m_PrevValue );
185  x_AutoComplete();
186  event.Skip();
187  return;
188  }
189 
190  wxArrayString new_base_choices = ProvideItems( cur_value );
191  wxArrayString* compare_to = HasProvider() ? &new_base_choices : &m_BaseChoices;
192 
193  wxString cur_low = m_IgnoreCase ? cur_value.Lower() : cur_value;
194  unsigned int matched_ix = 0;
195  while( matched_ix < compare_to->GetCount() ){
196  wxString cmp_str = m_IgnoreCase ? (*compare_to)[matched_ix].Lower() : (*compare_to)[matched_ix];
197 
198  if( cmp_str.StartsWith( cur_low ) ){
199  break;
200  }
201  ++matched_ix;
202  }
203  if( matched_ix == compare_to->GetCount() ){
204  SetValue( m_PrevValue );
205  x_AutoComplete();
206  return;
207  }
208 
209  if( HasProvider() ){
210  m_BaseChoices = new_base_choices;
211  }
212 
213  wxArrayString new_choices = m_Filtered ? GetFilteredItems( cur_value ) : m_BaseChoices;
214 
215  if( HasProvider() || m_Filtered ){
216  Clear();
217  Append( m_BaseChoices );
218  }
219 
220  SetValue( cur_value );
221  SetInsertionPoint( cur_pt );
222 
223  m_PrevValue = cur_value;
224  m_PrevCursor = cur_pt;
225 
226  x_AutoComplete();
227 
228  } else {
229  if( m_PrevValue == event.GetString() ){
230  x_AutoComplete();
231  event.Skip();
232  return;
233  }
234 
235  wxString cur_value = event.GetString();
236  long cur_pt = GetInsertionPoint();
237 
238 
239  m_PrevValue = cur_value;
240  m_PrevCursor = cur_pt;
241 
242  bool to_be_completed = cur_pt == GetLastPosition();
243 
244  // update base items
245  if( HasProvider() ){
246  m_BaseChoices = ProvideItems( cur_value );
247  }
248 
249  wxArrayString new_choices = m_Filtered ? GetFilteredItems( cur_value ) : m_BaseChoices;
250 
251  if( HasProvider() || m_Filtered ){
252  Clear();
253  Append( m_BaseChoices );
254 
255  SetValue( m_PrevValue );
256  SetInsertionPoint( m_PrevCursor );
257  }
258 
259 
260  if( to_be_completed && !m_AutoOff ){
261  x_AutoComplete();
262  }
263  }
264 }
265 
266 
267 void CAutoCompleteCombo::OnItemSelected( wxCommandEvent& event )
268 {
269  _TRACE("CAutoCompleteCombo::OnItemSelected index " << event.GetSelection() );// << " text " << str.c_str());
270 
271  wxString cur_value = m_IgnoreCase ? GetValue().Lower() : GetValue();
272  wxString prev_value = m_IgnoreCase ? m_PrevValue.Lower() : m_PrevValue;
273 
274  if( cur_value.StartsWith( prev_value ) ){
275  SetInsertionPoint( (long)prev_value.Length() );
276  SetSelection( (int)prev_value.Length(), -1 );
277  }
278 
279  if( cur_value.StartsWith( prev_value ) ){
280  SetInsertionPoint( (long)prev_value.Length() );
281  SetSelection( (int)prev_value.Length(), -1 );
282  }
283 
285 
286  event.Skip();
287 }
288 
289 void CAutoCompleteCombo::OnKeyDown( wxKeyEvent &event )
290 {
291  //***********************************************************************
292  //Note: This currently doesn't get called in in wxWidgets 2.9.3 for Cocoa
293  // but since the matching feature is only used in Radar (windows only)
294  // that should not be a problem.
295  //************************************************************************
296  _TRACE( "CAutoCompleteCombo::OnKeyDown " << event.GetKeyCode() );
297 
298  int kc = event.GetKeyCode();
299 
300  if( m_MatchedOnly ){
301  if( (kc == WXK_BACK || kc == WXK_CLEAR) ){
302 #if defined(__WXMAC__)
303  if( GetSelection() == GetLastPosition() ){
304  m_DoBackspace = true;
305  }
306 #else
307  long from, to;
308  GetSelection( &from, &to );
309  if( from != to && to == GetLastPosition() ){
310  m_DoBackspace = true;
311  }
312 #endif
313  }
314  }
315  event.Skip();
316 }
317 
318 void CAutoCompleteCombo::OnIdle( wxIdleEvent &event )
319 {
321  _TRACE( "CAutoCompleteCombo::OnIdle" );
322  }
323 
325  event.Skip();
326 }
327 
328 
330 {
331 # ifndef __WXMSW__
332  m_Timer.Start( 10, true );
333 }
334 void CAutoCompleteCombo::x_OnTimer( wxTimerEvent& )
335 {
336 # endif
337 
338  wxString orig_value = GetValue();
339  wxString prefix = m_IgnoreCase ? orig_value.Lower() : orig_value;
340 
341  for( unsigned int i = 0; i < GetCount(); i++ ){
342  wxString value = GetString( i );
343  wxString str_value = m_IgnoreCase ? value.Lower() : value;
344  if( str_value.StartsWith( prefix ) ){
345  // without this "if" application dead locks on Ubuntu/GTK and wxwidgets 2.9.3
346  if (value != orig_value) {
347  SetValue( value );
348  SetSelection( (int)prefix.Len(), -1 );
349  }
350  break;
351  }
352  }
353 }
354 
355 wxArrayString CAutoCompleteCombo::ProvideItems( const wxString& pattern )
356 {
357  wxArrayString wx_items;
358 
359  if( !m_Provider.IsNull() ){
360  vector<string> items;
361 
362  m_Provider->GetItems( ToStdString( pattern ), items );
363 
364  for( int i = 0; i < (int)items.size(); i++ ){
365  wx_items.Add( ToWxString( items[i] ) );
366  }
367  }
368 
369  return wx_items;
370 }
371 
372 wxArrayString CAutoCompleteCombo::GetFilteredItems( const wxString& pattern )
373 {
374  wxArrayString new_choices;
375  wxString pat_low = m_IgnoreCase ? pattern.Lower() : pattern;
376 
377  for( int i = 0; i < (int)m_BaseChoices.GetCount(); i++ ){
378  wxString base_choice = m_IgnoreCase ? m_BaseChoices[i].Lower() : m_BaseChoices[i];
379  if( base_choice.StartsWith( pat_low ) ){
380  new_choices.Add( m_BaseChoices[i] );
381  }
382  }
383 
384  return new_choices;
385 }
386 
387 /*
388 template<> void CMRUItemsProvider<string>::GetItems( const string& pattern, vector<string>& result )
389 {
390  m_List.GetItems( result );
391 }
392 */
393 
#define DICTIONARY_MAX_SIZE
CAutoCompleteComboBox.
CAutoCompleteCombo(wxWindow *parent, wxWindowID id=wxID_ANY)
void SetBaseItems(const wxArrayString &choices)
wxArrayString GetFilteredItems(const wxString &pattern)
void x_OnTimer(wxTimerEvent &event)
void GetBaseItems(wxArrayString &choices)
virtual wxArrayString ProvideItems(const wxString &pattern)
void OnIdle(wxIdleEvent &event)
void OnKeyDown(wxKeyEvent &event)
void x_AutoComplete()
Completes value from available choices.
void OnItemSelected(wxCommandEvent &event)
CIRef< IFilterItems > m_Provider
void Create(wxWindow *parent, wxWindowID id, const wxString &value, const wxPoint &pos, const wxSize &size, const wxArrayString &choices, long style=wxCB_DROPDOWN, const wxValidator &validator=wxDefaultValidator, const wxString &name=wxT("auto complete combo"))
void OnTextChanged(wxCommandEvent &event)
static void Init(void)
Definition: cursor6.c:76
#define _TRACE(message)
Definition: ncbidbg.hpp:122
bool IsNull(void) const THROWS_NONE
Check if pointer is null – same effect as Empty().
Definition: ncbiobj.hpp:735
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
END_EVENT_TABLE()
int i
#define wxT(x)
Definition: muParser.cpp:41
const struct ncbi::grid::netcache::search::fields::SIZE size
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
static const char * prefix[]
Definition: pcregrep.c:405
static static static wxID_ANY
wxString ToWxString(const string &s)
Definition: wx_utils.hpp:173
string ToStdString(const wxString &s)
Definition: wx_utils.hpp:161
Modified on Tue Jun 18 13:35:32 2024 by modify_doxy.py rev. 669887