diff --git a/include/wx/gtk/listbox.h b/include/wx/gtk/listbox.h index 45b330c515..707665eaad 100644 --- a/include/wx/gtk/listbox.h +++ b/include/wx/gtk/listbox.h @@ -100,6 +100,8 @@ public: void GTKDisableEvents(); void GTKEnableEvents(); + void GTKOnSelectionChanged(); + protected: virtual void DoClear(); virtual void DoDeleteOneItem(unsigned int n); diff --git a/include/wx/listbox.h b/include/wx/listbox.h index d2332d5d13..f023f6fa65 100644 --- a/include/wx/listbox.h +++ b/include/wx/listbox.h @@ -49,7 +49,7 @@ public: // multiple selection logic virtual bool IsSelected(int n) const = 0; - virtual void SetSelection(int n) { DoSetSelection(n, true); } + virtual void SetSelection(int n); void SetSelection(int n, bool select) { DoSetSelection(n, select); } void Deselect(int n) { DoSetSelection(n, false); } void DeselectAll(int itemToLeaveSelected = -1); @@ -96,11 +96,6 @@ public: int HitTest(int x, int y) const { return DoListHitTest(wxPoint(x, y)); } - // For generating events in multiple and extended mode: compare the current - // selections with the previously recorded ones (in m_oldSelections) and - // send the appropriate event if they differ, otherwise just return false. - bool CalcAndSendEvent(); - protected: virtual void DoSetFirstItem(int n) = 0; @@ -110,6 +105,17 @@ protected: virtual int DoListHitTest(const wxPoint& WXUNUSED(point)) const { return wxNOT_FOUND; } + // Helper for the code generating events in single selection mode: updates + // m_oldSelections and return true if the selection really changed. + // Otherwise just returns false. + bool DoChangeSingleSelection(int item); + + // Helper for generating events in multiple and extended mode: compare the + // current selections with the previously recorded ones (in + // m_oldSelections) and send the appropriate event if they differ, + // otherwise just return false. + bool CalcAndSendEvent(); + // Send a listbox (de)selection or double click event. // // Returns true if the event was processed. @@ -118,6 +124,9 @@ protected: // Array storing the indices of all selected items that we already notified // the user code about for multi selection list boxes. // + // For single selection list boxes, we reuse this array to store the single + // currently selected item, this is used by DoChangeSingleSelection(). + // // TODO-OPT: wxSelectionStore would be more efficient for big list boxes. wxArrayInt m_oldSelections; diff --git a/src/common/lboxcmn.cpp b/src/common/lboxcmn.cpp index 8787130451..5d7abb469f 100644 --- a/src/common/lboxcmn.cpp +++ b/src/common/lboxcmn.cpp @@ -59,6 +59,14 @@ bool wxListBoxBase::SetStringSelection(const wxString& s, bool select) return true; } +void wxListBoxBase::SetSelection(int n) +{ + if ( !HasMultipleSelection() ) + DoChangeSingleSelection(n); + + DoSetSelection(n, true); +} + void wxListBoxBase::DeselectAll(int itemToLeaveSelected) { if ( HasMultipleSelection() ) @@ -114,6 +122,24 @@ bool wxListBoxBase::SendEvent(wxEventType evtType, int item, bool selected) return HandleWindowEvent(event); } +bool wxListBoxBase::DoChangeSingleSelection(int item) +{ + // As we don't use m_oldSelections in single selection mode, we store the + // last item that we notified the user about in it in this case because we + // need to remember it to be able to filter out the dummy selection changes + // that we get when the user clicks on an already selected item. + if ( !m_oldSelections.empty() && *m_oldSelections.begin() == item ) + { + // Same item as the last time. + return false; + } + + m_oldSelections.clear(); + m_oldSelections.push_back(item); + + return true; +} + bool wxListBoxBase::CalcAndSendEvent() { wxArrayInt selections; diff --git a/src/gtk/listbox.cpp b/src/gtk/listbox.cpp index 5260617949..19d4beb5a6 100644 --- a/src/gtk/listbox.cpp +++ b/src/gtk/listbox.cpp @@ -119,49 +119,9 @@ gtk_listitem_changed_callback(GtkTreeSelection * WXUNUSED(selection), { if (g_blockEventsOnDrag) return; - if (listbox->HasFlag(wxLB_MULTIPLE | wxLB_EXTENDED)) - { - listbox->CalcAndSendEvent(); - } - else // single selection - { - wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, listbox->GetId() ); - event.SetEventObject( listbox ); - - int index = listbox->GetSelection(); - if (index == wxNOT_FOUND) - { - // indicate that this is a deselection - event.SetExtraLong( 0 ); - event.SetInt( -1 ); - - listbox->HandleWindowEvent( event ); - - return; - } - else - { - GtkTreeEntry* entry = listbox->GTKGetEntry( index ); - - // indicate that this is a selection - event.SetExtraLong( 1 ); - - event.SetInt( index ); - event.SetString(wxConvUTF8.cMB2WX(gtk_tree_entry_get_label(entry))); - - if ( listbox->HasClientObjectData() ) - event.SetClientObject( - (wxClientData*) gtk_tree_entry_get_userdata(entry) - ); - else if ( listbox->HasClientUntypedData() ) - event.SetClientData( gtk_tree_entry_get_userdata(entry) ); - - listbox->HandleWindowEvent( event ); - - g_object_unref (entry); - } - } + listbox->GTKOnSelectionChanged(); } + } //----------------------------------------------------------------------------- @@ -761,6 +721,55 @@ int wxListBox::FindString( const wxString &item, bool bCase ) const // selection // ---------------------------------------------------------------------------- +void wxListBox::GTKOnSelectionChanged() +{ + if ( HasFlag(wxLB_MULTIPLE | wxLB_EXTENDED) ) + { + CalcAndSendEvent(); + } + else // single selection + { + const int index = GetSelection(); + if ( !DoChangeSingleSelection(index) ) + return; + + wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, GetId() ); + event.SetEventObject( this ); + + if (index == wxNOT_FOUND) + { + // indicate that this is a deselection + event.SetExtraLong( 0 ); + event.SetInt( -1 ); + + HandleWindowEvent( event ); + + return; + } + else + { + GtkTreeEntry* entry = GTKGetEntry( index ); + + // indicate that this is a selection + event.SetExtraLong( 1 ); + + event.SetInt( index ); + event.SetString(wxConvUTF8.cMB2WX(gtk_tree_entry_get_label(entry))); + + if ( HasClientObjectData() ) + event.SetClientObject( + (wxClientData*) gtk_tree_entry_get_userdata(entry) + ); + else if ( HasClientUntypedData() ) + event.SetClientData( gtk_tree_entry_get_userdata(entry) ); + + HandleWindowEvent( event ); + + g_object_unref (entry); + } + } +} + int wxListBox::GetSelection() const { wxCHECK_MSG( m_treeview != NULL, wxNOT_FOUND, wxT("invalid listbox")); diff --git a/src/msw/listbox.cpp b/src/msw/listbox.cpp index 53d60ce89b..52fe4d0c4d 100644 --- a/src/msw/listbox.cpp +++ b/src/msw/listbox.cpp @@ -689,20 +689,10 @@ bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) if ( n == wxNOT_FOUND ) return false; - // As we don't use m_oldSelections in single selection mode, we store the - // last item that we notified the user about in it in this case because we - // need to remember it to be able to filter out the dummy LBN_SELCHANGE - // messages that we get when the user clicks on an already selected item. if ( param == LBN_SELCHANGE ) { - if ( !m_oldSelections.empty() && *m_oldSelections.begin() == n ) - { - // Same item as the last time. + if ( !DoChangeSingleSelection(n) ) return false; - } - - m_oldSelections.clear(); - m_oldSelections.push_back(n); } // Do generate an event otherwise.