From e6279e3ea863c79ef9dceff69efa6a53b7198fbc Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Wed, 21 May 2014 19:11:22 -0700 Subject: [PATCH] MGR: Continue fixing detection of list selection and list deselection; deselecting by clicking on empty part of list control (below or on its right) does not generate any list events if the selected item has been scrolled out of view, so we must use mouse click events within the wxListCtrl. --- clientgui/BOINCBaseView.cpp | 25 +++++++++++++------------ clientgui/BOINCBaseView.h | 5 +++-- clientgui/BOINCListCtrl.cpp | 26 ++++++++++++++++++++++++++ clientgui/BOINCListCtrl.h | 17 +++++++++++++++++ clientgui/ViewProjects.cpp | 6 +----- clientgui/ViewTransfers.cpp | 6 +----- clientgui/ViewWork.cpp | 6 +----- 7 files changed, 62 insertions(+), 29 deletions(-) diff --git a/clientgui/BOINCBaseView.cpp b/clientgui/BOINCBaseView.cpp index ad6f2029b2..0dd252f994 100644 --- a/clientgui/BOINCBaseView.cpp +++ b/clientgui/BOINCBaseView.cpp @@ -34,7 +34,6 @@ IMPLEMENT_DYNAMIC_CLASS(CBOINCBaseView, wxPanel) - CBOINCBaseView::CBOINCBaseView() {} CBOINCBaseView::CBOINCBaseView(wxNotebook* pNotebook) : @@ -337,8 +336,9 @@ bool CBOINCBaseView::OnRestoreState(wxConfigBase* pConfig) { } -// We don't currently use this because selecting an item -// triggers an EVT_LIST_CACHE_HINT; see OnCacheHint() below. +// We don't use this because multiple selection virtual +// wxListCtrl does not generate selection events for +// shift-click; see OnCheckSelectionChanged() below. void CBOINCBaseView::OnListSelected(wxListEvent& event) { wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseView::OnListSelected - Function Begin")); @@ -352,8 +352,9 @@ void CBOINCBaseView::OnListSelected(wxListEvent& event) { } -// We don't currently use this because selecting an item -// triggers an EVT_LIST_CACHE_HINT; see OnCacheHint() below. +// We don't use this because multiple selection virtual +// wxListCtrl does generates deselection events only for +// control-click; see OnCheckSelectionChanged() below. void CBOINCBaseView::OnListDeselected(wxListEvent& event) { wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseView::OnListDeselected - Function Begin")); @@ -367,13 +368,14 @@ void CBOINCBaseView::OnListDeselected(wxListEvent& event) { } -// Work around bugs (features?) in virtual list control: -// * It does not send deselection events. -// * It (apparently intentionally) does not send selection -// events if you add to selection using Shift_Click. +// Work around features in multiple selection virtual wxListCtrl: +// * It does not send deselection events (except ctrl-click). +// * It does not send selection events if you add to selection +// using Shift_Click. // -// We currently handle all selections and deselections here. -void CBOINCBaseView::OnCacheHint(wxListEvent& event) { +// We currently handle all selections and deselections here. This +// is called due to an event posted by CBOINCListCtrl::OnMouseUp(). +void CBOINCBaseView::OnCheckSelectionChanged(CCheckSelectionChangedEvent& ) { int newSelectionCount = m_pListPane->GetSelectedItemCount(); long currentSelection = m_pListPane->GetFirstSelected(); @@ -388,7 +390,6 @@ void CBOINCBaseView::OnCacheHint(wxListEvent& event) { m_iPreviousSelectionCount = newSelectionCount; m_lPreviousFirstSelection = currentSelection; - event.Skip(); } diff --git a/clientgui/BOINCBaseView.h b/clientgui/BOINCBaseView.h index d2a935d7e1..92d28d2fdb 100644 --- a/clientgui/BOINCBaseView.h +++ b/clientgui/BOINCBaseView.h @@ -22,11 +22,13 @@ #pragma interface "BOINCBaseView.cpp" #endif + #define DEFAULT_TASK_FLAGS wxTAB_TRAVERSAL | wxADJUST_MINSIZE | wxFULL_REPAINT_ON_RESIZE #define DEFAULT_LIST_FLAGS wxLC_REPORT | wxLC_VIRTUAL | wxLC_HRULES class CBOINCTaskCtrl; class CBOINCListCtrl; +class CCheckSelectionChangedEvent; struct PROJECT; @@ -146,7 +148,7 @@ protected: virtual void OnListRender( wxTimerEvent& event ); virtual void OnListSelected( wxListEvent& event ); virtual void OnListDeselected( wxListEvent& event ); - virtual void OnCacheHint(wxListEvent& event); + virtual void OnCheckSelectionChanged(CCheckSelectionChangedEvent& event); virtual wxString OnListGetItemText( long item, long column ) const; virtual int OnListGetItemImage( long item ) const; @@ -202,6 +204,5 @@ protected: CBOINCListCtrl* m_pListPane; }; - #endif diff --git a/clientgui/BOINCListCtrl.cpp b/clientgui/BOINCListCtrl.cpp index 85369d93e4..6ac41de583 100644 --- a/clientgui/BOINCListCtrl.cpp +++ b/clientgui/BOINCListCtrl.cpp @@ -25,18 +25,23 @@ #include "Events.h" +DEFINE_EVENT_TYPE(wxEVT_CHECK_SELECTION_CHANGED) + #if USE_NATIVE_LISTCONTROL DEFINE_EVENT_TYPE(wxEVT_DRAW_PROGRESSBAR) BEGIN_EVENT_TABLE(CBOINCListCtrl, LISTCTRL_BASE) EVT_DRAW_PROGRESSBAR(CBOINCListCtrl::OnDrawProgressBar) + EVT_LEFT_DOWN(CBOINCListCtrl::OnMouseClick) + EVT_LEFT_UP(CBOINCListCtrl::OnMouseClick) END_EVENT_TABLE() #else BEGIN_EVENT_TABLE(CBOINCListCtrl, LISTCTRL_BASE) EVT_SIZE(CBOINCListCtrl::OnSize) + EVT_LEFT_DOWN(CBOINCListCtrl::OnMouseClick) END_EVENT_TABLE() #endif @@ -383,6 +388,27 @@ void MyEvtHandler::OnPaint(wxPaintEvent & event) #endif +// Work around features in multiple selection virtual wxListCtrl: +// * It does not send deselection events (except ctrl-click). +// * It does not send selection events if you add to selection +// using Shift_Click. +// +// Post a special event. This will allow this mouse event to +// propogate through the chain to complete any selection or +// deselection operatiion, then the special event will trigger +// CBOINCBaseView::OnCheckSelectionChanged() to respond to the +// selection change, if any. + +// On Windows, selection occurs on mouse down but deselection +// occurs on mouse up, so we must check after both events. +// +void CBOINCListCtrl::OnMouseClick(wxMouseEvent& event) { + CCheckSelectionChangedEvent newEvent(wxEVT_CHECK_SELECTION_CHANGED, this); + m_pParentView->GetEventHandler()->AddPendingEvent(newEvent); + event.Skip(); +} + + // To reduce flicker, refresh only changed columns (except // on Mac, which is double-buffered to eliminate flicker.) void CBOINCListCtrl::RefreshCell(int row, int col) { diff --git a/clientgui/BOINCListCtrl.h b/clientgui/BOINCListCtrl.h index f0cc34ef5e..72c813f0b4 100644 --- a/clientgui/BOINCListCtrl.h +++ b/clientgui/BOINCListCtrl.h @@ -96,6 +96,7 @@ private: void SetupMacAccessibilitySupport(); void RemoveMacAccessibilitySupport(); void OnSize( wxSizeEvent &event ); + void OnMouseClick(wxMouseEvent& event); void* m_fauxHeaderView; void* m_fauxBodyView; @@ -117,12 +118,28 @@ public: virtual wxEvent * Clone() const { return new CDrawProgressBarEvent(*this); } }; +class CCheckSelectionChangedEvent : public wxEvent +{ +public: + CCheckSelectionChangedEvent(wxEventType evtType, CBOINCListCtrl* myCtrl) + : wxEvent(-1, evtType) + { + SetEventObject(myCtrl); + } + + virtual wxEvent * Clone() const { return new CCheckSelectionChangedEvent(*this); } +}; + + BEGIN_DECLARE_EVENT_TYPES() DECLARE_EVENT_TYPE( wxEVT_DRAW_PROGRESSBAR, 12000 ) +DECLARE_EVENT_TYPE( wxEVT_CHECK_SELECTION_CHANGED, 12002 ) END_DECLARE_EVENT_TYPES() #define EVT_DRAW_PROGRESSBAR(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_DRAW_PROGRESSBAR, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL), +#define EVT_CHECK_SELECTION_CHANGED(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_CHECK_SELECTION_CHANGED, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL), + // Define a custom event handler class MyEvtHandler : public wxEvtHandler diff --git a/clientgui/ViewProjects.cpp b/clientgui/ViewProjects.cpp index 9ab2408831..81ffa3a7fc 100644 --- a/clientgui/ViewProjects.cpp +++ b/clientgui/ViewProjects.cpp @@ -82,11 +82,7 @@ BEGIN_EVENT_TABLE (CViewProjects, CBOINCBaseView) EVT_BUTTON(ID_TASK_PROJECT_DETACH, CViewProjects::OnProjectDetach) EVT_BUTTON(ID_TASK_PROJECT_SHOW_PROPERTIES, CViewProjects::OnShowItemProperties) EVT_CUSTOM_RANGE(wxEVT_COMMAND_BUTTON_CLICKED, ID_TASK_PROJECT_WEB_PROJDEF_MIN, ID_TASK_PROJECT_WEB_PROJDEF_MAX, CViewProjects::OnProjectWebsiteClicked) -// We currently handle EVT_LIST_CACHE_HINT instead of EVT_LIST_ITEM_SELECTED -// or EVT_LIST_ITEM_DESELECTED. See CBOINCBaseView::OnCacheHint() for info. -// EVT_LIST_ITEM_SELECTED(ID_LIST_PROJECTSVIEW, CViewProjects::OnListSelected) -// EVT_LIST_ITEM_DESELECTED(ID_LIST_PROJECTSVIEW, CViewProjects::OnListDeselected) - EVT_LIST_CACHE_HINT(ID_LIST_PROJECTSVIEW, CViewProjects::OnCacheHint) + EVT_CHECK_SELECTION_CHANGED(CViewProjects::OnCheckSelectionChanged) EVT_LIST_COL_CLICK(ID_LIST_PROJECTSVIEW, CViewProjects::OnColClick) EVT_LIST_COL_END_DRAG(ID_LIST_PROJECTSVIEW, CViewProjects::OnColResize) END_EVENT_TABLE () diff --git a/clientgui/ViewTransfers.cpp b/clientgui/ViewTransfers.cpp index aa7009c9c9..f35ccb4259 100644 --- a/clientgui/ViewTransfers.cpp +++ b/clientgui/ViewTransfers.cpp @@ -68,11 +68,7 @@ IMPLEMENT_DYNAMIC_CLASS(CViewTransfers, CBOINCBaseView) BEGIN_EVENT_TABLE (CViewTransfers, CBOINCBaseView) EVT_BUTTON(ID_TASK_TRANSFERS_RETRYNOW, CViewTransfers::OnTransfersRetryNow) EVT_BUTTON(ID_TASK_TRANSFERS_ABORT, CViewTransfers::OnTransfersAbort) -// We currently handle EVT_LIST_CACHE_HINT instead of EVT_LIST_ITEM_SELECTED -// or EVT_LIST_ITEM_DESELECTED. See CBOINCBaseView::OnCacheHint() for info. -// EVT_LIST_ITEM_SELECTED(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnListSelected) -// EVT_LIST_ITEM_DESELECTED(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnListDeselected) - EVT_LIST_CACHE_HINT(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnCacheHint) + EVT_CHECK_SELECTION_CHANGED(CViewTransfers::OnCheckSelectionChanged) EVT_LIST_COL_CLICK(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnColClick) EVT_LIST_COL_END_DRAG(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnColResize) END_EVENT_TABLE () diff --git a/clientgui/ViewWork.cpp b/clientgui/ViewWork.cpp index 4eb4388a16..11caa3f921 100644 --- a/clientgui/ViewWork.cpp +++ b/clientgui/ViewWork.cpp @@ -89,11 +89,7 @@ BEGIN_EVENT_TABLE (CViewWork, CBOINCBaseView) EVT_BUTTON(ID_TASK_SHOW_PROPERTIES, CViewWork::OnShowItemProperties) EVT_BUTTON(ID_TASK_ACTIVE_ONLY, CViewWork::OnActiveTasksOnly) EVT_CUSTOM_RANGE(wxEVT_COMMAND_BUTTON_CLICKED, ID_TASK_PROJECT_WEB_PROJDEF_MIN, ID_TASK_PROJECT_WEB_PROJDEF_MAX, CViewWork::OnProjectWebsiteClicked) -// We currently handle EVT_LIST_CACHE_HINT instead of EVT_LIST_ITEM_SELECTED -// or EVT_LIST_ITEM_DESELECTED. See CBOINCBaseView::OnCacheHint() for info. -// EVT_LIST_ITEM_SELECTED(ID_LIST_WORKVIEW, CViewWork::OnListSelected) -// EVT_LIST_ITEM_DESELECTED(ID_LIST_WORKVIEW, CViewWork::OnListDeselected) - EVT_LIST_CACHE_HINT(ID_LIST_WORKVIEW, CViewWork::OnCacheHint) + EVT_CHECK_SELECTION_CHANGED(CViewWork::OnCheckSelectionChanged) EVT_LIST_COL_CLICK(ID_LIST_WORKVIEW, CViewWork::OnColClick) EVT_LIST_COL_END_DRAG(ID_LIST_WORKVIEW, CViewWork::OnColResize) END_EVENT_TABLE ()