]> git.saurik.com Git - wxWidgets.git/blob - src/univ/combobox.cpp
Guard against comparing invalid iterators, which produces an assertion
[wxWidgets.git] / src / univ / combobox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/combobox.cpp
3 // Purpose: wxComboBox implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 15.12.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #if wxUSE_COMBOBOX
27
28 #ifndef WX_PRECOMP
29 #include "wx/log.h"
30
31 #include "wx/button.h"
32 #include "wx/combobox.h"
33 #include "wx/listbox.h"
34 #include "wx/textctrl.h"
35 #include "wx/bmpbuttn.h"
36
37 #include "wx/validate.h"
38 #endif
39
40 #include "wx/tooltip.h"
41 #include "wx/combo.h"
42
43 #include "wx/univ/renderer.h"
44 #include "wx/univ/inphand.h"
45 #include "wx/univ/theme.h"
46
47
48 // ----------------------------------------------------------------------------
49 // wxComboListBox is a listbox modified to be used as a popup window in a
50 // combobox
51 // ----------------------------------------------------------------------------
52
53 class wxComboListBox : public wxListBox, public wxComboPopup
54 {
55 public:
56 // ctor and dtor
57 wxComboListBox();
58 virtual ~wxComboListBox();
59
60 // implement wxComboPopup methods
61 virtual bool Create(wxWindow* parent);
62 virtual void SetStringValue(const wxString& s);
63 virtual wxString GetStringValue() const;
64 virtual wxWindow *GetControl() { return this; }
65 virtual void OnPopup();
66 virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight);
67
68 // fix virtual function hiding
69 virtual void SetSelection(int n) { DoSetSelection(n, true); }
70 void SetSelection(int n, bool select) { DoSetSelection(n, select); }
71
72 // used to process wxUniv actions
73 bool PerformAction(const wxControlAction& action,
74 long numArg,
75 const wxString& strArg);
76
77 protected:
78 // set m_clicked value from here
79 void OnLeftUp(wxMouseEvent& event);
80
81 private:
82 DECLARE_EVENT_TABLE()
83 };
84
85 // ----------------------------------------------------------------------------
86 // event tables and such
87 // ----------------------------------------------------------------------------
88
89 BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
90 EVT_LEFT_UP(wxComboListBox::OnLeftUp)
91 END_EVENT_TABLE()
92
93 IMPLEMENT_DYNAMIC_CLASS2(wxComboBox, wxControl, wxComboCtrl)
94
95 // ============================================================================
96 // implementation
97 // ============================================================================
98
99 // ----------------------------------------------------------------------------
100 // wxComboListBox
101 // ----------------------------------------------------------------------------
102
103 wxComboListBox::wxComboListBox() : wxListBox(), wxComboPopup()
104 {
105 }
106
107 bool wxComboListBox::Create(wxWindow* parent)
108 {
109 if ( !wxListBox::Create(parent, wxID_ANY,
110 wxDefaultPosition, wxDefaultSize,
111 0, NULL,
112 wxBORDER_SIMPLE | wxLB_INT_HEIGHT |
113 m_combo->GetWindowStyle() & wxCB_SORT ? wxLB_SORT : 0) )
114 return false;
115
116 // we don't react to the mouse events outside the window at all
117 StopAutoScrolling();
118
119 return true;
120 }
121
122 wxComboListBox::~wxComboListBox()
123 {
124 }
125
126 wxString wxComboListBox::GetStringValue() const
127 {
128 return wxListBox::GetStringSelection();
129 }
130
131 void wxComboListBox::SetStringValue(const wxString& value)
132 {
133 if ( !value.empty() )
134 wxListBox::SetStringSelection(value);
135 else
136 wxListBox::SetSelection(-1);
137 }
138
139 void wxComboListBox::OnPopup()
140 {
141 }
142
143 bool wxComboListBox::PerformAction(const wxControlAction& action,
144 long numArg,
145 const wxString& strArg)
146
147 {
148 if ( action == wxACTION_LISTBOX_FIND )
149 {
150 // we don't let the listbox handle this as instead of just using the
151 // single key presses, as usual, we use the text ctrl value as prefix
152 // and this is done by wxComboCtrl itself
153 return true;
154 }
155
156 return wxListBox::PerformAction(action, numArg, strArg);
157 }
158
159 void wxComboListBox::OnLeftUp(wxMouseEvent& event)
160 {
161 // we should dismiss the combo now
162 // first update the combo and close the listbox
163 Dismiss();
164 m_combo->SetValue(wxListBox::GetStringSelection());
165
166 // next let the user code have the event
167 wxCommandEvent evt(wxEVT_COMMAND_COMBOBOX_SELECTED,m_combo->GetId());
168 evt.SetInt(wxListBox::GetSelection());
169 evt.SetEventObject(m_combo);
170 m_combo->ProcessEvent(evt);
171
172 event.Skip();
173 }
174
175 wxSize wxComboListBox::GetAdjustedSize(int minWidth,
176 int WXUNUSED(prefHeight),
177 int maxHeight)
178 {
179 wxSize bestSize = wxListBox::GetBestSize();
180 return wxSize(wxMax(bestSize.x,minWidth),
181 wxMin(bestSize.y,maxHeight));
182 }
183
184 // ----------------------------------------------------------------------------
185 // wxComboBox
186 // ----------------------------------------------------------------------------
187
188 void wxComboBox::Init()
189 {
190 m_lbox = (wxListBox *)NULL;
191 }
192
193 wxComboBox::wxComboBox(wxWindow *parent,
194 wxWindowID id,
195 const wxString& value,
196 const wxPoint& pos,
197 const wxSize& size,
198 const wxArrayString& choices,
199 long style,
200 const wxValidator& validator,
201 const wxString& name)
202 {
203 Init();
204
205 Create(parent, id, value, pos, size, choices, style, validator, name);
206 }
207
208 bool wxComboBox::Create(wxWindow *parent,
209 wxWindowID id,
210 const wxString& value,
211 const wxPoint& pos,
212 const wxSize& size,
213 const wxArrayString& choices,
214 long style,
215 const wxValidator& validator,
216 const wxString& name)
217 {
218 wxCArrayString chs(choices);
219
220 return Create(parent, id, value, pos, size, chs.GetCount(),
221 chs.GetStrings(), style, validator, name);
222 }
223
224 bool wxComboBox::Create(wxWindow *parent,
225 wxWindowID id,
226 const wxString& value,
227 const wxPoint& pos,
228 const wxSize& size,
229 int n,
230 const wxString choices[],
231 long style,
232 const wxValidator& validator,
233 const wxString& name)
234 {
235 if ( !wxComboCtrl::Create(parent, id, value, pos, size, style,
236 validator, name) )
237 {
238 return false;
239 }
240
241 wxComboListBox *combolbox = new wxComboListBox();
242 SetPopupControl(combolbox);
243
244 m_lbox = combolbox;
245 m_lbox->Set(n, choices);
246
247 return true;
248 }
249
250 wxComboBox::~wxComboBox()
251 {
252 }
253
254 // ----------------------------------------------------------------------------
255 // wxComboBox methods forwarded to wxTextCtrl
256 // ----------------------------------------------------------------------------
257
258 wxString wxComboBox::GetValue() const
259 {
260 return wxComboCtrl::GetValue();
261 }
262
263 void wxComboBox::SetValue(const wxString& value)
264 {
265 wxComboCtrl::SetValue(value);
266 }
267
268 void wxComboBox::Copy()
269 {
270 if ( GetTextCtrl() ) GetTextCtrl()->Copy();
271 }
272
273 void wxComboBox::Cut()
274 {
275 if ( GetTextCtrl() ) GetTextCtrl()->Cut();
276 }
277
278 void wxComboBox::Paste()
279 {
280 if ( GetTextCtrl() ) GetTextCtrl()->Paste();
281 }
282
283 void wxComboBox::SetInsertionPoint(long pos)
284 {
285 if ( GetTextCtrl() ) GetTextCtrl()->SetInsertionPoint(pos);
286 }
287
288 void wxComboBox::SetInsertionPointEnd()
289 {
290 if ( GetTextCtrl() ) GetTextCtrl()->SetInsertionPointEnd();
291 }
292
293 long wxComboBox::GetInsertionPoint() const
294 {
295 if ( GetTextCtrl() )
296 return GetTextCtrl()->GetInsertionPoint();
297 return -1;
298 }
299
300 wxTextPos wxComboBox::GetLastPosition() const
301 {
302 if ( GetTextCtrl() )
303 return GetTextCtrl()->GetLastPosition();
304 return -1;
305 }
306
307 void wxComboBox::Replace(long from, long to, const wxString& value)
308 {
309 if ( GetTextCtrl() ) GetTextCtrl()->Replace(from, to, value);
310 }
311
312 void wxComboBox::Remove(long from, long to)
313 {
314 if ( GetTextCtrl() ) GetTextCtrl()->Remove(from, to);
315 }
316
317 void wxComboBox::SetSelection(long from, long to)
318 {
319 if ( GetTextCtrl() ) GetTextCtrl()->SetSelection(from, to);
320 }
321
322 void wxComboBox::SetEditable(bool editable)
323 {
324 if ( GetTextCtrl() ) GetTextCtrl()->SetEditable(editable);
325 }
326
327 // ----------------------------------------------------------------------------
328 // wxComboBox methods forwarded to wxListBox
329 // ----------------------------------------------------------------------------
330
331 void wxComboBox::Clear()
332 {
333 GetLBox()->Clear();
334 if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
335 }
336
337 void wxComboBox::Delete(unsigned int n)
338 {
339 wxCHECK_RET( IsValid(n), _T("invalid index in wxComboBox::Delete") );
340
341 if (GetSelection() == (int)n)
342 if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
343
344 GetLBox()->Delete(n);
345 }
346
347 unsigned int wxComboBox::GetCount() const
348 {
349 return GetLBox()->GetCount();
350 }
351
352 wxString wxComboBox::GetString(unsigned int n) const
353 {
354 wxCHECK_MSG( IsValid(n), wxEmptyString, _T("invalid index in wxComboBox::GetString") );
355
356 return GetLBox()->GetString(n);
357 }
358
359 void wxComboBox::SetString(unsigned int n, const wxString& s)
360 {
361 wxCHECK_RET( IsValid(n), _T("invalid index in wxComboBox::SetString") );
362
363 GetLBox()->SetString(n, s);
364 }
365
366 int wxComboBox::FindString(const wxString& s, bool bCase) const
367 {
368 return GetLBox()->FindString(s, bCase);
369 }
370
371 void wxComboBox::SetSelection(int n)
372 {
373 wxCHECK_RET( IsValid(n), _T("invalid index in wxComboBox::Select") );
374
375 GetLBox()->SetSelection(n);
376 if ( GetTextCtrl() ) GetTextCtrl()->SetValue(GetLBox()->GetString(n));
377 }
378
379 int wxComboBox::GetSelection() const
380 {
381 #if 1 // FIXME:: What is the correct behavior?
382 // if the current value isn't one of the listbox strings, return -1
383 return GetLBox()->GetSelection();
384 #else
385 // Why oh why is this done this way?
386 // It is not because the value displayed in the text can be found
387 // in the list that it is the item that is selected!
388 return FindString(if ( GetTextCtrl() ) GetTextCtrl()->GetValue());
389 #endif
390 }
391
392 int wxComboBox::DoAppend(const wxString& item)
393 {
394 return GetLBox()->Append(item);
395 }
396
397 int wxComboBox::DoInsert(const wxString& item, unsigned int pos)
398 {
399 wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
400 wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
401
402 if (pos == GetCount())
403 return DoAppend(item);
404
405 GetLBox()->Insert(item, pos);
406 return pos;
407 }
408
409 void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
410 {
411 GetLBox()->SetClientData(n, clientData);
412 }
413
414 void *wxComboBox::DoGetItemClientData(unsigned int n) const
415 {
416 return GetLBox()->GetClientData(n);
417 }
418
419 void wxComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
420 {
421 GetLBox()->SetClientObject(n, clientData);
422 }
423
424 wxClientData* wxComboBox::DoGetItemClientObject(unsigned int n) const
425 {
426 return GetLBox()->GetClientObject(n);
427 }
428
429 bool wxComboBox::IsEditable() const
430 {
431 return GetTextCtrl() != NULL && (!HasFlag(wxCB_READONLY) || GetTextCtrl()->IsEditable() );
432 }
433
434 void wxComboBox::Undo()
435 {
436 if (IsEditable())
437 if ( GetTextCtrl() ) GetTextCtrl()->Undo();
438 }
439
440 void wxComboBox::Redo()
441 {
442 if (IsEditable())
443 if ( GetTextCtrl() ) GetTextCtrl()->Redo();
444 }
445
446 void wxComboBox::SelectAll()
447 {
448 if ( GetTextCtrl() ) GetTextCtrl()->SelectAll();
449 }
450
451 bool wxComboBox::CanCopy() const
452 {
453 if (GetTextCtrl() != NULL)
454 return GetTextCtrl()->CanCopy();
455 else
456 return false;
457 }
458
459 bool wxComboBox::CanCut() const
460 {
461 if (GetTextCtrl() != NULL)
462 return GetTextCtrl()->CanCut();
463 else
464 return false;
465 }
466
467 bool wxComboBox::CanPaste() const
468 {
469 if (IsEditable())
470 return GetTextCtrl()->CanPaste();
471 else
472 return false;
473 }
474
475 bool wxComboBox::CanUndo() const
476 {
477 if (IsEditable())
478 return GetTextCtrl()->CanUndo();
479 else
480 return false;
481 }
482
483 bool wxComboBox::CanRedo() const
484 {
485 if (IsEditable())
486 return GetTextCtrl()->CanRedo();
487 else
488 return false;
489 }
490
491
492 // ----------------------------------------------------------------------------
493 // wxStdComboBoxInputHandler
494 // ----------------------------------------------------------------------------
495
496 wxStdComboBoxInputHandler::wxStdComboBoxInputHandler(wxInputHandler *inphand)
497 : wxStdInputHandler(inphand)
498 {
499 }
500
501 bool wxStdComboBoxInputHandler::HandleKey(wxInputConsumer *consumer,
502 const wxKeyEvent& event,
503 bool pressed)
504 {
505 if ( pressed )
506 {
507 wxControlAction action;
508 switch ( event.GetKeyCode() )
509 {
510 case WXK_DOWN:
511 action = wxACTION_COMBOBOX_POPUP;
512 break;
513
514 case WXK_ESCAPE:
515 action = wxACTION_COMBOBOX_DISMISS;
516 break;
517 }
518
519 if ( !action.IsEmpty() )
520 {
521 consumer->PerformAction(action);
522
523 return true;
524 }
525 }
526
527 return wxStdInputHandler::HandleKey(consumer, event, pressed);
528 }
529
530
531 #endif // wxUSE_COMBOBOX