]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/combobox.cpp
add missing ! accidentally dropped in last commit
[wxWidgets.git] / src / gtk / combobox.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/combobox.cpp
3// Purpose:
4// Author: Robert Roebling
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
13#if wxUSE_COMBOBOX
14
15#include "wx/combobox.h"
16
17#ifndef WX_PRECOMP
18 #include "wx/intl.h"
19 #include "wx/settings.h"
20 #include "wx/textctrl.h" // for wxEVT_COMMAND_TEXT_UPDATED
21 #include "wx/arrstr.h"
22#endif
23
24#include "wx/gtk/private.h"
25
26// ----------------------------------------------------------------------------
27// GTK callbacks
28// ----------------------------------------------------------------------------
29
30extern "C" {
31static void
32gtkcombobox_text_changed_callback( GtkWidget *WXUNUSED(widget), wxComboBox *combo )
33{
34 if (!combo->m_hasVMT) return;
35
36 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, combo->GetId() );
37 event.SetString( combo->GetValue() );
38 event.SetEventObject( combo );
39 combo->HandleWindowEvent( event );
40}
41
42static void
43gtkcombobox_changed_callback( GtkWidget *WXUNUSED(widget), wxComboBox *combo )
44{
45 if (!combo->m_hasVMT) return;
46
47 if (combo->GetSelection() == -1)
48 return;
49
50 wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, combo->GetId() );
51 event.SetInt( combo->GetSelection() );
52 event.SetString( combo->GetStringSelection() );
53 event.SetEventObject( combo );
54 combo->HandleWindowEvent( event );
55}
56}
57
58//-----------------------------------------------------------------------------
59// wxComboBox
60//-----------------------------------------------------------------------------
61
62IMPLEMENT_DYNAMIC_CLASS(wxComboBox,wxControl)
63
64BEGIN_EVENT_TABLE(wxComboBox, wxControl)
65 EVT_CHAR(wxComboBox::OnChar)
66
67 EVT_MENU(wxID_CUT, wxComboBox::OnCut)
68 EVT_MENU(wxID_COPY, wxComboBox::OnCopy)
69 EVT_MENU(wxID_PASTE, wxComboBox::OnPaste)
70 EVT_MENU(wxID_UNDO, wxComboBox::OnUndo)
71 EVT_MENU(wxID_REDO, wxComboBox::OnRedo)
72 EVT_MENU(wxID_CLEAR, wxComboBox::OnDelete)
73 EVT_MENU(wxID_SELECTALL, wxComboBox::OnSelectAll)
74
75 EVT_UPDATE_UI(wxID_CUT, wxComboBox::OnUpdateCut)
76 EVT_UPDATE_UI(wxID_COPY, wxComboBox::OnUpdateCopy)
77 EVT_UPDATE_UI(wxID_PASTE, wxComboBox::OnUpdatePaste)
78 EVT_UPDATE_UI(wxID_UNDO, wxComboBox::OnUpdateUndo)
79 EVT_UPDATE_UI(wxID_REDO, wxComboBox::OnUpdateRedo)
80 EVT_UPDATE_UI(wxID_CLEAR, wxComboBox::OnUpdateDelete)
81 EVT_UPDATE_UI(wxID_SELECTALL, wxComboBox::OnUpdateSelectAll)
82END_EVENT_TABLE()
83
84bool wxComboBox::Create( wxWindow *parent, wxWindowID id,
85 const wxString& value,
86 const wxPoint& pos, const wxSize& size,
87 const wxArrayString& choices,
88 long style, const wxValidator& validator,
89 const wxString& name )
90{
91 wxCArrayString chs(choices);
92
93 return Create( parent, id, value, pos, size, chs.GetCount(),
94 chs.GetStrings(), style, validator, name );
95}
96
97bool wxComboBox::Create( wxWindow *parent, wxWindowID id, const wxString& value,
98 const wxPoint& pos, const wxSize& size,
99 int n, const wxString choices[],
100 long style, const wxValidator& validator,
101 const wxString& name )
102{
103 m_strings = NULL;
104 m_ignoreNextUpdate = false;
105 m_prevSelection = 0;
106
107 if (!PreCreation( parent, pos, size ) ||
108 !CreateBase( parent, id, pos, size, style, validator, name ))
109 {
110 wxFAIL_MSG( wxT("wxComboBox creation failed") );
111 return false;
112 }
113
114 if (HasFlag(wxCB_SORT))
115 m_strings = new wxSortedArrayString();
116
117 m_widget = gtk_combo_box_entry_new_text();
118
119 if (HasFlag(wxBORDER_NONE))
120 {
121 // Doesn't seem to work
122 // g_object_set (m_widget, "has-frame", FALSE, NULL);
123 }
124
125 GtkEntry * const entry = GetEntry();
126
127 gtk_entry_set_editable( entry, TRUE );
128
129 Append(n, choices);
130
131 m_parent->DoAddChild( this );
132
133 m_focusWidget = GTK_WIDGET( entry );
134
135 PostCreation(size);
136
137 ConnectWidget( m_widget );
138
139 gtk_entry_set_text( entry, wxGTK_CONV(value) );
140
141 if (style & wxCB_READONLY)
142 gtk_entry_set_editable( entry, FALSE );
143
144 g_signal_connect_after (entry, "changed",
145 G_CALLBACK (gtkcombobox_text_changed_callback), this);
146
147 g_signal_connect_after (m_widget, "changed",
148 G_CALLBACK (gtkcombobox_changed_callback), this);
149
150
151 SetInitialSize(size); // need this too because this is a wxControlWithItems
152
153 return true;
154}
155
156GtkEntry *wxComboBox::GetEntry() const
157{
158 return GTK_ENTRY(GTK_BIN(m_widget)->child);
159}
160
161GtkEditable *wxComboBox::GetEditable() const
162{
163 return GTK_EDITABLE( GTK_BIN(m_widget)->child );
164}
165
166wxComboBox::~wxComboBox()
167{
168 Clear();
169
170 delete m_strings;
171}
172
173void wxComboBox::SetFocus()
174{
175 if ( m_hasFocus )
176 {
177 // don't do anything if we already have focus
178 return;
179 }
180
181 gtk_widget_grab_focus( m_focusWidget );
182}
183
184int wxComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
185 unsigned int pos,
186 void **clientData, wxClientDataType type)
187{
188 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
189
190 wxASSERT_MSG( !IsSorted() || (pos == GetCount()),
191 _T("In a sorted combobox data could only be appended"));
192
193 const int count = items.GetCount();
194
195 int n = wxNOT_FOUND;
196
197 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
198 for( int i = 0; i < count; ++i )
199 {
200 n = pos + i;
201 // If sorted, use this wxSortedArrayStrings to determine
202 // the right insertion point
203 if(m_strings)
204 n = m_strings->Add(items[i]);
205
206 gtk_combo_box_insert_text( combobox, n, wxGTK_CONV( items[i] ) );
207
208 m_clientData.Insert( NULL, n );
209 AssignNewItemClientData(n, clientData, i, type);
210 }
211
212 InvalidateBestSize();
213
214 return n;
215}
216
217void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
218{
219 m_clientData[n] = clientData;
220}
221
222void* wxComboBox::DoGetItemClientData(unsigned int n) const
223{
224 return m_clientData[n];
225}
226
227void wxComboBox::DoClear()
228{
229 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
230
231 DisableEvents();
232
233 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
234 const unsigned int count = GetCount();
235 for (unsigned int i = 0; i < count; i++)
236 gtk_combo_box_remove_text( combobox, 0 );
237
238 m_clientData.Clear();
239
240 if(m_strings)
241 m_strings->Clear();
242
243 EnableEvents();
244
245 InvalidateBestSize();
246}
247
248void wxComboBox::DoDeleteOneItem(unsigned int n)
249{
250 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
251
252 wxCHECK_RET( IsValid(n), wxT("invalid index") );
253
254 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
255 gtk_combo_box_remove_text( combobox, n );
256
257 m_clientData.RemoveAt( n );
258 if(m_strings)
259 m_strings->RemoveAt( n );
260
261 InvalidateBestSize();
262}
263
264void wxComboBox::SetString(unsigned int n, const wxString &text)
265{
266 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
267
268 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
269 wxCHECK_RET( IsValid(n), wxT("invalid index") );
270
271 GtkTreeModel *model = gtk_combo_box_get_model( combobox );
272 GtkTreeIter iter;
273 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, n))
274 {
275 GValue value = { 0, };
276 g_value_init( &value, G_TYPE_STRING );
277 g_value_set_string( &value, wxGTK_CONV( text ) );
278 gtk_list_store_set_value( GTK_LIST_STORE(model), &iter, 0, &value );
279 g_value_unset( &value );
280 }
281
282 InvalidateBestSize();
283}
284
285int wxComboBox::FindString( const wxString &item, bool bCase ) const
286{
287 wxCHECK_MSG( m_widget != NULL, wxNOT_FOUND, wxT("invalid combobox") );
288
289 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
290 GtkTreeModel* model = gtk_combo_box_get_model( combobox );
291 GtkTreeIter iter;
292 gtk_tree_model_get_iter_first( model, &iter );
293 if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model), &iter ))
294 return -1;
295 int count = 0;
296 do
297 {
298 GValue value = { 0, };
299 gtk_tree_model_get_value( model, &iter, 0, &value );
300 wxString str = wxGTK_CONV_BACK( g_value_get_string( &value ) );
301 g_value_unset( &value );
302
303 if (item.IsSameAs( str, bCase ) )
304 return count;
305
306 count++;
307 }
308 while ( gtk_tree_model_iter_next(model, &iter) );
309
310 return wxNOT_FOUND;
311}
312
313int wxComboBox::GetSelection() const
314{
315 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
316 return gtk_combo_box_get_active( combobox );
317}
318
319int wxComboBox::GetCurrentSelection() const
320{
321 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
322
323 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
324 return gtk_combo_box_get_active( combobox );
325}
326
327wxString wxComboBox::GetString(unsigned int n) const
328{
329 wxCHECK_MSG( m_widget != NULL, wxEmptyString, wxT("invalid combobox") );
330
331 wxString str;
332
333 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
334 GtkTreeModel *model = gtk_combo_box_get_model( combobox );
335 GtkTreeIter iter;
336 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, n))
337 {
338 GValue value = { 0, };
339 gtk_tree_model_get_value( model, &iter, 0, &value );
340 wxString tmp = wxGTK_CONV_BACK( g_value_get_string( &value ) );
341 g_value_unset( &value );
342 return tmp;
343 }
344
345 return str;
346}
347
348unsigned int wxComboBox::GetCount() const
349{
350 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid combobox") );
351
352 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
353 GtkTreeModel* model = gtk_combo_box_get_model( combobox );
354 GtkTreeIter iter;
355 gtk_tree_model_get_iter_first( model, &iter );
356 if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model), &iter ))
357 return 0;
358 unsigned int ret = 1;
359 while (gtk_tree_model_iter_next( model, &iter ))
360 ret++;
361 return ret;
362}
363
364void wxComboBox::SetSelection( int n )
365{
366 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
367
368 DisableEvents();
369
370 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
371 gtk_combo_box_set_active( combobox, n );
372
373 EnableEvents();
374}
375
376void wxComboBox::OnChar( wxKeyEvent &event )
377{
378 switch ( event.GetKeyCode() )
379 {
380 case WXK_RETURN:
381 if ( HasFlag(wxTE_PROCESS_ENTER) )
382 {
383 // GTK automatically selects an item if its in the list
384 wxCommandEvent eventEnter(wxEVT_COMMAND_TEXT_ENTER, GetId());
385 eventEnter.SetString( GetValue() );
386 eventEnter.SetInt( GetSelection() );
387 eventEnter.SetEventObject( this );
388
389 if ( HandleWindowEvent(eventEnter) )
390 {
391 // Catch GTK event so that GTK doesn't open the drop
392 // down list upon RETURN.
393 return;
394 }
395 }
396 break;
397 }
398
399 event.Skip();
400}
401
402void wxComboBox::DisableEvents()
403{
404 g_signal_handlers_block_by_func(GTK_BIN(m_widget)->child,
405 (gpointer)gtkcombobox_text_changed_callback, this);
406
407 g_signal_handlers_block_by_func(m_widget,
408 (gpointer)gtkcombobox_changed_callback, this);
409}
410
411void wxComboBox::EnableEvents()
412{
413 g_signal_handlers_unblock_by_func(GTK_BIN(m_widget)->child,
414 (gpointer)gtkcombobox_text_changed_callback, this);
415
416 g_signal_handlers_unblock_by_func(m_widget,
417 (gpointer)gtkcombobox_changed_callback, this);
418}
419
420GtkWidget* wxComboBox::GetConnectWidget()
421{
422 return GTK_WIDGET( GetEntry() );
423}
424
425GdkWindow *wxComboBox::GTKGetWindow(wxArrayGdkWindows& windows) const
426{
427 wxUnusedVar(windows);
428
429 return GetEntry()->text_area;
430}
431
432wxSize wxComboBox::DoGetBestSize() const
433{
434 wxSize ret( wxControl::DoGetBestSize() );
435
436 // we know better our horizontal extent: it depends on the longest string
437 // in the combobox
438 if ( m_widget )
439 {
440 int width;
441 unsigned int count = GetCount();
442 for ( unsigned int n = 0; n < count; n++ )
443 {
444 GetTextExtent(GetString(n), &width, NULL, NULL, NULL );
445 if ( width > ret.x )
446 ret.x = width;
447 }
448 }
449
450 // empty combobox should have some reasonable default size too
451 if ( ret.x < 100 )
452 ret.x = 100;
453
454 CacheBestSize(ret);
455 return ret;
456}
457
458// static
459wxVisualAttributes
460wxComboBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
461{
462 return GetDefaultAttributesFromGTKWidget(gtk_combo_box_entry_new, true);
463}
464
465// ----------------------------------------------------------------------------
466// standard event handling
467// ----------------------------------------------------------------------------
468
469void wxComboBox::OnCut(wxCommandEvent& WXUNUSED(event))
470{
471 Cut();
472}
473
474void wxComboBox::OnCopy(wxCommandEvent& WXUNUSED(event))
475{
476 Copy();
477}
478
479void wxComboBox::OnPaste(wxCommandEvent& WXUNUSED(event))
480{
481 Paste();
482}
483
484void wxComboBox::OnUndo(wxCommandEvent& WXUNUSED(event))
485{
486 Undo();
487}
488
489void wxComboBox::OnRedo(wxCommandEvent& WXUNUSED(event))
490{
491 Redo();
492}
493
494void wxComboBox::OnDelete(wxCommandEvent& WXUNUSED(event))
495{
496 long from, to;
497 GetSelection(& from, & to);
498 if (from != -1 && to != -1)
499 Remove(from, to);
500}
501
502void wxComboBox::OnSelectAll(wxCommandEvent& WXUNUSED(event))
503{
504 SetSelection(-1, -1);
505}
506
507void wxComboBox::OnUpdateCut(wxUpdateUIEvent& event)
508{
509 event.Enable( CanCut() );
510}
511
512void wxComboBox::OnUpdateCopy(wxUpdateUIEvent& event)
513{
514 event.Enable( CanCopy() );
515}
516
517void wxComboBox::OnUpdatePaste(wxUpdateUIEvent& event)
518{
519 event.Enable( CanPaste() );
520}
521
522void wxComboBox::OnUpdateUndo(wxUpdateUIEvent& event)
523{
524 event.Enable( CanUndo() );
525}
526
527void wxComboBox::OnUpdateRedo(wxUpdateUIEvent& event)
528{
529 event.Enable( CanRedo() );
530}
531
532void wxComboBox::OnUpdateDelete(wxUpdateUIEvent& event)
533{
534 event.Enable(HasSelection() && IsEditable()) ;
535}
536
537void wxComboBox::OnUpdateSelectAll(wxUpdateUIEvent& event)
538{
539 event.Enable(GetLastPosition() > 0);
540}
541
542#endif // wxUSE_COMBOBOX