mirror of https://github.com/BOINC/boinc.git
MGR: Show # unread notices in Notices tab title, improve notification for unread notices, link to reminder frequency slider
svn path=/trunk/boinc/; revision=21042
This commit is contained in:
parent
b0cb81159f
commit
f811b9bccd
|
@ -2337,3 +2337,21 @@ David 31 Mar 2010
|
|||
client_types.cpp
|
||||
cs_notices.cpp
|
||||
*.h
|
||||
|
||||
Charlie 1 Apr 2010
|
||||
- MGR: Show number of unread notices in title of Notices tab (we consider
|
||||
all notices as having been read when Notices tab is showing and BOINC
|
||||
Manager is front process). Notify (balloon on Window or Linux, bounce
|
||||
Dock icon on Mac for 15 seconds) repeatedly when there are unread
|
||||
messages, with notification frequency set by Options dialog reminder
|
||||
interval slider.
|
||||
Note: Should there be 2 separate reminder frequency sliders for network
|
||||
connection and Unread notices?
|
||||
|
||||
clientgui/
|
||||
AdvancedFrame.cpp, .h
|
||||
BOINCBaseFrame.cpp, .h
|
||||
BOINCTaskBar.cpp, .h
|
||||
DlgOptions.cpp
|
||||
MainDocument.cpp, .h
|
||||
MacSysMenu.cpp
|
||||
|
|
|
@ -736,6 +736,8 @@ bool CAdvancedFrame::RepopulateNotebook() {
|
|||
CreateNotebookPage(new CViewStatistics(m_pNotebook));
|
||||
CreateNotebookPage(new CViewResources(m_pNotebook));
|
||||
|
||||
UpdateNoticesTabText();
|
||||
|
||||
wxLogTrace(wxT("Function Start/End"), wxT("CAdvancedFrame::RepopulateNotebook - Function End"));
|
||||
return true;
|
||||
}
|
||||
|
@ -767,6 +769,32 @@ bool CAdvancedFrame::CreateNotebookPage( CBOINCBaseView* pwndNewNotebookPage) {
|
|||
}
|
||||
|
||||
|
||||
void CAdvancedFrame::UpdateNoticesTabText() {
|
||||
wxWindow* pwndNotebookPage = NULL;
|
||||
CBOINCBaseView* pView = NULL;
|
||||
wxString strTabText;
|
||||
CMainDocument* pDoc = wxGetApp().GetDocument();
|
||||
|
||||
wxASSERT(pDoc);
|
||||
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
|
||||
|
||||
wxASSERT(m_pNotebook);
|
||||
pwndNotebookPage = m_pNotebook->GetPage(ID_ADVNOTICESVIEW - ID_ADVVIEWBASE);
|
||||
wxASSERT(pwndNotebookPage);
|
||||
pView = wxDynamicCast(pwndNotebookPage, CBOINCBaseView);
|
||||
wxASSERT(pView);
|
||||
|
||||
int count = pDoc->GetUnreadNoticeCount();
|
||||
if (count) {
|
||||
strTabText.Printf(wxT("%s (%d)"), pView->GetViewDisplayName().c_str(), count);
|
||||
} else {
|
||||
strTabText = pView->GetViewDisplayName();
|
||||
}
|
||||
|
||||
m_pNotebook->SetPageText(ID_ADVNOTICESVIEW - ID_ADVVIEWBASE, strTabText);
|
||||
}
|
||||
|
||||
|
||||
bool CAdvancedFrame::CreateStatusbar() {
|
||||
wxLogTrace(wxT("Function Start/End"), wxT("CAdvancedFrame::CreateStatusbar - Function Begin"));
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ private:
|
|||
bool RepopulateNotebook();
|
||||
bool CreateNotebookPage( CBOINCBaseView* pwndNewNotebookPage );
|
||||
bool DeleteNotebook();
|
||||
|
||||
void UpdateNoticesTabText();
|
||||
bool CreateStatusbar();
|
||||
bool DeleteStatusbar();
|
||||
|
||||
|
|
|
@ -370,6 +370,10 @@ int CBOINCBaseFrame::GetCurrentViewPage() {
|
|||
}
|
||||
|
||||
|
||||
void CBOINCBaseFrame::UpdateNoticesTabText() {
|
||||
}
|
||||
|
||||
|
||||
void CBOINCBaseFrame::FireInitialize() {
|
||||
CFrameEvent event(wxEVT_FRAME_INITIALIZED, this);
|
||||
AddPendingEvent(event);
|
||||
|
|
|
@ -63,7 +63,7 @@ public:
|
|||
virtual void OnExit( wxCommandEvent& event );
|
||||
|
||||
int GetCurrentViewPage();
|
||||
|
||||
virtual void UpdateNoticesTabText();
|
||||
int GetReminderFrequency() { return m_iReminderFrequency; }
|
||||
wxString GetDialupConnectionName() { return m_strNetworkDialupConnectionName; }
|
||||
|
||||
|
@ -82,7 +82,7 @@ public:
|
|||
virtual void StopTimers();
|
||||
virtual void UpdateRefreshTimerInterval();
|
||||
|
||||
inline void UpdateStatusText( const wxChar* ){}
|
||||
inline void UpdateStatusText( const wxChar* ){}
|
||||
|
||||
void ShowAlert(
|
||||
const wxString title,
|
||||
|
@ -117,6 +117,7 @@ protected:
|
|||
|
||||
virtual int _GetCurrentViewPage();
|
||||
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
|
|
|
@ -41,10 +41,11 @@
|
|||
#include "res/macbadgemask.xpm"
|
||||
#endif
|
||||
|
||||
// How long to bounce Dock icon on Mac
|
||||
#define MAX_NOTIFICATION_DURATION 15
|
||||
|
||||
DEFINE_EVENT_TYPE(wxEVT_TASKBAR_RELOADSKIN)
|
||||
DEFINE_EVENT_TYPE(wxEVT_TASKBAR_REFRESH)
|
||||
DEFINE_EVENT_TYPE(wxEVT_TASKBAR_NOTIFICATION_ALERT)
|
||||
|
||||
BEGIN_EVENT_TABLE(CTaskBarIcon, wxTaskBarIconEx)
|
||||
|
||||
|
@ -52,7 +53,6 @@ BEGIN_EVENT_TABLE(CTaskBarIcon, wxTaskBarIconEx)
|
|||
EVT_CLOSE(CTaskBarIcon::OnClose)
|
||||
EVT_TASKBAR_REFRESH(CTaskBarIcon::OnRefresh)
|
||||
EVT_TASKBAR_RELOADSKIN(CTaskBarIcon::OnReloadSkin)
|
||||
EVT_TASKBAR_NOTIFICATION_ALERT(CTaskBarIcon::OnNotificationAlert)
|
||||
EVT_TASKBAR_LEFT_DCLICK(CTaskBarIcon::OnLButtonDClick)
|
||||
#ifndef __WXMAC__
|
||||
EVT_TASKBAR_RIGHT_DOWN(CTaskBarIcon::OnRButtonDown)
|
||||
|
@ -80,7 +80,7 @@ END_EVENT_TABLE()
|
|||
|
||||
|
||||
CTaskBarIcon::CTaskBarIcon(wxString title, wxIcon* icon, wxIcon* iconDisconnected, wxIcon* iconSnooze) :
|
||||
#if defined(__WXMAC__)
|
||||
#ifdef __WXMAC__
|
||||
wxTaskBarIcon(DOCK)
|
||||
#else
|
||||
wxTaskBarIconEx(wxT("BOINCManagerSystray"), 1)
|
||||
|
@ -95,7 +95,9 @@ CTaskBarIcon::CTaskBarIcon(wxString title, wxIcon* icon, wxIcon* iconDisconnecte
|
|||
m_bMouseButtonPressed = false;
|
||||
|
||||
m_dtLastNotificationAlertExecuted = wxDateTime((time_t)0);
|
||||
m_iLastNotificationCount = 0;
|
||||
#ifdef __WXMAC__
|
||||
m_pNotificationRequest = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -318,30 +320,6 @@ void CTaskBarIcon::OnReloadSkin(CTaskbarEvent& WXUNUSED(event)) {
|
|||
}
|
||||
|
||||
|
||||
void CTaskBarIcon::OnNotificationAlert(CTaskbarEvent& WXUNUSED(event)) {
|
||||
CSkinAdvanced* pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
|
||||
wxString strTitle;
|
||||
|
||||
strTitle.Printf(
|
||||
_("%s Notices"),
|
||||
pSkinAdvanced->GetApplicationName().c_str()
|
||||
);
|
||||
|
||||
// Do not use SafeMessageBox here because we want to continue
|
||||
// doing periodic RPCs to get messages, get notices, etc.
|
||||
wxMessageDialog* pDlg = new wxMessageDialog(
|
||||
NULL,
|
||||
_("One or more notices are now available for viewing."),
|
||||
strTitle,
|
||||
wxOK
|
||||
);
|
||||
pDlg->ShowModal();
|
||||
if (pDlg) {
|
||||
pDlg->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CTaskBarIcon::FireReloadSkin() {
|
||||
CTaskbarEvent event(wxEVT_TASKBAR_RELOADSKIN, this);
|
||||
AddPendingEvent(event);
|
||||
|
@ -437,6 +415,27 @@ bool CTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& ) {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
// wxTopLevel::RequestUserAttention() doesn't have an API to cancel
|
||||
// after a timeout, so we must call Notification Manager directly on Mac
|
||||
void CTaskBarIcon::MacRequestUserAttention()
|
||||
{
|
||||
m_pNotificationRequest = (NMRecPtr) NewPtrClear( sizeof( NMRec) ) ;
|
||||
m_pNotificationRequest->qType = nmType ;
|
||||
m_pNotificationRequest->nmMark = 1;
|
||||
|
||||
NMInstall(m_pNotificationRequest);
|
||||
}
|
||||
|
||||
void CTaskBarIcon::MacCancelUserAttentionRequest()
|
||||
{
|
||||
if (m_pNotificationRequest) {
|
||||
NMRemove(m_pNotificationRequest);
|
||||
DisposePtr((Ptr)m_pNotificationRequest);
|
||||
m_pNotificationRequest = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ! __WXMAC__
|
||||
|
||||
|
||||
|
@ -703,7 +702,6 @@ void CTaskBarIcon::UpdateNoticeStatus() {
|
|||
CBOINCBaseFrame* pFrame = wxGetApp().GetFrame();
|
||||
CSkinAdvanced* pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
|
||||
wxString strTitle;
|
||||
int iNoticeCount = 0;
|
||||
|
||||
|
||||
wxASSERT(pDoc);
|
||||
|
@ -713,15 +711,18 @@ void CTaskBarIcon::UpdateNoticeStatus() {
|
|||
wxASSERT(wxDynamicCast(pFrame, CBOINCBaseFrame));
|
||||
wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
|
||||
|
||||
|
||||
if (!pFrame) return;
|
||||
|
||||
// Repeat notification for unread notices at user-selected reminder frequency
|
||||
wxTimeSpan tsLastNotificationDisplayed = wxDateTime::Now() - m_dtLastNotificationAlertExecuted;
|
||||
if (tsLastNotificationDisplayed.GetMinutes() >= 60) {
|
||||
if (
|
||||
(tsLastNotificationDisplayed.GetMinutes() >= pFrame->GetReminderFrequency())
|
||||
&& (pFrame->GetReminderFrequency() != 0)
|
||||
) {
|
||||
|
||||
iNoticeCount = pDoc->GetNoticeCount();
|
||||
if (iNoticeCount > m_iLastNotificationCount) {
|
||||
if (pDoc->GetUnreadNoticeCount()) {
|
||||
|
||||
// Update cached info
|
||||
m_iLastNotificationCount = iNoticeCount;
|
||||
m_dtLastNotificationAlertExecuted = wxDateTime::Now();
|
||||
|
||||
if (IsBalloonsSupported()) {
|
||||
|
@ -738,25 +739,28 @@ void CTaskBarIcon::UpdateNoticeStatus() {
|
|||
);
|
||||
} else {
|
||||
// For platforms that do not support balloons
|
||||
if (pFrame) {
|
||||
// If Manager is hidden, request user attention.
|
||||
if (! (pFrame->IsShown())) {
|
||||
pFrame->RequestUserAttention();
|
||||
}
|
||||
// If Manager is open to a tab other than Notices, display an alert.
|
||||
// If Manager is now hidden, alert will appear when Manager is shown.
|
||||
int currentTabView = pFrame->GetCurrentViewPage();
|
||||
if (! (currentTabView & VW_NOTIF)) {
|
||||
// Don't run the alert from within the taskbar Refresh event to
|
||||
// allow updates to continue behind the notification alert
|
||||
CTaskbarEvent event(wxEVT_TASKBAR_NOTIFICATION_ALERT, this);
|
||||
AddPendingEvent(event);
|
||||
}
|
||||
// If Manager is hidden or in backgroound, request user attention.
|
||||
if (! (wxGetApp().IsActive())) {
|
||||
#ifdef __WXMAC__
|
||||
MacRequestUserAttention(); // Bounce BOINC Dock icon
|
||||
#else
|
||||
pFrame->RequestUserAttention();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef __WXMAC__
|
||||
} else {
|
||||
// Stop bouncing BOINC Dock icon after MAX_NOTIFICATION_DURATION seconds
|
||||
if (m_pNotificationRequest) {
|
||||
if (wxGetApp().IsActive() ||
|
||||
(tsLastNotificationDisplayed.GetSeconds() >= MAX_NOTIFICATION_DURATION)
|
||||
) {
|
||||
MacCancelUserAttentionRequest();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
wxLogTrace(wxT("Function Start/End"), wxT("CTaskBarIcon::UpdateNoticeStatus - Function End"));
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ public:
|
|||
void OnClose(wxCloseEvent& event);
|
||||
void OnRefresh(CTaskbarEvent& event);
|
||||
void OnReloadSkin(CTaskbarEvent& event);
|
||||
void OnNotificationAlert(CTaskbarEvent& event);
|
||||
|
||||
void OnNotificationClick(wxTaskBarIconExEvent& event);
|
||||
void OnShutdown(wxTaskBarIconExEvent& event);
|
||||
|
@ -64,6 +63,13 @@ public:
|
|||
void AdjustMenuItems(wxMenu* menu);
|
||||
|
||||
#ifdef __WXMAC__
|
||||
private:
|
||||
NMRecPtr m_pNotificationRequest;
|
||||
|
||||
void MacRequestUserAttention();
|
||||
void MacCancelUserAttentionRequest();
|
||||
|
||||
public:
|
||||
wxMenu *CreatePopupMenu();
|
||||
bool SetIcon(const wxIcon& icon, const wxString& message = wxEmptyString);
|
||||
|
||||
|
@ -104,7 +110,6 @@ private:
|
|||
bool m_bMouseButtonPressed;
|
||||
|
||||
wxDateTime m_dtLastNotificationAlertExecuted;
|
||||
int m_iLastNotificationCount;
|
||||
|
||||
void ResetTaskBar();
|
||||
void DisplayContextMenu();
|
||||
|
@ -140,12 +145,10 @@ public:
|
|||
BEGIN_DECLARE_EVENT_TYPES()
|
||||
DECLARE_EVENT_TYPE( wxEVT_TASKBAR_RELOADSKIN, 10100 )
|
||||
DECLARE_EVENT_TYPE( wxEVT_TASKBAR_REFRESH, 10101 )
|
||||
DECLARE_EVENT_TYPE( wxEVT_TASKBAR_NOTIFICATION_ALERT, 10102 )
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
#define EVT_TASKBAR_RELOADSKIN(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_TASKBAR_RELOADSKIN, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL),
|
||||
#define EVT_TASKBAR_REFRESH(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_TASKBAR_REFRESH, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL),
|
||||
#define EVT_TASKBAR_NOTIFICATION_ALERT(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_TASKBAR_NOTIFICATION_ALERT, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL),
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -165,7 +165,7 @@ void CDlgOptions::CreateControls()
|
|||
itemFlexGridSizer6->Add(m_LanguageSelectionCtrl, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5);
|
||||
|
||||
wxStaticText* itemStaticText9 = new wxStaticText;
|
||||
itemStaticText9->Create( itemPanel4, wxID_STATIC, _("Network reminder interval:\n(minutes)"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
|
||||
itemStaticText9->Create( itemPanel4, wxID_STATIC, _("Network or notices reminder interval:\n(minutes)"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
|
||||
itemFlexGridSizer6->Add(itemStaticText9, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL, 5);
|
||||
|
||||
m_ReminderFrequencyCtrl = new wxSlider;
|
||||
|
@ -177,7 +177,7 @@ void CDlgOptions::CreateControls()
|
|||
#endif
|
||||
wxSL_HORIZONTAL|wxSL_LABELS);
|
||||
if (ShowToolTips())
|
||||
m_ReminderFrequencyCtrl->SetToolTip(_("How often should the Manager remind you when a network connection is needed?"));
|
||||
m_ReminderFrequencyCtrl->SetToolTip(_("How often should the Manager remind you when you have new notices or when a network connection is needed?"));
|
||||
itemFlexGridSizer6->Add(m_ReminderFrequencyCtrl, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5);
|
||||
|
||||
#ifdef __WXMSW__
|
||||
|
|
|
@ -392,6 +392,8 @@ CMainDocument::CMainDocument() : rpc(this) {
|
|||
|
||||
m_iMessageSequenceNumber = 0;
|
||||
m_iNoticeSequenceNumber = 0;
|
||||
m_iLastReadNoticeSequenceNumber = 0;
|
||||
m_iNumberUnreadNotices = 0;
|
||||
|
||||
m_dtCachedStateTimestamp = wxDateTime((time_t)0);
|
||||
m_iGet_state_rpc_result = 0;
|
||||
|
@ -1873,6 +1875,21 @@ int CMainDocument::CachedNoticeUpdate() {
|
|||
if (notices.notices.size() != 0) {
|
||||
m_iNoticeSequenceNumber = notices.notices[0]->seqno;
|
||||
}
|
||||
|
||||
// Consider all notices as having been read if Notices tab is open
|
||||
CBOINCBaseFrame* pFrame = wxGetApp().GetFrame();
|
||||
if (!pFrame) goto done;
|
||||
wxASSERT(wxDynamicCast(pFrame, CBOINCBaseFrame));
|
||||
|
||||
int currentTabView = pFrame->GetCurrentViewPage();
|
||||
if ((currentTabView & VW_NOTIF) && wxGetApp().IsActive()) {
|
||||
m_iLastReadNoticeSequenceNumber = m_iNoticeSequenceNumber;
|
||||
}
|
||||
int unread = m_iNoticeSequenceNumber - m_iLastReadNoticeSequenceNumber;
|
||||
if (m_iNumberUnreadNotices != unread) {
|
||||
m_iNumberUnreadNotices = unread;
|
||||
pFrame->UpdateNoticesTabText();
|
||||
}
|
||||
}
|
||||
done:
|
||||
in_this_func = false;
|
||||
|
|
|
@ -291,6 +291,10 @@ public:
|
|||
private:
|
||||
wxDateTime m_dtNoticesTimeStamp;
|
||||
|
||||
int m_iNoticeSequenceNumber;
|
||||
int m_iLastReadNoticeSequenceNumber;
|
||||
int m_iNumberUnreadNotices;
|
||||
|
||||
public:
|
||||
NOTICES notices;
|
||||
NOTICES async_notices_buf;
|
||||
|
@ -300,11 +304,10 @@ public:
|
|||
int CachedNoticeUpdate();
|
||||
|
||||
int GetNoticeCount();
|
||||
int GetUnreadNoticeCount() { return m_iNumberUnreadNotices; };
|
||||
|
||||
int ResetNoticeState();
|
||||
|
||||
int m_iNoticeSequenceNumber;
|
||||
|
||||
|
||||
//
|
||||
// Messages Tab
|
||||
|
|
|
@ -37,8 +37,6 @@ pascal OSStatus SysMenuEventHandler( EventHandlerCallRef inHandlerCallRef,
|
|||
{ kEventClassApplication, kEventAppShown},
|
||||
{kEventClassMenu, kEventMenuOpening} };
|
||||
|
||||
static const wxIcon* currentIcon = NULL;
|
||||
|
||||
|
||||
#if wxCHECK_VERSION(2,8,0)
|
||||
|
||||
|
@ -215,8 +213,6 @@ void CMacSystemMenu::BuildMenu() {
|
|||
themenu->SetEventHandler(this);
|
||||
|
||||
SetUpSystemMenu((MenuRef)(themenu->GetHMenu()), imageRef);
|
||||
|
||||
currentIcon = NULL;
|
||||
}
|
||||
if(imageRef != NULL) CGImageRelease( imageRef );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue