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 ()