]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/listbox.cpp
adding alpha to core graphics dc
[wxWidgets.git] / src / gtk / listbox.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/listbox.cpp
3// Purpose:
4// Author: Robert Roebling
5// Modified By: Ryan Norton (GtkTreeView implementation)
6// Id: $Id$
7// Copyright: (c) 1998 Robert Roebling
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// For compilers that support precompilation, includes "wx.h".
12#include "wx/wxprec.h"
13
14#if wxUSE_LISTBOX
15
16#include "wx/listbox.h"
17
18#ifndef WX_PRECOMP
19 #include "wx/dynarray.h"
20 #include "wx/intl.h"
21 #include "wx/log.h"
22 #include "wx/utils.h"
23 #include "wx/settings.h"
24 #include "wx/checklst.h"
25 #include "wx/arrstr.h"
26#endif
27
28#include "wx/gtk/private.h"
29#include "wx/gtk/treeentry_gtk.h"
30
31#if wxUSE_TOOLTIPS
32 #include "wx/tooltip.h"
33#endif
34
35#include <gdk/gdk.h>
36#include <gtk/gtk.h>
37#include <gdk/gdkkeysyms.h>
38
39//-----------------------------------------------------------------------------
40// data
41//-----------------------------------------------------------------------------
42
43extern bool g_blockEventsOnDrag;
44extern bool g_blockEventsOnScroll;
45
46
47
48//-----------------------------------------------------------------------------
49// Macro to tell which row the strings are in (1 if native checklist, 0 if not)
50//-----------------------------------------------------------------------------
51
52#if wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST
53# define WXLISTBOX_DATACOLUMN_ARG(x) (x->m_hasCheckBoxes ? 1 : 0)
54#else
55# define WXLISTBOX_DATACOLUMN_ARG(x) (0)
56#endif // wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST
57
58#define WXLISTBOX_DATACOLUMN WXLISTBOX_DATACOLUMN_ARG(this)
59
60//-----------------------------------------------------------------------------
61// "row-activated"
62//-----------------------------------------------------------------------------
63
64extern "C" {
65static void
66gtk_listbox_row_activated_callback(GtkTreeView *treeview,
67 GtkTreePath *path,
68 GtkTreeViewColumn *col,
69 wxListBox *listbox)
70{
71 if (g_isIdle) wxapp_install_idle_handler();
72
73 if (g_blockEventsOnDrag) return;
74 if (g_blockEventsOnScroll) return;
75
76 if (!listbox->m_hasVMT) return;
77
78 //Notes:
79 //1) This is triggered by either a double-click or a space press
80 //2) We handle both here because
81 //2a) in the case of a space/keypress we can't really know
82 // which item was pressed on because we can't get coords
83 // from a keyevent
84 //2b) It seems more correct
85
86 int sel = gtk_tree_path_get_indices(path)[0];
87
88 if(!listbox->m_spacePressed)
89 {
90 //Assume it was double-click
91 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, listbox->GetId() );
92 event.SetEventObject( listbox );
93
94 if(listbox->IsSelected(sel))
95 {
96 GtkTreeEntry* entry = listbox->GtkGetEntry(sel);
97
98 if(entry)
99 {
100 event.SetInt(sel);
101 event.SetString(wxConvUTF8.cMB2WX(gtk_tree_entry_get_label(entry)));
102
103 if ( listbox->HasClientObjectData() )
104 event.SetClientObject(
105 (wxClientData*) gtk_tree_entry_get_userdata(entry) );
106 else if ( listbox->HasClientUntypedData() )
107 event.SetClientData( gtk_tree_entry_get_userdata(entry) );
108 g_object_unref (entry);
109 }
110 else
111 {
112 wxLogSysError(wxT("Internal error - could not get entry for double-click"));
113 event.SetInt(-1);
114 }
115 }
116 else
117 event.SetInt(-1);
118
119 listbox->GetEventHandler()->ProcessEvent( event );
120 }
121 else
122 {
123 listbox->m_spacePressed = false; //don't block selection behaviour anymore
124
125 //Space was pressed - toggle the appropriate checkbox and the selection
126#if wxUSE_CHECKLISTBOX //Do it for both native and non-native
127 if (listbox->m_hasCheckBoxes)
128 {
129 wxCheckListBox *clb = (wxCheckListBox *)listbox;
130
131 clb->Check( sel, !clb->IsChecked(sel) );
132
133 wxCommandEvent new_event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
134 new_event.SetEventObject( listbox );
135 new_event.SetInt( sel );
136 listbox->GetEventHandler()->ProcessEvent( new_event );
137 }
138#endif // wxUSE_CHECKLISTBOX
139
140 if( (((listbox->GetWindowStyleFlag() & wxLB_MULTIPLE) != 0) ||
141 ((listbox->GetWindowStyleFlag() & wxLB_EXTENDED) != 0)) )
142 {
143 //toggle the selection + send event
144 listbox->GtkSetSelection(sel, !listbox->IsSelected( sel ), false);
145 }
146 }
147}
148}
149
150//-----------------------------------------------------------------------------
151// "button_press_event"
152//-----------------------------------------------------------------------------
153
154extern "C" {
155static gint
156gtk_listbox_button_press_callback( GtkWidget *widget,
157 GdkEventButton *gdk_event,
158 wxListBox *listbox )
159{
160 if (g_isIdle) wxapp_install_idle_handler();
161
162 if (g_blockEventsOnDrag) return FALSE;
163 if (g_blockEventsOnScroll) return FALSE;
164
165 if (!listbox->m_hasVMT) return FALSE;
166
167 //Just to be on the safe side - it should be unset in the activate callback
168 //but we don't want any obscure bugs if it doesn't get called somehow...
169 listbox->m_spacePressed = false;
170
171#if wxUSE_CHECKLISTBOX && !wxUSE_NATIVEGTKCHECKLIST
172 if ((listbox->m_hasCheckBoxes) && (gdk_event->x < 15) && (gdk_event->type != GDK_2BUTTON_PRESS))
173 {
174 GtkTreePath* path;
175 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
176 (gint)gdk_event->x, (gint)gdk_event->y,
177 &path, NULL, NULL, NULL);
178 int sel = gtk_tree_path_get_indices(path)[0];
179 gtk_tree_path_free(path);
180
181 wxCheckListBox *clb = (wxCheckListBox *)listbox;
182
183 clb->Check( sel, !clb->IsChecked(sel) );
184
185 wxCommandEvent event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
186 event.SetEventObject( listbox );
187 event.SetInt( sel );
188 listbox->GetEventHandler()->ProcessEvent( event );
189 }
190#endif // wxUSE_CHECKLISTBOX && !wxUSE_NATIVEGTKCHECKLIST
191
192 return FALSE;
193}
194}
195
196//-----------------------------------------------------------------------------
197// "key_press_event"
198//-----------------------------------------------------------------------------
199
200extern "C" {
201static gint
202gtk_listbox_key_press_callback( GtkWidget *widget,
203 GdkEventKey *gdk_event,
204 wxListBox *listbox )
205{
206 if (g_isIdle) wxapp_install_idle_handler();
207
208 if (g_blockEventsOnDrag) return FALSE;
209
210
211 bool ret = false;
212
213 if ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab))
214 {
215 wxNavigationKeyEvent new_event;
216 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
217 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
218 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
219 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
220 new_event.SetCurrentFocus( listbox );
221 ret = listbox->GetEventHandler()->ProcessEvent( new_event );
222 }
223
224 if ((gdk_event->keyval == GDK_Return) && (!ret))
225 {
226 // eat return in all modes (RN:WHY?)
227 ret = true;
228 }
229
230 // Check or uncheck item with SPACE
231 if (gdk_event->keyval == ' ')
232 {
233 //In the keyevent we don't know the index of the item
234 //and the activated event gets called anyway...
235 //
236 //Also, activating with the space causes the treeview to
237 //unselect all the items and then select the item in question
238 //wx's behaviour is to just toggle the item's selection state
239 //and leave the others alone
240 listbox->m_spacePressed = true;
241 }
242
243 if (ret)
244 {
245 g_signal_stop_emission_by_name (widget, "key_press_event");
246 return TRUE;
247 }
248
249 return FALSE;
250}
251}
252
253//-----------------------------------------------------------------------------
254// "select" and "deselect"
255//-----------------------------------------------------------------------------
256
257extern "C" {
258static gboolean gtk_listitem_select_cb( GtkTreeSelection* selection,
259 GtkTreeModel* model,
260 GtkTreePath* path,
261 gboolean is_selected,
262 wxListBox *listbox )
263{
264 if (g_isIdle) wxapp_install_idle_handler();
265
266 if (!listbox->m_hasVMT) return TRUE;
267 if (g_blockEventsOnDrag) return TRUE;
268
269 if (listbox->m_spacePressed) return FALSE; //see keyevent callback
270 if (listbox->m_blockEvent) return TRUE;
271
272 // NB: wxdocs explicitly say that this event only gets sent when
273 // something is actually selected, plus the controls example
274 // assumes so and passes -1 to the dogetclientdata funcs if not
275
276 // OK, so basically we need to do a bit of a run-around here as
277 // 1) is_selected says whether the item(s?) are CURRENTLY selected -
278 // i.e. if is_selected is FALSE then the item is going to be
279 // selected right now!
280 // 2) However, since it is not already selected and the user
281 // will expect it to be we need to manually select it and
282 // return FALSE telling GTK we handled the selection
283 if (is_selected) return TRUE;
284
285 int nIndex = gtk_tree_path_get_indices(path)[0];
286 GtkTreeEntry* entry = listbox->GtkGetEntry(nIndex);
287
288 if(entry)
289 {
290 //Now, as mentioned above, we manually select the row that is/was going
291 //to be selected anyway by GTK
292 listbox->m_blockEvent = true; //if we don't block events we will lock the
293 //app due to recursion!!
294
295 GtkTreeSelection* selection =
296 gtk_tree_view_get_selection(listbox->m_treeview);
297 GtkTreeIter iter;
298 gtk_tree_model_get_iter(GTK_TREE_MODEL(listbox->m_liststore), &iter, path);
299 gtk_tree_selection_select_iter(selection, &iter);
300
301 listbox->m_blockEvent = false;
302
303 //Finally, send the wx event
304 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, listbox->GetId() );
305 event.SetEventObject( listbox );
306
307 // indicate whether this is a selection or a deselection
308 event.SetExtraLong( 1 );
309
310 event.SetInt(nIndex);
311 event.SetString(wxConvUTF8.cMB2WX(gtk_tree_entry_get_label(entry)));
312
313 if ( listbox->HasClientObjectData() )
314 event.SetClientObject(
315 (wxClientData*) gtk_tree_entry_get_userdata(entry)
316 );
317 else if ( listbox->HasClientUntypedData() )
318 event.SetClientData( gtk_tree_entry_get_userdata(entry) );
319
320 listbox->GetEventHandler()->ProcessEvent( event );
321
322 g_object_unref (entry);
323 return FALSE; //We handled it/did it manually
324 }
325
326 return TRUE; //allow selection to change
327}
328}
329
330//-----------------------------------------------------------------------------
331// GtkTreeEntry destruction (to destroy client data)
332//-----------------------------------------------------------------------------
333
334extern "C" {
335static void gtk_tree_entry_destroy_cb(GtkTreeEntry* entry,
336 wxListBox* listbox)
337{
338 if(listbox->HasClientObjectData())
339 {
340 gpointer userdata = gtk_tree_entry_get_userdata(entry);
341 if(userdata)
342 delete (wxClientData *)userdata;
343 }
344}
345}
346
347//-----------------------------------------------------------------------------
348// Sorting callback (standard CmpNoCase return value)
349//-----------------------------------------------------------------------------
350
351extern "C" {
352static gint gtk_listbox_sort_callback(GtkTreeModel *model,
353 GtkTreeIter *a,
354 GtkTreeIter *b,
355 wxListBox *listbox)
356{
357 GtkTreeEntry* entry;
358 GtkTreeEntry* entry2;
359
360 gtk_tree_model_get(GTK_TREE_MODEL(listbox->m_liststore),
361 a,
362 WXLISTBOX_DATACOLUMN_ARG(listbox),
363 &entry, -1);
364 gtk_tree_model_get(GTK_TREE_MODEL(listbox->m_liststore),
365 b,
366 WXLISTBOX_DATACOLUMN_ARG(listbox),
367 &entry2, -1);
368 wxCHECK_MSG(entry, 0, wxT("Could not get entry"));
369 wxCHECK_MSG(entry2, 0, wxT("Could not get entry2"));
370
371 //We compare collate keys here instead of calling g_utf8_collate
372 //as it is rather slow (and even the docs reccommend this)
373 int ret = strcasecmp(gtk_tree_entry_get_collate_key(entry),
374 gtk_tree_entry_get_collate_key(entry2));
375
376 g_object_unref (entry);
377 g_object_unref (entry2);
378
379 return ret;
380}
381}
382
383//-----------------------------------------------------------------------------
384// Searching callback (TRUE == not equal, FALSE == equal)
385//-----------------------------------------------------------------------------
386
387extern "C" {
388static gboolean gtk_listbox_searchequal_callback(GtkTreeModel* model,
389 gint column,
390 const gchar* key,
391 GtkTreeIter* iter,
392 wxListBox* listbox)
393{
394 GtkTreeEntry* entry;
395
396 gtk_tree_model_get(GTK_TREE_MODEL(listbox->m_liststore),
397 iter,
398 WXLISTBOX_DATACOLUMN_ARG(listbox),
399 &entry, -1);
400 wxCHECK_MSG(entry, 0, wxT("Could not get entry"));
401 gchar* keycollatekey = g_utf8_collate_key(key, -1);
402
403 int ret = strcasecmp(keycollatekey,
404 gtk_tree_entry_get_collate_key(entry));
405
406 g_free(keycollatekey);
407 g_object_unref (entry);
408
409 return ret != 0;
410}
411}
412
413//-----------------------------------------------------------------------------
414// wxListBox
415//-----------------------------------------------------------------------------
416
417IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
418
419// ----------------------------------------------------------------------------
420// construction
421// ----------------------------------------------------------------------------
422
423void wxListBox::Init()
424{
425 m_treeview = (GtkTreeView*) NULL;
426#if wxUSE_CHECKLISTBOX
427 m_hasCheckBoxes = false;
428#endif // wxUSE_CHECKLISTBOX
429 m_spacePressed = false;
430}
431
432bool wxListBox::Create( wxWindow *parent, wxWindowID id,
433 const wxPoint &pos, const wxSize &size,
434 const wxArrayString& choices,
435 long style, const wxValidator& validator,
436 const wxString &name )
437{
438 wxCArrayString chs(choices);
439
440 return Create( parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
441 style, validator, name );
442}
443
444bool wxListBox::Create( wxWindow *parent, wxWindowID id,
445 const wxPoint &pos, const wxSize &size,
446 int n, const wxString choices[],
447 long style, const wxValidator& validator,
448 const wxString &name )
449{
450 m_needParent = true;
451 m_acceptsFocus = true;
452 m_blockEvent = false;
453
454 if (!PreCreation( parent, pos, size ) ||
455 !CreateBase( parent, id, pos, size, style, validator, name ))
456 {
457 wxFAIL_MSG( wxT("wxListBox creation failed") );
458 return false;
459 }
460
461 m_widget = gtk_scrolled_window_new( (GtkAdjustment*) NULL, (GtkAdjustment*) NULL );
462 if (style & wxLB_ALWAYS_SB)
463 {
464 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
465 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS );
466 }
467 else
468 {
469 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
470 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
471 }
472
473
474 GtkScrolledWindowSetBorder(m_widget, style);
475
476 m_treeview = GTK_TREE_VIEW( gtk_tree_view_new( ) );
477
478 //wxListBox doesn't have a header :)
479 //NB: If enabled SetFirstItem doesn't work correctly
480 gtk_tree_view_set_headers_visible(m_treeview, FALSE);
481
482#if wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST
483 if(m_hasCheckBoxes)
484 ((wxCheckListBox*)this)->DoCreateCheckList();
485#endif // wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST
486
487 // Create the data column
488 gtk_tree_view_insert_column_with_attributes(m_treeview, -1, "",
489 gtk_cell_renderer_text_new(),
490 "text",
491 WXLISTBOX_DATACOLUMN, NULL);
492
493 // Now create+set the model (GtkListStore) - first argument # of columns
494#if wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST
495 if(m_hasCheckBoxes)
496 m_liststore = gtk_list_store_new(2, G_TYPE_BOOLEAN,
497 GTK_TYPE_TREE_ENTRY);
498 else
499#endif
500 m_liststore = gtk_list_store_new(1, GTK_TYPE_TREE_ENTRY);
501
502 gtk_tree_view_set_model(m_treeview, GTK_TREE_MODEL(m_liststore));
503
504 g_object_unref (m_liststore); //free on treeview destruction
505
506 // Disable the pop-up textctrl that enables searching - note that
507 // the docs specify that even if this disabled (which we are doing)
508 // the user can still have it through the start-interactive-search
509 // key binding...either way we want to provide a searchequal callback
510 // NB: If this is enabled a doubleclick event (activate) gets sent
511 // on a successful search
512 gtk_tree_view_set_search_column(m_treeview, WXLISTBOX_DATACOLUMN);
513 gtk_tree_view_set_search_equal_func(m_treeview,
514 (GtkTreeViewSearchEqualFunc) gtk_listbox_searchequal_callback,
515 this,
516 NULL);
517
518 gtk_tree_view_set_enable_search(m_treeview, FALSE);
519
520
521 GtkTreeSelection* selection = gtk_tree_view_get_selection( m_treeview );
522 gtk_tree_selection_set_select_function(selection,
523 (GtkTreeSelectionFunc)gtk_listitem_select_cb,
524 this, NULL); //NULL == destroycb
525
526 GtkSelectionMode mode;
527 if (style & wxLB_MULTIPLE)
528 {
529 mode = GTK_SELECTION_MULTIPLE;
530 }
531 else if (style & wxLB_EXTENDED)
532 {
533 mode = GTK_SELECTION_EXTENDED;
534 }
535 else
536 {
537 // if style was 0 set single mode
538 m_windowStyle |= wxLB_SINGLE;
539 mode = GTK_SELECTION_SINGLE;
540 }
541
542 gtk_tree_selection_set_mode( selection, mode );
543
544 //Handle sortable stuff
545 if(style & wxLB_SORT)
546 {
547 //Setup sorting in ascending (wx) order
548 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(m_liststore),
549 WXLISTBOX_DATACOLUMN,
550 GTK_SORT_ASCENDING);
551
552 //Set the sort callback
553 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(m_liststore),
554 WXLISTBOX_DATACOLUMN,
555 (GtkTreeIterCompareFunc) gtk_listbox_sort_callback,
556 this, //userdata
557 NULL //"destroy notifier"
558 );
559 }
560
561
562 gtk_container_add (GTK_CONTAINER (m_widget), GTK_WIDGET(m_treeview) );
563
564 gtk_widget_show( GTK_WIDGET(m_treeview) );
565
566 wxListBox::DoInsertItems(wxArrayString(n, choices), 0); // insert initial items
567
568 //treeview-specific events
569 g_signal_connect(m_treeview, "row-activated",
570 G_CALLBACK(gtk_listbox_row_activated_callback), this);
571
572 // other events
573 g_signal_connect (m_treeview, "button_press_event",
574 G_CALLBACK (gtk_listbox_button_press_callback),
575 this);
576 g_signal_connect (m_treeview, "key_press_event",
577 G_CALLBACK (gtk_listbox_key_press_callback),
578 this);
579
580 m_parent->DoAddChild( this );
581
582 PostCreation(size);
583 SetBestSize(size); // need this too because this is a wxControlWithItems
584
585 return true;
586}
587
588wxListBox::~wxListBox()
589{
590 m_hasVMT = false;
591
592 Clear();
593}
594
595// ----------------------------------------------------------------------------
596// adding items
597// ----------------------------------------------------------------------------
598
599void wxListBox::GtkInsertItems(const wxArrayString& items,
600 void** clientData, unsigned int pos)
601{
602 wxCHECK_RET( m_treeview != NULL, wxT("invalid listbox") );
603
604 InvalidateBestSize();
605
606 // Create and set column ids and GValues
607
608 unsigned int nNum = items.GetCount();
609 unsigned int nCurCount = wxListBox::GetCount();
610 wxASSERT_MSG(pos <= nCurCount, wxT("Invalid index passed to wxListBox"));
611
612 GtkTreeIter* pIter = NULL; // append by default
613 GtkTreeIter iter;
614 if (pos != nCurCount)
615 {
616 gboolean res = gtk_tree_model_iter_nth_child(
617 GTK_TREE_MODEL(m_liststore),
618 &iter, NULL, //NULL = parent = get first
619 (int)pos );
620 if(!res)
621 {
622 wxLogSysError(wxT("internal wxListBox error in insertion"));
623 return;
624 }
625
626 pIter = &iter;
627 }
628
629 for (unsigned int i = 0; i < nNum; ++i)
630 {
631 wxString label = items[i];
632
633#if wxUSE_CHECKLISTBOX && !wxUSE_NATIVEGTKCHECKLIST
634 if (m_hasCheckBoxes)
635 {
636 label.Prepend(wxCHECKLBOX_STRING);
637 }
638#endif // wxUSE_CHECKLISTBOX
639
640
641 GtkTreeEntry* entry = gtk_tree_entry_new();
642 gtk_tree_entry_set_label(entry, wxConvUTF8.cWX2MB(label));
643 gtk_tree_entry_set_destroy_func(entry,
644 (GtkTreeEntryDestroy)gtk_tree_entry_destroy_cb,
645 this);
646
647 if (clientData)
648 gtk_tree_entry_set_userdata(entry, clientData[i]);
649
650 GtkTreeIter itercur;
651 gtk_list_store_insert_before(m_liststore, &itercur, pIter);
652
653#if wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST
654 if (m_hasCheckBoxes)
655 {
656 gtk_list_store_set(m_liststore, &itercur,
657 0, FALSE, //FALSE == not toggled
658 1, entry, -1);
659 }
660 else
661#endif
662 gtk_list_store_set(m_liststore, &itercur,
663 0, entry, -1);
664
665 g_object_unref (entry); //liststore always refs :)
666 }
667}
668
669void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
670{
671 wxCHECK_RET( IsValidInsert(pos), wxT("invalid index in wxListBox::InsertItems") );
672
673 GtkInsertItems(items, NULL, pos);
674}
675
676int wxListBox::DoAppend( const wxString& item )
677{
678 // Call DoInsertItems
679 unsigned int nWhere = wxListBox::GetCount();
680 wxArrayString aItems;
681 aItems.Add(item);
682 wxListBox::DoInsertItems(aItems, nWhere);
683 return nWhere;
684}
685
686void wxListBox::DoSetItems( const wxArrayString& items,
687 void **clientData)
688{
689 Clear();
690 GtkInsertItems(items, clientData, 0);
691}
692
693// ----------------------------------------------------------------------------
694// deleting items
695// ----------------------------------------------------------------------------
696
697void wxListBox::Clear()
698{
699 wxCHECK_RET( m_treeview != NULL, wxT("invalid listbox") );
700
701 InvalidateBestSize();
702
703 gtk_list_store_clear( m_liststore ); /* well, THAT was easy :) */
704}
705
706void wxListBox::Delete(unsigned int n)
707{
708 wxCHECK_RET( m_treeview != NULL, wxT("invalid listbox") );
709
710 InvalidateBestSize();
711
712 GtkTreeIter iter;
713 gboolean res = gtk_tree_model_iter_nth_child(
714 GTK_TREE_MODEL(m_liststore),
715 &iter, NULL, //NULL = parent = get first
716 n
717 );
718
719 wxCHECK_RET( res, wxT("wrong listbox index") );
720
721 //this returns false if iter is invalid (i.e. deleting item
722 //at end) but since we don't use iter, well... :)
723 gtk_list_store_remove(m_liststore, &iter);
724}
725
726// ----------------------------------------------------------------------------
727// get GtkTreeEntry from position (note: you need to g_unref it if valid)
728// ----------------------------------------------------------------------------
729
730struct _GtkTreeEntry* wxListBox::GtkGetEntry(int n) const
731{
732 GtkTreeIter iter;
733 gboolean res = gtk_tree_model_iter_nth_child(
734 GTK_TREE_MODEL(m_liststore),
735 &iter, NULL, //NULL = parent = get first
736 n );
737
738 if (!res)
739 {
740 wxLogDebug(wxT("gtk_tree_model_iter_nth_child failed\n")
741 wxT("Passed in value was:[%i] List size:[%u]"),
742 n, wxListBox::GetCount() );
743 return NULL;
744 }
745
746
747 GtkTreeEntry* entry = NULL;
748 gtk_tree_model_get(GTK_TREE_MODEL(m_liststore), &iter,
749 WXLISTBOX_DATACOLUMN, &entry, -1);
750
751 return entry;
752}
753
754// ----------------------------------------------------------------------------
755// client data
756// ----------------------------------------------------------------------------
757
758void* wxListBox::DoGetItemClientData(unsigned int n) const
759{
760 wxCHECK_MSG( IsValid(n), NULL,
761 wxT("Invalid index passed to GetItemClientData") );
762
763 GtkTreeEntry* entry = GtkGetEntry(n);
764 wxCHECK_MSG(entry, NULL, wxT("could not get entry"));
765
766 void* userdata = gtk_tree_entry_get_userdata( entry );
767 g_object_unref (entry);
768 return userdata;
769}
770
771wxClientData* wxListBox::DoGetItemClientObject(unsigned int n) const
772{
773 return (wxClientData*) wxListBox::DoGetItemClientData(n);
774}
775
776void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
777{
778 wxCHECK_RET( IsValid(n),
779 wxT("Invalid index passed to SetItemClientData") );
780
781 GtkTreeEntry* entry = GtkGetEntry(n);
782 wxCHECK_RET(entry, wxT("could not get entry"));
783
784 gtk_tree_entry_set_userdata( entry, clientData );
785 g_object_unref (entry);
786}
787
788void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
789{
790 // wxItemContainer already deletes data for us
791 wxListBox::DoSetItemClientData(n, (void*) clientData);
792}
793
794// ----------------------------------------------------------------------------
795// string list access
796// ----------------------------------------------------------------------------
797
798void wxListBox::SetString(unsigned int n, const wxString &string)
799{
800 wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::SetString") );
801 wxCHECK_RET( m_treeview != NULL, wxT("invalid listbox") );
802
803 GtkTreeEntry* entry = GtkGetEntry(n);
804 wxCHECK_RET( entry, wxT("wrong listbox index") );
805
806 wxString label = string;
807
808#if wxUSE_CHECKLISTBOX && !wxUSE_NATIVEGTKCHECKLIST
809 if (m_hasCheckBoxes)
810 label.Prepend(wxCHECKLBOX_STRING);
811#endif // wxUSE_CHECKLISTBOX
812
813 // RN: This may look wierd but the problem is that the TreeView
814 // doesn't resort or update when changed above and there is no real
815 // notification function...
816 void* userdata = gtk_tree_entry_get_userdata(entry);
817 gtk_tree_entry_set_userdata(entry, NULL); //don't delete on destroy
818 g_object_unref (entry);
819
820 bool bWasSelected = wxListBox::IsSelected(n);
821 wxListBox::Delete(n);
822
823 wxArrayString aItems;
824 aItems.Add(label);
825 GtkInsertItems(aItems, &userdata, n);
826 if (bWasSelected)
827 wxListBox::GtkSetSelection(n, true, true);
828}
829
830wxString wxListBox::GetString(unsigned int n) const
831{
832 wxCHECK_MSG( m_treeview != NULL, wxEmptyString, wxT("invalid listbox") );
833
834 GtkTreeEntry* entry = GtkGetEntry(n);
835 wxCHECK_MSG( entry, wxEmptyString, wxT("wrong listbox index") );
836
837 wxString label = wxGTK_CONV_BACK( gtk_tree_entry_get_label(entry) );
838
839#if wxUSE_CHECKLISTBOX && !wxUSE_NATIVEGTKCHECKLIST
840