From dbfa4734885006b42c811f1a65b24e5682526f42 Mon Sep 17 00:00:00 2001 From: "scott%scott-macgregor.org" Date: Fri, 9 Jan 2004 07:27:21 +0000 Subject: [PATCH] Bug #75866 --> Mark a message as read in JS instead of once for each mail protocol to simplify code. Hookup the JS function to a timer to allow users to only mark messages as read after they have been viewed in the preview pane for a configurable number of seconds. sr=bienvenu --- .../base/resources/content/commandglue.js | 3 ++ .../content/mail3PaneWindowCommands.js | 12 +++++++ mailnews/base/resources/content/mailWindow.js | 1 + .../resources/content/mailWindowOverlay.js | 31 +++++++++++++++- .../base/resources/content/messageWindow.js | 1 + mailnews/base/resources/content/threadPane.js | 1 + mailnews/imap/src/nsImapMailFolder.cpp | 11 ------ mailnews/imap/src/nsImapService.cpp | 8 ++++- mailnews/imap/src/nsImapUrl.cpp | 35 ------------------- mailnews/local/src/nsMailboxProtocol.cpp | 26 -------------- mailnews/news/src/nsNNTPProtocol.cpp | 24 ------------- mailnews/news/src/nsNNTPProtocol.h | 7 ++-- 12 files changed, 58 insertions(+), 102 deletions(-) diff --git a/mailnews/base/resources/content/commandglue.js b/mailnews/base/resources/content/commandglue.js index 7619e2809a1..bbe1e9ff98f 100644 --- a/mailnews/base/resources/content/commandglue.js +++ b/mailnews/base/resources/content/commandglue.js @@ -298,6 +298,9 @@ function RerootFolder(uri, newFolder, viewType, viewFlags, sortType, sortOrder) gDBView = null; } + // cancel the pending mark as read timer + ClearPendingReadTimer(); + // if this is the drafts, sent, or send later folder, // we show "Recipient" instead of "Author" SetSentFolderColumns(IsSpecialFolder(newFolder, MSG_FOLDER_FLAG_SENTMAIL | MSG_FOLDER_FLAG_DRAFTS | MSG_FOLDER_FLAG_QUEUE)); diff --git a/mailnews/base/resources/content/mail3PaneWindowCommands.js b/mailnews/base/resources/content/mail3PaneWindowCommands.js index 4b17f509af9..9ffa97a0759 100644 --- a/mailnews/base/resources/content/mail3PaneWindowCommands.js +++ b/mailnews/base/resources/content/mail3PaneWindowCommands.js @@ -469,10 +469,22 @@ var DefaultController = break;// This does nothing because the createfilter is invoked from the popupnode oncommand. case "button_delete": case "cmd_delete": + // if the user deletes a message before its mark as read timer goes off, we should mark it as read + // this ensures that we clear the biff indicator from the system tray when the user deletes the new message + if (gMarkViewedMessageAsReadTimer) + { + MarkCurrentMessageAsRead(); + ClearPendingReadTimer(); + } SetNextMessageAfterDelete(); gDBView.doCommand(nsMsgViewCommandType.deleteMsg); break; case "cmd_shiftDelete": + if (gMarkViewedMessageAsReadTimer) + { + MarkCurrentMessageAsRead(); + ClearPendingReadTimer(); + } SetNextMessageAfterDelete(); gDBView.doCommand(nsMsgViewCommandType.deleteNoTrash); break; diff --git a/mailnews/base/resources/content/mailWindow.js b/mailnews/base/resources/content/mailWindow.js index 51fedc705d1..f2fad4b6acc 100644 --- a/mailnews/base/resources/content/mailWindow.js +++ b/mailnews/base/resources/content/mailWindow.js @@ -75,6 +75,7 @@ var gLastKeywords = ""; function OnMailWindowUnload() { RemoveMailOfflineObserver(); + ClearPendingReadTimer(); var searchSession = GetSearchSession(); if (searchSession) diff --git a/mailnews/base/resources/content/mailWindowOverlay.js b/mailnews/base/resources/content/mailWindowOverlay.js index 89e36a19b62..8f2f94158ed 100644 --- a/mailnews/base/resources/content/mailWindowOverlay.js +++ b/mailnews/base/resources/content/mailWindowOverlay.js @@ -40,6 +40,7 @@ var gWindowManagerInterface; var gPrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch); var gPrintSettings = null; var gWindowReuse = 0; +var gMarkViewedMessageAsReadTimer = null; // if the user has configured the app to mark a message as read if it is viewed for more than n seconds var gTimelineService = null; var gTimelineEnabled = ("@mozilla.org;timeline-service;1" in Components.classes); @@ -2031,6 +2032,20 @@ function SetUpJunkBar(aMsgHdr) goUpdateCommand('button_junk'); } +function MarkCurrentMessageAsRead() +{ + gDBView.doCommand(nsMsgViewCommandType.markMessagesRead); +} + +function ClearPendingReadTimer() +{ + if (gMarkViewedMessageAsReadTimer) + { + clearTimeout(gMarkViewedMessageAsReadTimer); + gMarkViewedMessageAsReadTimer = null; + } +} + function OnMsgLoaded(aUrl) { if (!aUrl) @@ -2038,6 +2053,8 @@ function OnMsgLoaded(aUrl) var folder = aUrl.folder; var msgURI = GetLoadedMessage(); + var msgHdr = null; + if (!folder || !msgURI) return; @@ -2045,10 +2062,22 @@ function OnMsgLoaded(aUrl) SetUpJunkBar(null); else { - var msgHdr = messenger.messageServiceFromURI(msgURI).messageURIToMsgHdr(msgURI); + msgHdr = messenger.messageServiceFromURI(msgURI).messageURIToMsgHdr(msgURI); SetUpJunkBar(msgHdr); } + // we just finished loading a message. set a timer to actually mark the message as read after n seconds + // where n can be configured by the user. + var markReadOnADelay = gPrefs.getBoolPref("mailnews.mark_message_read.delay"); + if (msgHdr && !msgHdr.isRead) + { + var wintype = document.firstChild.getAttribute('windowtype'); + if (markReadOnADelay && wintype == "mail:3pane") // only use the timer if viewing using the 3-pane preview pane and the user has set the pref + gMarkViewedMessageAsReadTimer = setTimeout(MarkCurrentMessageAsRead, gPrefs.getIntPref("mailnews.mark_message_read.delay.interval") * 1000); + else + MarkCurrentMessageAsRead(); + } + // See if MDN was requested but has not been sent. HandleMDNResponse(aUrl); diff --git a/mailnews/base/resources/content/messageWindow.js b/mailnews/base/resources/content/messageWindow.js index ef25a1dc11c..b658b0847fa 100644 --- a/mailnews/base/resources/content/messageWindow.js +++ b/mailnews/base/resources/content/messageWindow.js @@ -173,6 +173,7 @@ nsMsgDBViewCommandUpdater.prototype = displayMessageChanged : function(aFolder, aSubject, aKeywords) { setTitleFromFolder(aFolder, aSubject); + ClearPendingReadTimer(); // we are loading / selecting a new message so kill the mark as read timer for the currently viewed message gCurrentMessageUri = gDBView.URIForFirstSelectedMessage; UpdateStandAloneMessageCounts(); SetKeywords(aKeywords); diff --git a/mailnews/base/resources/content/threadPane.js b/mailnews/base/resources/content/threadPane.js index c86269084f7..44cc05e9346 100644 --- a/mailnews/base/resources/content/threadPane.js +++ b/mailnews/base/resources/content/threadPane.js @@ -85,6 +85,7 @@ nsMsgDBViewCommandUpdater.prototype = displayMessageChanged : function(aFolder, aSubject, aKeywords) { setTitleFromFolder(aFolder, aSubject); + ClearPendingReadTimer(); // we are loading / selecting a new message so kill the mark as read timer for the currently viewed message gHaveLoadedMessage = true; SetKeywords(aKeywords); goUpdateCommand("button_junk"); diff --git a/mailnews/imap/src/nsImapMailFolder.cpp b/mailnews/imap/src/nsImapMailFolder.cpp index f91370ca778..38ef7bb2513 100644 --- a/mailnews/imap/src/nsImapMailFolder.cpp +++ b/mailnews/imap/src/nsImapMailFolder.cpp @@ -3786,17 +3786,6 @@ nsImapMailFolder::NormalEndMsgWriteStream(nsMsgKey uidOfMessage, nsCOMPtr msgHdr; m_curMsgUid = uidOfMessage; res = GetMessageHeader(m_curMsgUid, getter_AddRefs(msgHdr)); - - if (msgHdr && markRead) - { - PRBool isRead; - msgHdr->GetIsRead(&isRead); - if (!isRead) - { - msgHdr->MarkRead(PR_TRUE); - commit = PR_TRUE; - } - } if (commit && mDatabase) mDatabase->Commit(nsMsgDBCommitType::kLargeCommit); diff --git a/mailnews/imap/src/nsImapService.cpp b/mailnews/imap/src/nsImapService.cpp index f389ca5e991..6d6640721c6 100644 --- a/mailnews/imap/src/nsImapService.cpp +++ b/mailnews/imap/src/nsImapService.cpp @@ -555,7 +555,13 @@ NS_IMETHODIMP nsImapService::DisplayMessage(const char* aMessageURI, if (hasMsgOffline) msgurl->SetMsgIsInLocalCache(PR_TRUE); - rv = FetchMessage(imapUrl, nsIImapUrl::nsImapMsgFetch, folder, imapMessageSink, + nsCOMPtr prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); + PRBool forcePeek = PR_FALSE; // should the message fetch force a peak or a traditional fetch? + + if (NS_SUCCEEDED(rv) && prefBranch) + prefBranch->GetBoolPref("mailnews.mark_message_read.delay", &forcePeek); + + rv = FetchMessage(imapUrl, forcePeek ? nsIImapUrl::nsImapMsgFetchPeek : nsIImapUrl::nsImapMsgFetch, folder, imapMessageSink, aMsgWindow, aDisplayConsumer, msgKey, PR_FALSE, (mPrintingOperation) ? "print" : nsnull, aURL); } } diff --git a/mailnews/imap/src/nsImapUrl.cpp b/mailnews/imap/src/nsImapUrl.cpp index 7168ba0ea1e..13d0f121cca 100644 --- a/mailnews/imap/src/nsImapUrl.cpp +++ b/mailnews/imap/src/nsImapUrl.cpp @@ -1347,41 +1347,6 @@ NS_IMETHODIMP nsImapUrl::SetMsgLoadingFromCache(PRBool loadingFromCache) { nsresult rv = NS_OK; m_msgLoadingFromCache = loadingFromCache; - if (loadingFromCache) - { - nsCOMPtr folder; - nsMsgKey key; - - nsCAutoString folderURI; - rv = nsParseImapMessageURI(mURI.get(), folderURI, &key, nsnull); - NS_ENSURE_SUCCESS(rv, rv); - - if (m_imapAction != nsImapMsgFetch) // only do this on msg fetch, i.e., if user is reading msg. - return rv; - rv = GetMsgFolder(getter_AddRefs(folder)); - - nsCOMPtr database; - if (folder && NS_SUCCEEDED(folder->GetMsgDatabase(nsnull, getter_AddRefs(database))) && database) - { - PRBool msgRead = PR_TRUE; - database->IsRead(key, &msgRead); - if (!msgRead) - { - nsCOMPtr messages; - rv = NS_NewISupportsArray(getter_AddRefs(messages)); - if (NS_FAILED(rv)) - return rv; - nsCOMPtr message; - GetMsgDBHdrFromURI(mURI.get(), getter_AddRefs(message)); - nsCOMPtr msgSupport(do_QueryInterface(message, &rv)); - if (msgSupport) - { - messages->AppendElement(msgSupport); - folder->MarkMessagesRead(messages, PR_TRUE); - } - } - } - } return rv; } diff --git a/mailnews/local/src/nsMailboxProtocol.cpp b/mailnews/local/src/nsMailboxProtocol.cpp index 232f30001ca..a3353875d30 100644 --- a/mailnews/local/src/nsMailboxProtocol.cpp +++ b/mailnews/local/src/nsMailboxProtocol.cpp @@ -404,32 +404,6 @@ PRInt32 nsMailboxProtocol::DoneReadingMessage() if (m_mailboxAction == nsIMailboxUrl::ActionSaveMessageToDisk && m_tempMessageFile) rv = m_tempMessageFile->CloseStream(); - nsCOMPtr msgUrl = do_QueryInterface(m_runningUrl, &rv); - NS_ENSURE_SUCCESS(rv,rv); - - nsCAutoString queryStr; - rv = msgUrl->GetQuery(queryStr); - NS_ENSURE_SUCCESS(rv,rv); - - // check if this is a filter plugin requesting the message. - // in that case, don't mark it as read, - // since the user didn't actually read it. - // the spec for msgUrl is of the form: - // mailbox:////Inbox?number=3287862&header=filter" - if ((queryStr.Find("header=filter") == kNotFound) && m_mailboxAction == nsIMailboxUrl::ActionFetchMessage) - { - // now mark the message as read - nsCOMPtr msgHdr; - if (m_runningUrl) - rv = m_runningUrl->GetMessageHeader(getter_AddRefs(msgHdr)); - NS_ASSERTION(msgHdr, "no msg hdr!"); - if (!msgHdr) return NS_ERROR_UNEXPECTED; - PRBool isRead; - msgHdr->GetIsRead(&isRead); - if (NS_SUCCEEDED(rv) && !isRead) - msgHdr->MarkRead(PR_TRUE); - } - return rv; } diff --git a/mailnews/news/src/nsNNTPProtocol.cpp b/mailnews/news/src/nsNNTPProtocol.cpp index 33eff12be7e..9519f218337 100644 --- a/mailnews/news/src/nsNNTPProtocol.cpp +++ b/mailnews/news/src/nsNNTPProtocol.cpp @@ -848,7 +848,6 @@ nsresult nsNNTPProtocol::ReadFromMemCache(nsICacheEntryDescriptor *entry) rv = pump->AsyncRead(cacheListener, m_channelContext); NS_RELEASE(cacheListener); - MarkCurrentMsgRead(); if (NS_SUCCEEDED(rv)) // ONLY if we succeeded in actually starting the read should we return { // we're not calling nsMsgProtocol::AsyncRead(), which calls nsNNTPProtocol::LoadUrl, so we need to take care of some stuff it does. @@ -913,7 +912,6 @@ PRBool nsNNTPProtocol::ReadFromLocalCache() rv = pump->AsyncRead(cacheListener, m_channelContext); NS_RELEASE(cacheListener); - MarkCurrentMsgRead(); if (NS_SUCCEEDED(rv)) // ONLY if we succeeded in actually starting the read should we return { @@ -2313,7 +2311,6 @@ PRInt32 nsNNTPProtocol::SendFirstNNTPCommandResponse() FinishMemCacheEntry(PR_FALSE); // cleanup mem cache entry if (NS_SUCCEEDED(rv) && group_name && !savingArticleOffline) { - MarkCurrentMsgRead(); nsXPIDLString titleStr; rv = GetNewsStringByName("htmlNewsErrorTitle", getter_Copies(titleStr)); NS_ENSURE_SUCCESS(rv,rv); @@ -2569,7 +2566,6 @@ PRInt32 nsNNTPProtocol::DisplayArticle(nsIInputStream * inputStream, PRUint32 le if (line[0] == '.' && line[1] == 0) { m_nextState = NEWS_DONE; - MarkCurrentMsgRead(); ClearFlag(NNTP_PAUSE_FOR_READ); @@ -2598,26 +2594,6 @@ PRInt32 nsNNTPProtocol::DisplayArticle(nsIInputStream * inputStream, PRUint32 le return 0; } -nsresult nsNNTPProtocol::MarkCurrentMsgRead() -{ - nsCOMPtr msgHdr; - nsresult rv = NS_OK; - - // if this is a message id url, (news://host/message-id) then don't go try to mark it read - if (m_runningURL && !m_messageID && (m_key != nsMsgKey_None)) { - rv = m_runningURL->GetMessageHeader(getter_AddRefs(msgHdr)); - - if (NS_SUCCEEDED(rv) && msgHdr) - { - PRBool isRead; - msgHdr->GetIsRead(&isRead); - if (!isRead) - msgHdr->MarkRead(PR_TRUE); - } - } - return rv; -} - PRInt32 nsNNTPProtocol::ReadArticle(nsIInputStream * inputStream, PRUint32 length) { PRUint32 status = 0; diff --git a/mailnews/news/src/nsNNTPProtocol.h b/mailnews/news/src/nsNNTPProtocol.h index 9304ef1051a..032b7b8e2dc 100644 --- a/mailnews/news/src/nsNNTPProtocol.h +++ b/mailnews/news/src/nsNNTPProtocol.h @@ -183,9 +183,9 @@ public: NS_IMETHOD Cancel(nsresult status); // handle stop button NS_IMETHOD GetContentType(nsACString &aContentType); - NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt); - NS_IMETHOD GetOriginalURI(nsIURI* *aURI); - NS_IMETHOD SetOriginalURI(nsIURI* aURI); + NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt); + NS_IMETHOD GetOriginalURI(nsIURI* *aURI); + NS_IMETHOD SetOriginalURI(nsIURI* aURI); nsresult LoadUrl(nsIURI * aURL, nsISupports * aConsumer); @@ -410,7 +410,6 @@ private: void SetProgressBarPercent(PRUint32 aProgress, PRUint32 aProgressMax); nsresult SetProgressStatus(const PRUnichar *aMessage); nsresult SetCheckingForNewNewsStatus(PRInt32 current, PRInt32 total); - nsresult MarkCurrentMsgRead(); // marks the message corresponding to the currently running url read. nsresult InitializeNewsFolderFromUri(const char *uri); void TimerCallback(); nsCOMPtr mInputStream;