make the message view persist on a per folder basis. (#63853)

make it so you can view "threads with unread".  (#52927)
threaded and unread are no longer mutually exclusive.

later, I'll add "unread threaded" which is no the
same thing as "thread with unread".

fix the nsMsgMessageDataSource() to ask the view, thread or msg database for existance of messages, instead of getting an enumerator for all messages, and seeing if it is non empty.  more performance work on the way.

move enums from MailNewsTypes.h to MailNewsTypes2.idl, so that I can use the same ones from JS and C++.

sr=bienvenu
This commit is contained in:
sspitzer%netscape.com 2001-01-04 00:12:36 +00:00
parent 4e02ab8830
commit e2955b1ba8
31 changed files with 691 additions and 1108 deletions

View File

@ -55,19 +55,6 @@
{0x8a, 0x5d, 0x0, 0x60, 0xb0, 0xfc, 0x4, 0xd2} \
}
//
// nsMessageViewDataSource
//
#define NS_MESSAGEVIEWDATASOURCE_CONTRACTID \
NS_RDF_DATASOURCE_CONTRACTID_PREFIX "mail-messageview"
#define NS_MESSAGEVIEWDATASOURCE_CID \
{ /* 14495573-E945-11d2-8A52-0060B0FC04D2 */ \
0x14495573, 0xe945, 0x11d2, \
{0x8a, 0x52, 0x0, 0x60, 0xb0, 0xfc, 0x4, 0xd2}}
//
// nsMsgAccountManager
//

View File

@ -51,7 +51,6 @@
#include "nsMessengerMigrator.h"
#include "nsMsgIdentity.h"
#include "nsMsgIncomingServer.h"
#include "nsMessageViewDataSource.h"
#include "nsMsgFolderDataSource.h"
#include "nsMsgMessageDataSource.h"

View File

@ -32,11 +32,9 @@ interface nsIMsgWindow;
interface nsIMessageView : nsISupports
{
%{C++
enum { eShowAll =0, eShowRead =1, eShowUnread =2 , eShowWatched =3};
%}
attribute unsigned long viewType;
attribute boolean showThreads;
void GetMessages(in nsIRDFResource parentResource, in nsIMsgWindow msgWindow, out nsISimpleEnumerator messages);
boolean hasMessages(in nsIRDFResource parentResource, in nsIMsgWindow msgWindow);
};

View File

@ -68,10 +68,12 @@ const nsMsgBiffState nsMsgBiffState_Unknown = 2; // We dunno whether there is ne
void ReplaceElement(in nsISupports element, in nsISupports newElement);
nsISimpleEnumerator getMessages(in nsIMsgWindow aMsgWindow);
nsISimpleEnumerator getThreads(in nsIMsgWindow aMsgWindow);
nsISimpleEnumerator getThreadsOfType(in nsIMsgWindow aMsgWindow, in unsigned long viewType);
boolean hasThreads(in nsIMsgWindow aMsgWindow);
boolean hasMessagesOfType(in nsIMsgWindow aMsgWindow, in unsigned long viewType);
void startFolderLoading();
void endFolderLoading();
void startFolderLoading();
void endFolderLoading();
/* get new headers for db */
void updateFolder(in nsIMsgWindow aWindow);

View File

@ -48,5 +48,7 @@ interface nsIMsgThread : nsISupports {
void MarkChildRead(in boolean bRead);
nsISimpleEnumerator EnumerateMessages(in nsMsgKey parent);
nsISimpleEnumerator EnumerateUnreadMessages(in nsMsgKey parent);
boolean hasMessagesOfType(in nsMsgKey parent, in unsigned long viewType);
};

View File

@ -98,7 +98,7 @@ function ChangeFolderByDOMNode(folderNode)
dump(uri + "\n");
var isThreaded = folderNode.getAttribute('threaded');
if ((isThreaded == "") && isNewsURI(uri)) {
isThreaded = "true";
}
@ -109,8 +109,10 @@ function ChangeFolderByDOMNode(folderNode)
var sortDirection = folderNode.getAttribute('sortDirection');
var viewType = folderNode.getAttribute('viewType');
if (uri)
ChangeFolderByURI(uri, isThreaded == "true", sortResource, sortDirection);
ChangeFolderByURI(uri, isThreaded == "true", sortResource, sortDirection, viewType);
}
function setTitleFromFolder(msgfolder, subject)
@ -159,7 +161,7 @@ function setTitleFromFolder(msgfolder, subject)
window.title = title;
}
function ChangeFolderByURI(uri, isThreaded, sortID, sortDirection)
function ChangeFolderByURI(uri, isThreaded, sortID, sortDirection, viewType)
{
dump('In ChangeFolderByURI uri = ' + uri + "\n");
if (uri == gCurrentLoadingFolderURI)
@ -195,6 +197,7 @@ function ChangeFolderByURI(uri, isThreaded, sortID, sortDirection)
gCurrentLoadingFolderIsThreaded = isThreaded;
gCurrentLoadingFolderSortID = sortID;
gCurrentLoadingFolderSortDirection = sortDirection;
gCurrentLoadingFolderViewType = viewType;
msgfolder.startFolderLoading();
msgfolder.updateFolder(msgWindow);
}
@ -209,7 +212,8 @@ function ChangeFolderByURI(uri, isThreaded, sortID, sortDirection)
gCurrentFolderToReroot = "";
gCurrentLoadingFolderIsThreaded = false;
gCurrentLoadingFolderSortID = "";
RerootFolder(uri, msgfolder, isThreaded, sortID, sortDirection);
gCurrentLoadingFolderViewType = "";
RerootFolder(uri, msgfolder, isThreaded, sortID, sortDirection, viewType);
//Need to do this after rerooting folder. Otherwise possibility of receiving folder loaded
//notification before folder has actually changed.
@ -227,7 +231,7 @@ function isNewsURI(uri)
}
}
function RerootFolder(uri, newFolder, isThreaded, sortID, sortDirection)
function RerootFolder(uri, newFolder, isThreaded, sortID, sortDirection, viewType)
{
dump('In reroot folder\n');
@ -242,7 +246,9 @@ function RerootFolder(uri, newFolder, isThreaded, sortID, sortDirection)
//Set threaded state
ShowThreads(isThreaded);
//Set the view type
SetViewType(viewType);
//Clear the new messages of the old folder
var oldFolderURI = folder.getAttribute("ref");
@ -854,9 +860,22 @@ function IsSpecialFolder(msgFolder, specialFolderNames)
}
function SetViewType(viewType)
{
//dump("in SetViewType with " + viewType + "\n");
if (!viewType || (viewType == "")) {
viewType = nsMsgViewType.eShowAll;
}
if(messageView)
{
messageView.viewType = viewType;
}
}
function ShowThreads(showThreads)
{
dump('in showthreads\n');
//dump('in showthreads\n');
if(messageView)
{
messageView.showThreads = showThreads;

View File

@ -58,7 +58,7 @@
CanSubscribe="rdf:http://home.netscape.com/NC-rdf#CanSubscribe"
CanFileMessages="rdf:http://home.netscape.com/NC-rdf#CanFileMessages"
NoSelect="rdf:http://home.netscape.com/NC-rdf#NoSelect"
persist="threaded open sortResource sortDirection">
persist="threaded open sortResource sortDirection viewType">
<treerow class="tree-folder-row"
IsServer="rdf:http://home.netscape.com/NC-rdf#IsServer"
HasUnreadMessages="rdf:http://home.netscape.com/NC-rdf#HasUnreadMessages"

View File

@ -288,12 +288,9 @@ var DefaultController =
case "cmd_previousFlaggedMsg":
return IsViewNavigationItemEnabled();
case "cmd_viewAllMsgs":
return true;
case "cmd_sortByThread":
return (messageView.viewType != viewShowUnread);
break;
case "cmd_viewUnreadMsgs":
return (messageView.showThreads == false);
return true;
break;
case "cmd_undo":
case "cmd_redo":
@ -816,10 +813,7 @@ function MsgPreviousFlaggedMessage()
GoPreviousMessage(navigateFlagged, true);
}
var viewShowAll =0;
var viewShowRead = 1;
var viewShowUnread =2;
var viewShowWatched = 3;
var nsMsgViewType = Components.interfaces.nsMsgViewType;
function MsgViewAllMsgs()
{
@ -827,8 +821,12 @@ function MsgViewAllMsgs()
if(messageView)
{
messageView.viewType = viewShowAll;
messageView.showThreads = false;
messageView.viewType = nsMsgViewType.eShowAll;
var folder = GetSelectedFolder();
if(folder) {
folder.setAttribute("viewType", messageView.viewType);
}
}
RefreshThreadTreeView();
}
@ -839,8 +837,12 @@ function MsgViewUnreadMsg()
if(messageView)
{
messageView.viewType = viewShowUnread;
messageView.showThreads = false;
messageView.viewType = nsMsgViewType.eShowUnread;
var folder = GetSelectedFolder();
if(folder) {
folder.setAttribute("viewType", messageView.viewType);
}
}
RefreshThreadTreeView();

View File

@ -73,12 +73,12 @@ function InitViewMessagesMenu()
var allMenuItem = document.getElementById("viewAllMessagesMenuItem");
var hidden = allMenuItem.getAttribute("hidden") == "true";
if(allMenuItem && !hidden)
allMenuItem.setAttribute("checked", messageView.viewType == viewShowAll);
allMenuItem.setAttribute("checked", messageView.viewType == nsMsgViewType.eShowAll);
var unreadMenuItem = document.getElementById("viewUnreadMessagesMenuItem");
hidden = unreadMenuItem.getAttribute("hidden") == "true";
if(unreadMenuItem && !hidden)
unreadMenuItem.setAttribute("checked", messageView.viewType == viewShowUnread);
unreadMenuItem.setAttribute("checked", messageView.viewType == nsMsgViewType.eShowUnread);
}

View File

@ -36,6 +36,7 @@ var gCurrentFolderToReroot;
var gCurrentLoadingFolderIsThreaded = false;
var gCurrentLoadingFolderSortID ="";
var gCurrentLoadingFolderSortDirection = null;
var gCurrentLoadingFolderViewType = "";
var gCurrentDisplayedMessage = null;
var gNextMessageAfterDelete = null;
@ -110,10 +111,11 @@ var folderListener = {
if(msgFolder)
{
msgFolder.endFolderLoading();
RerootFolder(uri, msgFolder, gCurrentLoadingFolderIsThreaded, gCurrentLoadingFolderSortID, gCurrentLoadingFolderSortDirection);
RerootFolder(uri, msgFolder, gCurrentLoadingFolderIsThreaded, gCurrentLoadingFolderSortID, gCurrentLoadingFolderSortDirection, gCurrentLoadingFolderViewType);
gCurrentLoadingFolderIsThreaded = false;
gCurrentLoadingFolderSortID = "";
gCurrentLoadingFolderSortDirection = null;
gCurrentLoadingFolderViewType = "";
if (gNextMessageAfterLoad) {
gNextMessageAfterLoad = false;

View File

@ -208,11 +208,6 @@ function ChangeThreadView()
}
else if(currentView == 'unthreaded')
{
//if we're in unread messages view, don't allow to go into threaded mode because
//we don't support it.
if(messageView.viewType == viewShowUnread)
return;
ShowThreads(true);
if(folder)
folder.setAttribute('threaded', "true");

View File

@ -28,7 +28,6 @@ nsMsgMailSession.h
nsMsgFolderCache.h
nsMsgFolderDataSource.h
nsMsgMessageDataSource.h
nsMessageViewDataSource.h
nsMsgAccount.h
nsMsgAccountManager.h
nsMsgRDFDataSource.h

View File

@ -43,7 +43,6 @@ CPPSRCS = \
nsMsgRDFDataSource.cpp \
nsMsgFolderDataSource.cpp \
nsMsgMessageDataSource.cpp \
nsMessageViewDataSource.cpp \
nsMsgAccountManagerDS.cpp \
nsMsgRDFUtils.cpp \
nsMsgBiffManager.cpp \
@ -74,7 +73,6 @@ EXPORTS = \
nsMsgFolderDataSource.h \
nsMsgFolderCache.h \
nsMsgMessageDataSource.h \
nsMessageViewDataSource.h \
nsMsgAccountManagerDS.h \
nsMsgRDFDataSource.h \
nsMsgRDFUtils.h \

View File

@ -37,7 +37,6 @@ EXPORTS= \
nsMsgFolderDataSource.h \
nsMsgFolderCache.h \
nsMsgMessageDataSource.h \
nsMessageViewDataSource.h \
nsMsgAccount.h \
nsMsgAccountManager.h \
nsMsgRDFDataSource.h \
@ -72,7 +71,6 @@ CPP_OBJS= \
.\$(OBJDIR)\nsUrlListenerManager.obj \
.\$(OBJDIR)\nsMsgMailSession.obj \
.\$(OBJDIR)\nsCopyMessageStreamListener.obj \
.\$(OBJDIR)\nsMessageViewDataSource.obj \
.\$(OBJDIR)\nsMsgAccountManager.obj \
.\$(OBJDIR)\nsMsgAccount.obj \
.\$(OBJDIR)\nsMsgFolderDataSource.obj \

View File

@ -26,10 +26,9 @@
#include "nsIMessage.h"
#include "nsIMsgFolder.h"
#include "nsMsgUtils.h"
#include "nsMessageViewDataSource.h"
#include "nsEnumeratorUtils.h"
#include "MailNewsTypes.h"
#include "MailNewsTypes2.h"
NS_IMPL_ISUPPORTS1(nsMessageView, nsIMessageView)
@ -37,8 +36,7 @@ nsMessageView::nsMessageView()
{
NS_INIT_REFCNT();
mShowThreads = PR_FALSE;
mViewType = nsIMessageView::eShowAll;
mViewType = nsMsgViewType::eShowAll;
}
nsMessageView::~nsMessageView()
@ -81,94 +79,358 @@ NS_IMETHODIMP nsMessageView::SetShowThreads(PRBool aShowThreads)
return NS_OK;
}
NS_IMETHODIMP nsMessageView::GetMessages(nsIRDFResource *parentResource, nsIMsgWindow* msgWindow, nsISimpleEnumerator **messages)
NS_IMETHODIMP nsMessageView::HasMessages(nsIRDFResource *parentResource, nsIMsgWindow* msgWindow, PRBool *hasMessages)
{
nsresult rv = NS_OK;
*messages = nsnull;
*hasMessages = PR_FALSE;
PRUint32 viewType;
rv = GetViewType(&viewType);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIMessage> message(do_QueryInterface(parentResource, &rv));
if (NS_SUCCEEDED(rv)) {
if(mShowThreads)
{
if(mShowThreads) {
nsCOMPtr<nsIMsgFolder> msgfolder;
rv = message->GetMsgFolder(getter_AddRefs(msgfolder));
if(NS_SUCCEEDED(rv))
{
if(NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIMsgThread> thread;
rv = msgfolder->GetThreadForMessage(message, getter_AddRefs(thread));
if(NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISimpleEnumerator> threadMessages;
nsMsgKey msgKey;
message->GetMessageKey(&msgKey);
thread->EnumerateMessages(msgKey, getter_AddRefs(threadMessages));
nsCOMPtr<nsMessageFromMsgHdrEnumerator> converter;
NS_NewMessageFromMsgHdrEnumerator(threadMessages, msgfolder, getter_AddRefs(converter));
PRUint32 viewType;
rv = GetViewType(&viewType);
if(NS_FAILED(rv)) return rv;
nsMessageViewMessageEnumerator * messageEnumerator =
new nsMessageViewMessageEnumerator(converter, viewType);
if(!messageEnumerator)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(messageEnumerator);
*messages = messageEnumerator;
rv = NS_OK;
if(NS_SUCCEEDED(rv)) {
nsMsgKey msgKey;
message->GetMessageKey(&msgKey);
rv = thread->HasMessagesOfType(msgKey, viewType, hasMessages);
NS_ENSURE_SUCCESS(rv,rv);
}
}
}
}
nsCOMPtr<nsIMsgFolder> folder(do_QueryInterface(parentResource));
else {
nsCOMPtr<nsIMsgFolder> folder(do_QueryInterface(parentResource));
if(folder) {
if(mShowThreads) {
rv = folder->HasThreads(msgWindow, hasMessages);
NS_ENSURE_SUCCESS(rv,rv);
}
else {
rv = folder->HasMessagesOfType(msgWindow, viewType, hasMessages);
NS_ENSURE_SUCCESS(rv,rv);
}
}
}
if(folder)
{
if(mShowThreads)
{
return rv;
}
NS_IMETHODIMP nsMessageView::GetMessages(nsIRDFResource *parentResource, nsIMsgWindow* msgWindow, nsISimpleEnumerator **messages)
{
nsresult rv = NS_OK;
PRUint32 viewType;
rv = GetViewType(&viewType);
NS_ENSURE_SUCCESS(rv,rv);
*messages = nsnull;
nsCOMPtr<nsIMessage> message(do_QueryInterface(parentResource, &rv));
if (NS_SUCCEEDED(rv)) {
if(mShowThreads) {
nsCOMPtr<nsIMsgFolder> msgfolder;
rv = message->GetMsgFolder(getter_AddRefs(msgfolder));
if(NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIMsgThread> thread;
rv = msgfolder->GetThreadForMessage(message, getter_AddRefs(thread));
if(NS_SUCCEEDED(rv)) {
nsCOMPtr<nsISimpleEnumerator> threadMessages;
nsMsgKey msgKey;
message->GetMessageKey(&msgKey);
#ifdef HAVE_4X_UNREAD_THREADS
switch (viewType) {
case nsMsgViewType::eShowAll:
thread->EnumerateMessages(msgKey, getter_AddRefs(threadMessages));
break;
case nsMsgViewType::eShowUnread:
thread->EnumerateUnreadMessages(msgKey, getter_AddRefs(threadMessages));
break;
case nsMsgViewType::eShowRead:
case nsMsgViewType::eShowWatched:
default:
NS_ENSURE_SUCCESS(NS_ERROR_UNEXPECTED,NS_ERROR_UNEXPECTED);
break;
}
#else
// Threads with unread
thread->EnumerateMessages(msgKey, getter_AddRefs(threadMessages));
#endif /* HAVE_4X_UNREAD_THREADS */
nsCOMPtr<nsMessageFromMsgHdrEnumerator> converter;
NS_NewMessageFromMsgHdrEnumerator(threadMessages, msgfolder, getter_AddRefs(converter));
// we've done the work (by calling EnumerateMessages()
// or EnumerateUnreadMessages(), based on viewType)
// so we want all messages that are left.
nsMessageViewMessageEnumerator * messageEnumerator =
new nsMessageViewMessageEnumerator(converter, nsMsgViewType::eShowAll);
if(!messageEnumerator) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(messageEnumerator);
*messages = messageEnumerator;
rv = NS_OK;
}
}
}
}
else {
nsCOMPtr<nsIMsgFolder> folder(do_QueryInterface(parentResource));
if(folder) {
if(mShowThreads) {
nsCOMPtr<nsISimpleEnumerator> threads;
rv = folder->GetThreads(msgWindow, getter_AddRefs(threads));
if (NS_FAILED(rv)) return rv;
rv = folder->GetThreadsOfType(msgWindow, viewType, getter_AddRefs(threads));
NS_ENSURE_SUCCESS(rv,rv);
nsMessageViewThreadEnumerator * threadEnumerator =
new nsMessageViewThreadEnumerator(threads, folder);
if(!threadEnumerator)
return NS_ERROR_OUT_OF_MEMORY;
if(!threadEnumerator) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(threadEnumerator);
*messages = threadEnumerator;
rv = NS_OK;
}
else
{
else {
nsCOMPtr<nsISimpleEnumerator> folderMessages;
rv = folder->GetMessages(msgWindow, getter_AddRefs(folderMessages));
if (NS_SUCCEEDED(rv))
{
PRUint32 viewType;
rv = GetViewType(&viewType);
if(NS_FAILED(rv))
return rv;
if (NS_SUCCEEDED(rv)) {
nsMessageViewMessageEnumerator * messageEnumerator =
new nsMessageViewMessageEnumerator(folderMessages, viewType);
if(!messageEnumerator)
return NS_ERROR_OUT_OF_MEMORY;
if(!messageEnumerator) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(messageEnumerator);
*messages = messageEnumerator;
rv = NS_OK;
}
}
}
}
if(!*messages)
{
if(!*messages) {
//return empty array
nsCOMPtr<nsISupportsArray> assertions;
rv = NS_NewISupportsArray(getter_AddRefs(assertions));
if(NS_FAILED(rv))
return rv;
NS_ENSURE_SUCCESS(rv,rv);
rv = NS_NewArrayEnumerator(messages, assertions);
}
return rv;
}
////////////////////////// nsMessageViewMessageEnumerator //////////////////
NS_IMPL_ISUPPORTS1(nsMessageViewMessageEnumerator, nsISimpleEnumerator)
nsMessageViewMessageEnumerator::nsMessageViewMessageEnumerator(nsISimpleEnumerator *srcEnumerator,
PRUint32 viewType)
{
NS_INIT_REFCNT();
mSrcEnumerator = dont_QueryInterface(srcEnumerator);
mViewType = viewType;
}
nsMessageViewMessageEnumerator::~nsMessageViewMessageEnumerator()
{
//member variables are nsCOMPtr's.
}
/** Next will advance the list. will return failed if already at end
*/
NS_IMETHODIMP nsMessageViewMessageEnumerator::GetNext(nsISupports **aItem)
{
if (!aItem)
return NS_ERROR_NULL_POINTER;
if(!mCurMsg)
return NS_ERROR_FAILURE;
*aItem = mCurMsg;
NS_ADDREF(*aItem);
return NS_OK;
}
/** GetNext will return the next item it will fail if the list is empty
* @param aItem return value
*/
/** return if the collection is at the end. that is the beginning following a call to Prev
* and it is the end of the list following a call to next
* @param aItem return value
*/
NS_IMETHODIMP nsMessageViewMessageEnumerator::HasMoreElements(PRBool *aResult)
{
if(!aResult)
return NS_ERROR_NULL_POINTER;
nsresult rv = SetAtNextItem();
*aResult = NS_SUCCEEDED(rv);
return NS_OK;
}
//This function sets mSrcEnumerator at the next item that fits
//the criteria for this enumerator. If there are no more items
//returns NS_ERROR_FAILURE
nsresult nsMessageViewMessageEnumerator::SetAtNextItem()
{
nsresult rv;
nsCOMPtr<nsISupports> currentItem;
nsCOMPtr<nsIMessage> message;
PRBool hasMore = PR_FALSE;
while(NS_SUCCEEDED(mSrcEnumerator->HasMoreElements(&hasMore)) && hasMore)
{
rv = mSrcEnumerator->GetNext(getter_AddRefs(currentItem));
PRBool successful = PR_FALSE;
if(NS_FAILED(rv))
break;
message = do_QueryInterface(currentItem, &rv);
if(NS_SUCCEEDED(rv))
{
PRBool meetsCriteria;
rv = MeetsCriteria(message, &meetsCriteria);
if(NS_SUCCEEDED(rv) & meetsCriteria)
successful = PR_TRUE;
}
if(successful)
{
mCurMsg = do_QueryInterface(currentItem, &rv);
return rv;
}
}
return NS_ERROR_FAILURE;
}
nsresult nsMessageViewMessageEnumerator::MeetsCriteria(nsIMessage *message, PRBool *meetsCriteria)
{
if(!meetsCriteria)
return NS_ERROR_NULL_POINTER;
*meetsCriteria = PR_FALSE;
if(mViewType == nsMsgViewType::eShowAll)
{
*meetsCriteria = PR_TRUE;
}
else
{
PRUint32 flags;
message->GetFlags(&flags);
if(mViewType == nsMsgViewType::eShowRead)
*meetsCriteria = flags & MSG_FLAG_READ;
else if(mViewType == nsMsgViewType::eShowUnread)
*meetsCriteria = !(flags & MSG_FLAG_READ);
else if(mViewType == nsMsgViewType::eShowWatched)
*meetsCriteria = flags & MSG_FLAG_WATCHED;
}
return NS_OK;
}
////////////////////////// nsMessageViewThreadEnumerator //////////////////
NS_IMPL_ISUPPORTS1(nsMessageViewThreadEnumerator, nsISimpleEnumerator)
nsMessageViewThreadEnumerator::nsMessageViewThreadEnumerator(nsISimpleEnumerator *threads,
nsIMsgFolder *srcFolder)
{
NS_INIT_REFCNT();
mThreads = do_QueryInterface(threads);
mFolder = do_QueryInterface(srcFolder);
mNeedToPrefetch = PR_TRUE;
}
nsMessageViewThreadEnumerator::~nsMessageViewThreadEnumerator()
{
//member variables are nsCOMPtr's
}
/** Next will advance the list. will return failed if already at end
*/
NS_IMETHODIMP nsMessageViewThreadEnumerator::GetNext(nsISupports **aItem)
{
nsresult rv = NS_OK;
if(!mMessages)
return NS_ERROR_FAILURE;
if (mNeedToPrefetch)
rv = Prefetch();
if (NS_SUCCEEDED(rv) && mMessages)
rv = mMessages->GetNext(aItem);
// NS_ASSERTION(NS_SUCCEEDED(rv),"getnext shouldn't fail");
mNeedToPrefetch = PR_TRUE;
return rv;
}
nsresult nsMessageViewThreadEnumerator::Prefetch()
{
nsresult rv = NS_OK;
//then check to see if the there are no more messages in last thread
//Get the next thread
rv = mThreads->GetNext(getter_AddRefs(mCurThread));
if(NS_SUCCEEDED(rv))
{
rv = GetMessagesForCurrentThread();
mNeedToPrefetch = PR_FALSE;
}
else
mMessages = nsnull;
return rv;
}
/** return if the collection is at the end. that is the beginning following a call to Prev
* and it is the end of the list following a call to next
* @param aItem return value
*/
NS_IMETHODIMP nsMessageViewThreadEnumerator::HasMoreElements(PRBool *aResult)
{
if (!aResult)
return NS_ERROR_NULL_POINTER;
nsresult rv = NS_OK;
if (mNeedToPrefetch)
Prefetch();
//First check to see if there are no more threads
if (mMessages)
rv = mMessages->HasMoreElements(aResult);
else
*aResult = nsnull;
return rv;
}
nsresult nsMessageViewThreadEnumerator::GetMessagesForCurrentThread()
{
nsCOMPtr<nsIMsgThread> thread;
nsresult rv = NS_OK;
if(mCurThread)
{
thread = do_QueryInterface(mCurThread, &rv);
if(NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISimpleEnumerator> msgHdrs;
rv = thread->EnumerateMessages(nsMsgKey_None, getter_AddRefs(msgHdrs));
nsMessageFromMsgHdrEnumerator *messages;
NS_NewMessageFromMsgHdrEnumerator(msgHdrs, mFolder, &messages);
mMessages = do_QueryInterface(messages, &rv);
NS_IF_RELEASE(messages);
}
}
else
mMessages = nsnull;
return rv;
}

View File

@ -24,6 +24,9 @@
#define _nsMessageView_h
#include "nsIMessageView.h"
#include "nsIEnumerator.h"
#include "nsIMsgFolder.h"
#include "nsIMessage.h"
class nsMessageView : public nsIMessageView {
@ -42,6 +45,55 @@ protected:
};
class nsMessageViewMessageEnumerator: public nsISimpleEnumerator
{
public:
NS_DECL_ISUPPORTS
nsMessageViewMessageEnumerator(nsISimpleEnumerator *srcEnumerator, PRUint32 viewType);
virtual ~nsMessageViewMessageEnumerator();
NS_DECL_NSISIMPLEENUMERATOR
protected:
nsresult SetAtNextItem();
nsresult MeetsCriteria(nsIMessage *message, PRBool *meetsCriteria);
protected:
nsCOMPtr<nsISimpleEnumerator> mSrcEnumerator;
nsCOMPtr<nsISupports> mCurMsg;
nsCOMPtr<nsISupports> mCurThread;
PRUint32 mViewType;
};
class nsMessageViewThreadEnumerator: public nsISimpleEnumerator
{
public:
NS_DECL_ISUPPORTS
nsMessageViewThreadEnumerator(nsISimpleEnumerator *srcEnumerator, nsIMsgFolder *srcFolder);
virtual ~nsMessageViewThreadEnumerator();
NS_DECL_NSISIMPLEENUMERATOR
protected:
nsresult GetMessagesForCurrentThread();
nsresult Prefetch();
protected:
nsCOMPtr<nsISimpleEnumerator> mThreads;
nsCOMPtr<nsISimpleEnumerator> mMessages;
nsCOMPtr<nsISupports> mCurThread;
nsCOMPtr<nsIMsgFolder> mFolder;
PRBool mNeedToPrefetch;
};
#endif

View File

@ -1,816 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
*/
#include "nsMessageViewDataSource.h"
#include "nsEnumeratorUtils.h"
#include "nsRDFCID.h"
#include "nsIServiceManager.h"
#include "nsXPIDLString.h"
#include "nsMsgRDFUtils.h"
#include "nsMsgUtils.h"
#include "plstr.h"
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
nsIRDFResource* nsMessageViewDataSource::kNC_MessageChild = nsnull;
nsIRDFResource* nsMessageViewDataSource::kNC_Subject = nsnull;
nsIRDFResource* nsMessageViewDataSource::kNC_Sender = nsnull;
nsIRDFResource* nsMessageViewDataSource::kNC_Date = nsnull;
nsIRDFResource* nsMessageViewDataSource::kNC_Status = nsnull;
NS_IMPL_ADDREF(nsMessageViewDataSource)
NS_IMETHODIMP_(nsrefcnt)
nsMessageViewDataSource::Release()
{
// We need a special implementation of Release(). The composite
// datasource holds a reference to mDataSource, and mDataSource
// holds a reference _back_ to the composite datasource by way of
// the "observer".
NS_PRECONDITION(PRInt32(mRefCnt) > 0, "duplicate release");
--mRefCnt;
// When the number of references is one, we know that all that
// remains is the circular references from mDataSource back to
// us. Release it.
if (mRefCnt == 1 && mDataSource) {
mDataSource->RemoveObserver(this);
return 0;
}
else if (mRefCnt == 0) {
delete this;
return 0;
}
else {
return mRefCnt;
}
}
NS_IMETHODIMP
nsMessageViewDataSource::QueryInterface(REFNSIID iid, void** result)
{
if (! result)
return NS_ERROR_NULL_POINTER;
*result = nsnull;
if (iid.Equals(NS_GET_IID(nsIRDFCompositeDataSource)) ||
iid.Equals(NS_GET_IID(nsIRDFDataSource)) ||
iid.Equals(NS_GET_IID(nsISupports)))
{
*result = NS_STATIC_CAST(nsIRDFCompositeDataSource*, this);
NS_ADDREF_THIS();
}
if(*result)
{
return NS_OK;
}
return NS_NOINTERFACE;
}
nsMessageViewDataSource::nsMessageViewDataSource(void)
{
NS_INIT_REFCNT();
mObservers = nsnull;
mViewType = nsIMessageView::eShowAll;
mInitialized = PR_FALSE;
mShowThreads = PR_FALSE;
}
nsMessageViewDataSource::~nsMessageViewDataSource (void)
{
mRDFService->UnregisterDataSource(this);
nsrefcnt refcnt;
NS_RELEASE2(kNC_MessageChild, refcnt);
NS_RELEASE2(kNC_Subject, refcnt);
NS_RELEASE2(kNC_Date, refcnt);
NS_RELEASE2(kNC_Sender, refcnt);
NS_RELEASE2(kNC_Status, refcnt);
nsServiceManager::ReleaseService(kRDFServiceCID, mRDFService); // XXX probably need shutdown listener here
mRDFService = nsnull;
}
nsresult
nsMessageViewDataSource::Init()
{
if (mInitialized)
return NS_ERROR_ALREADY_INITIALIZED;
nsresult rv;
rv = nsServiceManager::GetService(kRDFServiceCID,
NS_GET_IID(nsIRDFService),
(nsISupports**) &mRDFService); // XXX probably need shutdown listener here
if (NS_FAILED(rv)) return rv;
mRDFService->RegisterDataSource(this, PR_FALSE);
if (! kNC_MessageChild) {
mRDFService->GetResource(NC_RDF_MESSAGECHILD, &kNC_MessageChild);
mRDFService->GetResource(NC_RDF_SUBJECT, &kNC_Subject);
mRDFService->GetResource(NC_RDF_DATE, &kNC_Date);
mRDFService->GetResource(NC_RDF_SENDER, &kNC_Sender);
mRDFService->GetResource(NC_RDF_STATUS , &kNC_Status);
}
mInitialized = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::GetURI(char* *uri)
{
if ((*uri = nsXPIDLCString::Copy("rdf:mail-messageview")) == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::GetSource(nsIRDFResource* property,
nsIRDFNode* target,
PRBool tv,
nsIRDFResource** source /* out */)
{
if(mDataSource)
return mDataSource->GetSource(property, target, tv, source);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::GetTarget(nsIRDFResource* source,
nsIRDFResource* property,
PRBool tv,
nsIRDFNode** target)
{
nsresult rv;
//First see if we handle this
nsCOMPtr<nsIMessage> message(do_QueryInterface(source));
if(message)
{
rv = createMessageNode(message, property, target);
if(NS_SUCCEEDED(rv) && rv != NS_RDF_NO_VALUE)
return rv;
}
if(mDataSource)
return mDataSource->GetTarget(source, property, tv, target);
else
return NS_RDF_NO_VALUE;
}
NS_IMETHODIMP nsMessageViewDataSource::GetSources(nsIRDFResource* property,
nsIRDFNode* target,
PRBool tv,
nsISimpleEnumerator** sources)
{
if(mDataSource)
return mDataSource->GetSources(property, target, tv, sources);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::GetTargets(nsIRDFResource* source,
nsIRDFResource* property,
PRBool tv,
nsISimpleEnumerator** targets)
{
if(mDataSource)
return mDataSource->GetTargets(source, property, tv, targets);
else
return NS_RDF_NO_VALUE;
}
NS_IMETHODIMP nsMessageViewDataSource::Assert(nsIRDFResource* source,
nsIRDFResource* property,
nsIRDFNode* target,
PRBool tv)
{
if(mDataSource)
return mDataSource->Assert(source, property, target, tv);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::Unassert(nsIRDFResource* source,
nsIRDFResource* property,
nsIRDFNode* target)
{
if(mDataSource)
return mDataSource->Unassert(source, property, target);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::Change(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aOldTarget,
nsIRDFNode* aNewTarget)
{
if (mDataSource)
return mDataSource->Change(aSource, aProperty, aOldTarget, aNewTarget);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::Move(nsIRDFResource* aOldSource,
nsIRDFResource* aNewSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget)
{
if (mDataSource)
return mDataSource->Move(aOldSource, aNewSource, aProperty, aTarget);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::HasAssertion(nsIRDFResource* source,
nsIRDFResource* property,
nsIRDFNode* target,
PRBool tv,
PRBool* hasAssertion)
{
if(mDataSource)
return mDataSource->HasAssertion(source, property, target, tv, hasAssertion);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::AddObserver(nsIRDFObserver* n)
{
if (! mObservers) {
nsresult rv = NS_NewISupportsArray(getter_AddRefs(mObservers));
if (NS_FAILED(rv)) return rv;
}
mObservers->AppendElement(n);
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::RemoveObserver(nsIRDFObserver* n)
{
if (! mObservers)
return NS_OK;
mObservers->RemoveElement(n);
return NS_OK;
}
nsresult
nsMessageViewDataSource::GetMessageEnumerator(nsIMessage* message, nsISimpleEnumerator* *result)
{
nsresult rv;
nsCOMPtr<nsIMsgFolder> folder;
rv = message->GetMsgFolder(getter_AddRefs(folder));
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(folder, "GetMsgFolder returned NS_OK, but no folder");
nsCOMPtr<nsIMsgThread> thread;
rv = folder->GetThreadForMessage(message, getter_AddRefs(thread));
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(folder, "GetThreadForMessage returned NS_OK, but no thread");
nsMsgKey msgKey;
rv = message->GetMessageKey(&msgKey);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISimpleEnumerator> messages;
rv = thread->EnumerateMessages(msgKey, getter_AddRefs(messages));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsMessageFromMsgHdrEnumerator> converter;
rv = NS_NewMessageFromMsgHdrEnumerator(messages, folder, getter_AddRefs(converter));
if (NS_FAILED(rv)) return rv;
nsMessageViewMessageEnumerator* messageEnumerator =
new nsMessageViewMessageEnumerator(converter, nsIMessageView::eShowAll);
if (!messageEnumerator)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(messageEnumerator);
*result = messageEnumerator;
return NS_OK;
}
NS_IMETHODIMP
nsMessageViewDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, PRBool *result)
{
*result = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsMessageViewDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, PRBool *result)
{
nsresult rv;
nsCOMPtr<nsIMessage> message;
if(mShowThreads && NS_SUCCEEDED(aSource->QueryInterface(NS_GET_IID(nsIMessage), getter_AddRefs(message))))
{
if (aArc == kNC_Subject ||
aArc == kNC_Sender ||
aArc == kNC_Date ||
aArc == kNC_Status) {
*result = PR_TRUE;
return NS_OK;
}
else if (aArc == kNC_MessageChild) {
nsCOMPtr<nsISimpleEnumerator> messageEnumerator;
rv = GetMessageEnumerator(message, getter_AddRefs(messageEnumerator));
if (NS_SUCCEEDED(rv)) {
PRBool hasMore = PR_FALSE;
if (NS_SUCCEEDED(messageEnumerator->HasMoreElements(&hasMore)) && hasMore) {
*result = PR_TRUE;
return NS_OK;
}
}
}
}
if (mDataSource)
return mDataSource->HasArcOut(aSource, aArc, result);
else
*result = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::ArcLabelsIn(nsIRDFNode* node,
nsISimpleEnumerator** labels)
{
if(mDataSource)
return mDataSource->ArcLabelsIn(node, labels);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::ArcLabelsOut(nsIRDFResource* source,
nsISimpleEnumerator** labels)
{
nsCOMPtr<nsIMessage> message;
if(mShowThreads && NS_SUCCEEDED(source->QueryInterface(NS_GET_IID(nsIMessage), getter_AddRefs(message))))
{
nsresult rv;
nsCOMPtr<nsISupportsArray> arcs;
NS_NewISupportsArray(getter_AddRefs(arcs));
if (arcs == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
arcs->AppendElement(kNC_Subject);
arcs->AppendElement(kNC_Sender);
arcs->AppendElement(kNC_Date);
arcs->AppendElement(kNC_Status);
nsCOMPtr<nsISimpleEnumerator> messageEnumerator;
rv = GetMessageEnumerator(message, getter_AddRefs(messageEnumerator));
if (NS_SUCCEEDED(rv)) {
PRBool hasMore = PR_FALSE;
if (NS_SUCCEEDED(messageEnumerator->HasMoreElements(&hasMore)) && hasMore) {
arcs->AppendElement(kNC_MessageChild);
}
}
return NS_NewArrayEnumerator(labels, arcs);
}
if(mDataSource)
return mDataSource->ArcLabelsOut(source, labels);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::GetAllResources(nsISimpleEnumerator** aCursor)
{
if(mDataSource)
return mDataSource->GetAllResources(aCursor);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::GetAllCommands(nsIRDFResource* source,
nsIEnumerator/*<nsIRDFResource>*/** commands)
{
if(mDataSource)
return mDataSource->GetAllCommands(source, commands);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::GetAllCmds(nsIRDFResource* source,
nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
{
if(mDataSource)
return mDataSource->GetAllCmds(source, commands);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
nsIRDFResource* aCommand,
nsISupportsArray/*<nsIRDFResource>*/* aArguments,
PRBool* aResult)
{
if(mDataSource)
return mDataSource->IsCommandEnabled(aSources, aCommand, aArguments, aResult);
else
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
nsIRDFResource* aCommand,
nsISupportsArray/*<nsIRDFResource>*/* aArguments)
{
if(mDataSource)
return mDataSource->DoCommand(aSources, aCommand, aArguments);
else
return NS_OK;
}
NS_IMETHODIMP
nsMessageViewDataSource::GetAllowNegativeAssertions(PRBool *aAllowNegativeAssertions)
{
// *aAllowNegativeAssertions = mAllowNegativeAssertions;
*aAllowNegativeAssertions = PR_TRUE; // XXX fix build bustage
return(NS_OK);
}
NS_IMETHODIMP
nsMessageViewDataSource::SetAllowNegativeAssertions(PRBool aAllowNegativeAssertions)
{
// mAllowNegativeAssertions = aAllowNegativeAssertions;
return(NS_OK);
}
NS_IMETHODIMP
nsMessageViewDataSource::GetCoalesceDuplicateArcs(PRBool *aCoalesceDuplicateArcs)
{
// *aCoalesceDuplicateArcs = mCoalesceDuplicateArcs;
*aCoalesceDuplicateArcs = PR_TRUE; // XXX fix build bustage
return(NS_OK);
}
NS_IMETHODIMP
nsMessageViewDataSource::SetCoalesceDuplicateArcs(PRBool aCoalesceDuplicateArcs)
{
// mCoalesceDuplicateArcs = aCoalesceDuplicateArcs;
return(NS_OK);
}
//We're only going to allow one datasource at a time.
NS_IMETHODIMP nsMessageViewDataSource::AddDataSource(nsIRDFDataSource* source)
{
if(mDataSource)
RemoveDataSource(mDataSource);
mDataSource = dont_QueryInterface(source);
mDataSource->AddObserver(this);
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::RemoveDataSource(nsIRDFDataSource* source)
{
mDataSource->RemoveObserver(this);
mDataSource = null_nsCOMPtr();
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::GetDataSources(nsISimpleEnumerator** _result)
{
return NS_NewSingletonEnumerator(_result, mDataSource);
}
NS_IMETHODIMP nsMessageViewDataSource::OnAssert(nsIRDFDataSource* aDataSource,
nsIRDFResource* subject,
nsIRDFResource* predicate,
nsIRDFNode* object)
{
if (mObservers) {
PRUint32 count;
nsresult rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = count - 1; i >= 0; --i) {
nsIRDFObserver* obs = (nsIRDFObserver*) mObservers->ElementAt(i);
obs->OnAssert(this, subject, predicate, object);
NS_RELEASE(obs);
}
}
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::OnUnassert(nsIRDFDataSource* aDataSource,
nsIRDFResource* subject,
nsIRDFResource* predicate,
nsIRDFNode* object)
{
if (mObservers) {
PRUint32 count;
nsresult rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = PRInt32(count) - 1; i >= 0; --i) {
nsIRDFObserver* obs = (nsIRDFObserver*) mObservers->ElementAt(i);
obs->OnUnassert(this, subject, predicate, object);
NS_RELEASE(obs);
}
}
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::OnChange(nsIRDFDataSource* aDataSource,
nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aOldTarget,
nsIRDFNode* aNewTarget)
{
if (mObservers) {
PRUint32 count;
nsresult rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = PRInt32(count) - 1; i >= 0; --i) {
nsIRDFObserver* obs = (nsIRDFObserver*) mObservers->ElementAt(i);
obs->OnChange(this, aSource, aProperty, aOldTarget, aNewTarget);
NS_RELEASE(obs);
}
}
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::OnMove(nsIRDFDataSource* aDataSource,
nsIRDFResource* aOldSource,
nsIRDFResource* aNewSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget)
{
if (mObservers) {
PRUint32 count;
nsresult rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = PRInt32(count) - 1; i >= 0; --i) {
nsIRDFObserver* obs = (nsIRDFObserver*) mObservers->ElementAt(i);
obs->OnMove(aDataSource, aOldSource, aNewSource, aProperty, aTarget);
NS_RELEASE(obs);
}
}
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
{
return NS_OK;
}
NS_IMETHODIMP nsMessageViewDataSource::EndUpdateBatch(nsIRDFDataSource* aDataSource)
{
return NS_OK;
}
nsresult
nsMessageViewDataSource::createMessageNode(nsIMessage *message,
nsIRDFResource *property,
nsIRDFNode **target)
{
return NS_RDF_NO_VALUE;
}
////////////////////////// nsMessageViewMessageEnumerator //////////////////
NS_IMPL_ISUPPORTS1(nsMessageViewMessageEnumerator, nsISimpleEnumerator)
nsMessageViewMessageEnumerator::nsMessageViewMessageEnumerator(nsISimpleEnumerator *srcEnumerator,
PRUint32 showStatus)
{
NS_INIT_REFCNT();
mSrcEnumerator = dont_QueryInterface(srcEnumerator);
mShowStatus = showStatus;
}
nsMessageViewMessageEnumerator::~nsMessageViewMessageEnumerator()
{
//member variables are nsCOMPtr's.
}
/** Next will advance the list. will return failed if already at end
*/
NS_IMETHODIMP nsMessageViewMessageEnumerator::GetNext(nsISupports **aItem)
{
if (!aItem)
return NS_ERROR_NULL_POINTER;
if(!mCurMsg)
return NS_ERROR_FAILURE;
*aItem = mCurMsg;
NS_ADDREF(*aItem);
return NS_OK;
}
/** GetNext will return the next item it will fail if the list is empty
* @param aItem return value
*/
/** return if the collection is at the end. that is the beginning following a call to Prev
* and it is the end of the list following a call to next
* @param aItem return value
*/
NS_IMETHODIMP nsMessageViewMessageEnumerator::HasMoreElements(PRBool *aResult)
{
if(!aResult)
return NS_ERROR_NULL_POINTER;
nsresult rv = SetAtNextItem();
*aResult = NS_SUCCEEDED(rv);
return NS_OK;
}
//This function sets mSrcEnumerator at the next item that fits
//the criteria for this enumerator. If there are no more items
//returns NS_ERROR_FAILURE
nsresult nsMessageViewMessageEnumerator::SetAtNextItem()
{
nsresult rv;
nsCOMPtr<nsISupports> currentItem;
nsCOMPtr<nsIMessage> message;
PRBool hasMore = PR_FALSE;
while(NS_SUCCEEDED(mSrcEnumerator->HasMoreElements(&hasMore)) && hasMore)
{
rv = mSrcEnumerator->GetNext(getter_AddRefs(currentItem));
PRBool successful = PR_FALSE;
if(NS_FAILED(rv))
break;
message = do_QueryInterface(currentItem, &rv);
if(NS_SUCCEEDED(rv))
{
PRBool meetsCriteria;
rv = MeetsCriteria(message, &meetsCriteria);
if(NS_SUCCEEDED(rv) & meetsCriteria)
successful = PR_TRUE;
}
if(successful)
{
mCurMsg = do_QueryInterface(currentItem, &rv);
return rv;
}
}
return NS_ERROR_FAILURE;
}
nsresult nsMessageViewMessageEnumerator::MeetsCriteria(nsIMessage *message, PRBool *meetsCriteria)
{
if(!meetsCriteria)
return NS_ERROR_NULL_POINTER;
*meetsCriteria = PR_FALSE;
if(mShowStatus == nsIMessageView::eShowAll)
{
*meetsCriteria = PR_TRUE;
}
else
{
PRUint32 flags;
message->GetFlags(&flags);
if(mShowStatus == nsIMessageView::eShowRead)
*meetsCriteria = flags & MSG_FLAG_READ;
else if(mShowStatus == nsIMessageView::eShowUnread)
*meetsCriteria = !(flags & MSG_FLAG_READ);
else if(mShowStatus == nsIMessageView::eShowWatched)
*meetsCriteria = flags & MSG_FLAG_WATCHED;
}
return NS_OK;
}
////////////////////////// nsMessageViewThreadEnumerator //////////////////
NS_IMPL_ISUPPORTS1(nsMessageViewThreadEnumerator, nsISimpleEnumerator)
nsMessageViewThreadEnumerator::nsMessageViewThreadEnumerator(nsISimpleEnumerator *threads,
nsIMsgFolder *srcFolder)
{
NS_INIT_REFCNT();
mThreads = do_QueryInterface(threads);
mFolder = do_QueryInterface(srcFolder);
mNeedToPrefetch = PR_TRUE;
}
nsMessageViewThreadEnumerator::~nsMessageViewThreadEnumerator()
{
//member variables are nsCOMPtr's
}
/** Next will advance the list. will return failed if already at end
*/
NS_IMETHODIMP nsMessageViewThreadEnumerator::GetNext(nsISupports **aItem)
{
nsresult rv = NS_OK;
if(!mMessages)
return NS_ERROR_FAILURE;
if (mNeedToPrefetch)
rv = Prefetch();
if (NS_SUCCEEDED(rv) && mMessages)
rv = mMessages->GetNext(aItem);
// NS_ASSERTION(NS_SUCCEEDED(rv),"getnext shouldn't fail");
mNeedToPrefetch = PR_TRUE;
return rv;
}
nsresult nsMessageViewThreadEnumerator::Prefetch()
{
nsresult rv = NS_OK;
//then check to see if the there are no more messages in last thread
//Get the next thread
rv = mThreads->GetNext(getter_AddRefs(mCurThread));
if(NS_SUCCEEDED(rv))
{
rv = GetMessagesForCurrentThread();
mNeedToPrefetch = PR_FALSE;
}
else
mMessages = nsnull;
return rv;
}
/** return if the collection is at the end. that is the beginning following a call to Prev
* and it is the end of the list following a call to next
* @param aItem return value
*/
NS_IMETHODIMP nsMessageViewThreadEnumerator::HasMoreElements(PRBool *aResult)
{
if (!aResult)
return NS_ERROR_NULL_POINTER;
nsresult rv = NS_OK;
if (mNeedToPrefetch)
Prefetch();
//First check to see if there are no more threads
if (mMessages)
rv = mMessages->HasMoreElements(aResult);
else
*aResult = nsnull;
return rv;
}
nsresult nsMessageViewThreadEnumerator::GetMessagesForCurrentThread()
{
nsCOMPtr<nsIMsgThread> thread;
nsresult rv = NS_OK;
if(mCurThread)
{
thread = do_QueryInterface(mCurThread, &rv);
if(NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISimpleEnumerator> msgHdrs;
rv = thread->EnumerateMessages(nsMsgKey_None, getter_AddRefs(msgHdrs));
nsMessageFromMsgHdrEnumerator *messages;
NS_NewMessageFromMsgHdrEnumerator(msgHdrs, mFolder, &messages);
mMessages = do_QueryInterface(messages, &rv);
NS_IF_RELEASE(messages);
}
}
else
mMessages = nsnull;
return rv;
}

View File

@ -1,128 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef NSMESSAGEVIEWDATASOURCE_H
#define NSMESSAGEVIEWDATASOURCE_H
#include "nsIRDFCompositeDataSource.h"
#include "nsIMessageView.h"
#include "nsIMsgFolder.h"
#include "nsIRDFNode.h"
#include "nsIRDFService.h"
#include "nsISupportsArray.h"
#include "nsIEnumerator.h"
#include "nsIMessage.h"
#include "nsIMsgThread.h"
#include "nsCOMPtr.h"
/**
* The mail data source.
*/
class nsMessageViewDataSource : public nsIRDFCompositeDataSource,
public nsIRDFObserver
{
private:
nsCOMPtr<nsISupportsArray> mObservers;
PRBool mInitialized;
nsIRDFService * mRDFService;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRDFDATASOURCE
NS_DECL_NSIRDFCOMPOSITEDATASOURCE
NS_DECL_NSIRDFOBSERVER
nsMessageViewDataSource(void);
virtual ~nsMessageViewDataSource (void);
virtual nsresult Init();
protected:
nsresult createMessageNode(nsIMessage *message, nsIRDFResource *property, nsIRDFNode **target);
nsresult GetMessageEnumerator(nsIMessage* message, nsISimpleEnumerator* *result);
// caching frequently used resources
protected:
nsCOMPtr<nsIRDFDataSource> mDataSource;
PRUint32 mViewType;
PRBool mShowThreads;
static nsIRDFResource* kNC_MessageChild;
static nsIRDFResource* kNC_Subject;
static nsIRDFResource* kNC_Date;
static nsIRDFResource* kNC_Sender;
static nsIRDFResource* kNC_Status;
};
class nsMessageViewMessageEnumerator: public nsISimpleEnumerator
{
public:
NS_DECL_ISUPPORTS
nsMessageViewMessageEnumerator(nsISimpleEnumerator *srcEnumerator, PRUint32 showStatus);
virtual ~nsMessageViewMessageEnumerator();
NS_DECL_NSISIMPLEENUMERATOR
protected:
nsresult SetAtNextItem();
nsresult MeetsCriteria(nsIMessage *message, PRBool *meetsCriteria);
protected:
nsCOMPtr<nsISimpleEnumerator> mSrcEnumerator;
nsCOMPtr<nsISupports> mCurMsg;
nsCOMPtr<nsISupports> mCurThread;
PRUint32 mShowStatus;
};
class nsMessageViewThreadEnumerator: public nsISimpleEnumerator
{
public:
NS_DECL_ISUPPORTS
nsMessageViewThreadEnumerator(nsISimpleEnumerator *srcEnumerator, nsIMsgFolder *srcFolder);
virtual ~nsMessageViewThreadEnumerator();
NS_DECL_NSISIMPLEENUMERATOR
protected:
nsresult GetMessagesForCurrentThread();
nsresult Prefetch();
protected:
nsCOMPtr<nsISimpleEnumerator> mThreads;
nsCOMPtr<nsISimpleEnumerator> mMessages;
nsCOMPtr<nsISupports> mCurThread;
nsCOMPtr<nsIMsgFolder> mFolder;
PRBool mNeedToPrefetch;
};
#endif

View File

@ -45,8 +45,6 @@
#include "nsMsgBaseCID.h"
#include "nsIInputStream.h"
#include "nsMessageViewDataSource.h"
#include "nsTraceRefcnt.h"
#include "nsIMsgFolder.h" // TO include biffState enum. Change to bool later...

View File

@ -39,7 +39,6 @@
#include "nsMsgBaseCID.h"
#include "nsIMessageView.h"
#include "nsMsgUtils.h"
#include "nsMessageViewDataSource.h"
#include "nsTextFormatter.h"
@ -1825,8 +1824,6 @@ nsresult
nsMsgMessageDataSource::createMessageMessageChildNode(nsIMessage *message,
nsIRDFNode **target)
{
// this is slow, but for now, call GetTargets and then create
// a node out of the first message, if any
nsCOMPtr<nsIRDFResource> messageResource(do_QueryInterface(message));
return createMessageChildNode(messageResource, target);
}
@ -1843,15 +1840,18 @@ nsresult
nsMsgMessageDataSource::createMessageChildNode(nsIRDFResource *resource, nsIRDFNode** target)
{
nsresult rv;
nsCOMPtr<nsISimpleEnumerator> messages;
rv = GetTargets(resource, kNC_MessageChild, PR_TRUE,
getter_AddRefs(messages));
nsCOMPtr<nsIMessageView> messageView;
PRBool hasMessages;
messages->HasMoreElements(&hasMessages);
rv = GetMessageView(getter_AddRefs(messageView));
NS_ENSURE_SUCCESS(rv,rv);
if (hasMessages)
PRBool hasMessages = PR_FALSE;
rv = messageView->HasMessages(resource, mWindow, &hasMessages);
NS_ENSURE_SUCCESS(rv,rv);
if (hasMessages) {
return createNode("has messages", target, getRDFService());
}
return NS_RDF_NO_VALUE;

View File

@ -166,12 +166,34 @@ NS_IMETHODIMP nsMsgDBFolder::EndFolderLoading(void)
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::GetThreads(nsIMsgWindow *aMsgWindow, nsISimpleEnumerator** threadEnumerator)
NS_IMETHODIMP nsMsgDBFolder::HasThreads(nsIMsgWindow *aMsgWindow, PRBool *hasThreads)
{
nsresult rv = GetDatabase(aMsgWindow);
NS_ENSURE_SUCCESS(rv,rv);
rv = mDatabase->HasThreads(hasThreads);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::HasMessagesOfType(nsIMsgWindow *aMsgWindow, PRUint32 viewType, PRBool *hasMessages)
{
nsresult rv = NS_OK;
rv = GetDatabase(aMsgWindow);
NS_ENSURE_SUCCESS(rv,rv);
rv = mDatabase->HasMessagesOfType(viewType, hasMessages);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::GetThreadsOfType(nsIMsgWindow *aMsgWindow, PRUint32 viewType, nsISimpleEnumerator** threadEnumerator)
{
nsresult rv = GetDatabase(aMsgWindow);
if(NS_SUCCEEDED(rv))
return mDatabase->EnumerateThreads(threadEnumerator);
return mDatabase->EnumerateThreads(viewType, threadEnumerator);
else
return rv;
}

View File

@ -50,11 +50,13 @@ public:
virtual ~nsMsgDBFolder(void);
NS_DECL_NSIDBCHANGELISTENER
NS_IMETHOD StartFolderLoading(void);
NS_IMETHOD EndFolderLoading(void);
NS_IMETHOD GetThreads(nsIMsgWindow *aMsgWindow, nsISimpleEnumerator** threadEnumerator);
NS_IMETHOD StartFolderLoading(void);
NS_IMETHOD EndFolderLoading(void);
NS_IMETHOD GetThreadsOfType(nsIMsgWindow *aMsgWindow, PRUint32 viewType, nsISimpleEnumerator** threadEnumerator);
NS_IMETHOD GetThreadForMessage(nsIMessage *message, nsIMsgThread **thread);
NS_IMETHOD HasMessage(nsIMessage *message, PRBool *hasMessage);
NS_IMETHOD HasThreads(nsIMsgWindow *aMsgWindow, PRBool *hasThreads);
NS_IMETHOD HasMessagesOfType(nsIMsgWindow *aMsgWindow, PRUint32 viewType, PRBool *hasMessages);
NS_IMETHOD GetCharset(PRUnichar * *aCharset);
NS_IMETHOD SetCharset(const PRUnichar * aCharset);
//NS_IMETHOD HasNewMessages(PRBool *hasNewMessages);

View File

@ -435,6 +435,12 @@ NS_IMETHODIMP nsMsgFolder::GetParent(nsIFolder **aParent)
return NS_OK;
}
NS_IMETHODIMP
nsMsgFolder::HasMessagesOfType(nsIMsgWindow *aMsgWindow, PRUint32 type, PRBool *hasMessages)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsMsgFolder::GetMessages(nsIMsgWindow *aMsgWindow, nsISimpleEnumerator* *result)
{
@ -458,8 +464,14 @@ nsMsgFolder::UpdateFolder(nsIMsgWindow *)
return NS_OK;
}
NS_IMETHODIMP
nsMsgFolder::HasThreads(nsIMsgWindow *aMsgWindow, PRBool *hasThreads)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsMsgFolder::GetThreads(nsIMsgWindow *aMsgWindow, nsISimpleEnumerator ** threadEnumerator)
nsMsgFolder::GetThreadsOfType(nsIMsgWindow *aMsgWindow, PRUint32 viewType, nsISimpleEnumerator ** threadEnumerator)
{
// XXX should this return an empty enumeration?
return NS_ERROR_FAILURE;

View File

@ -67,8 +67,11 @@ public:
// begin NS_DECL_NSIMSGFOLDER
NS_IMETHOD AddUnique(nsISupports *element);
NS_IMETHOD ReplaceElement(nsISupports *element, nsISupports *newElement);
NS_IMETHOD HasMessagesOfType(nsIMsgWindow *aMsgWindow, PRUint32 viewType, PRBool *
hasMessages);
NS_IMETHOD GetMessages(nsIMsgWindow *aMsgWindow, nsISimpleEnumerator **_retval);
NS_IMETHOD GetThreads(nsIMsgWindow *aMsgWindow, nsISimpleEnumerator **_retval);
NS_IMETHOD GetThreadsOfType(nsIMsgWindow *aMsgWindow, PRUint32 viewType, nsISimpleEnumerator **_retval);
NS_IMETHOD HasThreads(nsIMsgWindow *aMsgWindow, PRBool *hasThreads);
NS_IMETHOD StartFolderLoading(void);
NS_IMETHOD EndFolderLoading(void);
NS_IMETHOD UpdateFolder(nsIMsgWindow *window);

View File

@ -106,7 +106,9 @@ interface nsIMsgDatabase : nsIDBChangeAnnouncer {
[noscript] void ListAllKeys(in nsMsgKeyArrayRef outputKeys);
nsISimpleEnumerator EnumerateMessages();
nsISimpleEnumerator EnumerateThreads();
boolean hasMessagesOfType(in unsigned long viewType);
nsISimpleEnumerator EnumerateThreads(in unsigned long viewType);
boolean hasThreads();
nsIMsgThread GetThreadContainingMsgHdr(in nsIMsgDBHdr msgHdr) ;

View File

@ -60,6 +60,8 @@ public:
virtual nsresult CreateMsgHdr(nsIMdbRow* hdrRow, nsMsgKey key, nsIMsgDBHdr **result);
virtual nsresult GetThreadForMsgKey(nsMsgKey msgKey, nsIMsgThread **result);
virtual nsresult EnumerateUnreadMessages(nsISimpleEnumerator* *result);
virtual nsresult EnumerateReadMessages(nsISimpleEnumerator* *result);
// this might just be for debugging - we'll see.
nsresult ListAllThreads(nsMsgKeyArray *threadIds);
//////////////////////////////////////////////////////////////////////////////

View File

@ -46,6 +46,8 @@
#include "nsIMsgAccountManager.h"
#include "nsIMsgFolderCache.h"
#include "nsIMsgFolderCacheElement.h"
#include "MailNewsTypes2.h"
static NS_DEFINE_CID(kCMorkFactory, NS_MORK_CID);
#if defined(XP_MAC) && defined(CompareString)
@ -623,8 +625,8 @@ nsMsgDatabase::nsMsgDatabase()
m_offlineMsgOffsetColumnToken(0),
m_offlineMessageSizeColumnToken(0),
m_HeaderParser(nsnull),
m_cachedHeaders(nsnull),
m_headersInUse(nsnull),
m_cachedHeaders(nsnull),
m_bCacheHeaders(PR_FALSE)
{
@ -2247,6 +2249,14 @@ NS_IMETHODIMP nsMsgDatabase::ListAllKeys(nsMsgKeyArray &outputKeys)
return err;
}
static nsresult
nsMsgDBThreadUnreadFilter(nsIMsgThread *thread)
{
PRUint32 numUnreadChildren = 0;
nsresult rv = thread->GetNumUnreadChildren(&numUnreadChildren);
if (NS_FAILED(rv)) return rv;
return (numUnreadChildren > 0) ? NS_OK : NS_COMFALSE;
}
class nsMsgDBThreadEnumerator : public nsISimpleEnumerator
{
@ -2257,10 +2267,10 @@ public:
NS_DECL_NSISIMPLEENUMERATOR
// nsMsgDBEnumerator methods:
typedef nsresult (*nsMsgDBThreadEnumeratorFilter)(nsIMsgThread* hdr, void* closure);
typedef nsresult (*nsMsgDBThreadEnumeratorFilter)(nsIMsgThread* thread);
nsMsgDBThreadEnumerator(nsMsgDatabase* db,
nsMsgDBThreadEnumeratorFilter filter, void* closure);
nsMsgDBThreadEnumeratorFilter filter);
virtual ~nsMsgDBThreadEnumerator();
protected:
@ -2272,13 +2282,12 @@ protected:
PRBool mDone;
PRBool mNextPrefetched;
nsMsgDBThreadEnumeratorFilter mFilter;
void* mClosure;
};
nsMsgDBThreadEnumerator::nsMsgDBThreadEnumerator(nsMsgDatabase* db,
nsMsgDBThreadEnumeratorFilter filter, void* closure)
nsMsgDBThreadEnumeratorFilter filter)
: mDB(db), mTableCursor(nsnull), mResultThread(nsnull), mDone(PR_FALSE),
mFilter(filter), mClosure(closure)
mFilter(filter)
{
NS_INIT_REFCNT();
NS_ADDREF(mDB);
@ -2370,7 +2379,7 @@ nsresult nsMsgDBThreadEnumerator::PrefetchNext()
if (numChildren == 0)
continue;
}
if (mFilter && mFilter(mResultThread, mClosure) != NS_OK)
if (mFilter && mFilter(mResultThread) != NS_OK)
continue;
else
break;
@ -2394,9 +2403,27 @@ NS_IMETHODIMP nsMsgDBThreadEnumerator::HasMoreElements(PRBool *aResult)
}
NS_IMETHODIMP
nsMsgDatabase::EnumerateThreads(nsISimpleEnumerator* *result)
nsMsgDatabase::EnumerateThreads(PRUint32 viewType, nsISimpleEnumerator* *result)
{
nsMsgDBThreadEnumerator* e = new nsMsgDBThreadEnumerator(this, nsnull, nsnull);
nsresult rv = NS_OK;
nsMsgDBThreadEnumerator* e = nsnull;
switch (viewType) {
case nsMsgViewType::eShowAll:
e = new nsMsgDBThreadEnumerator(this, nsnull);
NS_ENSURE_SUCCESS(rv,rv);
break;
case nsMsgViewType::eShowUnread:
e = new nsMsgDBThreadEnumerator(this, nsMsgDBThreadUnreadFilter);
NS_ENSURE_SUCCESS(rv,rv);
break;
case nsMsgViewType::eShowRead:
case nsMsgViewType::eShowWatched:
default:
NS_ENSURE_SUCCESS(NS_ERROR_UNEXPECTED,NS_ERROR_UNEXPECTED);
break;
}
if (e == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(e);
@ -2463,6 +2490,28 @@ nsMsgDatabase::EnumerateUnreadMessages(nsISimpleEnumerator* *result)
*result = e;
return NS_OK;
}
static nsresult
nsMsgReadFilter(nsIMsgDBHdr* msg, void* closure)
{
nsMsgDatabase* db = (nsMsgDatabase*)closure;
PRBool wasRead = PR_TRUE;
nsresult rv = db->IsHeaderRead(msg, &wasRead);
if (NS_FAILED(rv))
return rv;
return wasRead ? NS_OK : NS_COMFALSE;
}
NS_IMETHODIMP
nsMsgDatabase::EnumerateReadMessages(nsISimpleEnumerator* *result)
{
nsMsgDBEnumerator* e = new nsMsgDBEnumerator(this, nsMsgReadFilter, this);
if (e == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(e);
*result = e;
return NS_OK;
}
#endif
NS_IMETHODIMP nsMsgDatabase::CreateNewHdr(nsMsgKey key, nsIMsgDBHdr **pnewHdr)
@ -3239,21 +3288,17 @@ nsresult nsMsgDatabase::ListAllThreads(nsMsgKeyArray *threadIds)
nsresult rv;
nsMsgThread *pThread;
nsISimpleEnumerator* threads;
rv = EnumerateThreads(&threads);
if (NS_FAILED(rv))
return rv;
nsCOMPtr <nsISimpleEnumerator> threads;
rv = EnumerateThreads(nsMsgViewType::eShowAll, getter_AddRefs(threads));
if (NS_FAILED(rv)) return rv;
PRBool hasMore = PR_FALSE;
while (NS_SUCCEEDED(rv = threads->HasMoreElements(&hasMore)) && (hasMore == PR_TRUE))
{
rv = threads->GetNext((nsISupports**)&pThread);
NS_ASSERTION(NS_SUCCEEDED(rv), "nsMsgDBEnumerator broken");
if (NS_FAILED(rv))
break;
NS_ENSURE_SUCCESS(rv,rv);
if (threadIds)
{
if (threadIds) {
nsMsgKey key;
(void)pThread->GetThreadKey(&key);
threadIds->Add(key);
@ -3261,7 +3306,6 @@ nsresult nsMsgDatabase::ListAllThreads(nsMsgKeyArray *threadIds)
// NS_RELEASE(pThread);
pThread = nsnull;
}
NS_RELEASE(threads);
return rv;
}
@ -3292,6 +3336,47 @@ NS_IMETHODIMP nsMsgDatabase::GetLowWaterArticleNum(nsMsgKey *key)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgDatabase::HasMessagesOfType(PRUint32 viewType, PRBool *hasMessages)
{
nsresult rv;
nsCOMPtr <nsISimpleEnumerator> messages;
switch (viewType) {
case nsMsgViewType::eShowAll:
rv = EnumerateMessages(getter_AddRefs(messages));
NS_ENSURE_SUCCESS(rv,rv);
break;
case nsMsgViewType::eShowRead:
rv = EnumerateReadMessages(getter_AddRefs(messages));
NS_ENSURE_SUCCESS(rv,rv);
break;
case nsMsgViewType::eShowUnread:
rv = EnumerateUnreadMessages(getter_AddRefs(messages));
NS_ENSURE_SUCCESS(rv,rv);
break;
case nsMsgViewType::eShowWatched:
default:
NS_ENSURE_SUCCESS(NS_ERROR_UNEXPECTED,NS_ERROR_UNEXPECTED);
break;
}
rv = messages->HasMoreElements(hasMessages);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
NS_IMETHODIMP nsMsgDatabase::HasThreads(PRBool *hasThreads)
{
nsresult rv;
nsCOMPtr <nsISimpleEnumerator> threads;
rv = EnumerateThreads(nsMsgViewType::eShowAll, getter_AddRefs(threads));
NS_ENSURE_SUCCESS(rv,rv);
rv = threads->HasMoreElements(hasThreads);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
#ifdef DEBUG
nsresult nsMsgDatabase::DumpContents()

View File

@ -567,8 +567,7 @@ NS_IMETHODIMP nsMsgHdr::GetMessageOffset(PRUint32 *result)
NS_IMETHODIMP nsMsgHdr::SetMessageOffset(PRUint32 offset)
{
nsresult rv = SetUInt32Column(offset, m_mdb->m_offlineMsgOffsetColumnToken);
SetUInt32Column(offset, m_mdb->m_offlineMsgOffsetColumnToken);
return NS_OK;
}

View File

@ -25,6 +25,7 @@
#include "nsMsgThread.h"
#include "nsMsgDatabase.h"
#include "nsCOMPtr.h"
#include "MailNewsTypes2.h"
NS_IMPL_ISUPPORTS1(nsMsgThread, nsMsgThread)
@ -602,9 +603,9 @@ protected:
PRInt32 mChildIndex;
PRBool mDone;
PRBool mNeedToPrefetch;
PRBool mFoundChildren;
nsMsgThreadEnumeratorFilter mFilter;
void* mClosure;
PRBool mFoundChildren;
};
nsMsgThreadEnumerator::nsMsgThreadEnumerator(nsMsgThread *thread, nsMsgKey startKey,
@ -767,6 +768,11 @@ nsresult nsMsgThreadEnumerator::Prefetch()
nsMsgKey parentKey;
nsMsgKey curKey;
if (mFilter && mFilter(mResultHdr, mClosure) != NS_OK) {
mResultHdr = nsnull;
continue;
}
mResultHdr->GetThreadParent(&parentKey);
mResultHdr->GetMessageKey(&curKey);
// if the parent is the same as the msg we're enumerating over,
@ -819,6 +825,90 @@ NS_IMETHODIMP nsMsgThreadEnumerator::HasMoreElements(PRBool *aResult)
return NS_OK;
}
#if 0
// this performance optimization isn't working quite right yet.
NS_IMETHODIMP nsMsgThread::HasMessagesOfType(nsMsgKey parentKey, PRUint32 viewType, PRBool *hasMessages)
{
nsresult rv;
PRUint32 numChildren = 0;
PRUint32 numUnreadChildren = 0;
rv = GetNumChildren(&numChildren);
NS_ENSURE_SUCCESS(rv,rv);
switch (viewType) {
case nsMsgViewType::eShowAll:
// don't return true on messages without children
*hasMessages = (numChildren > 1);
break;
case nsMsgViewType::eShowUnread:
rv = GetNumUnreadChildren(&numUnreadChildren);
NS_ENSURE_SUCCESS(rv,rv);
// don't return true on messages without children
*hasMessages = ((numChildren > 1) && (numUnreadChildren > 1));
break;
case nsMsgViewType::eShowRead:
case nsMsgViewType::eShowWatched:
default:
NS_ENSURE_SUCCESS(NS_ERROR_UNEXPECTED,NS_ERROR_UNEXPECTED);
break;
}
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
#else
NS_IMETHODIMP nsMsgThread::HasMessagesOfType(nsMsgKey parentKey, PRUint32 viewType, PRBool *hasMessages)
{
nsresult rv;
nsCOMPtr <nsISimpleEnumerator> messages;
switch (viewType) {
case nsMsgViewType::eShowAll:
rv = EnumerateMessages(parentKey, getter_AddRefs(messages));
NS_ENSURE_SUCCESS(rv,rv);
break;
case nsMsgViewType::eShowUnread:
rv = EnumerateUnreadMessages(parentKey, getter_AddRefs(messages));
NS_ENSURE_SUCCESS(rv,rv);
break;
case nsMsgViewType::eShowRead:
case nsMsgViewType::eShowWatched:
default:
NS_ENSURE_SUCCESS(NS_ERROR_UNEXPECTED,NS_ERROR_UNEXPECTED);
break;
}
rv = messages->HasMoreElements(hasMessages);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
#endif
static nsresult
nsMsgThreadUnreadFilter(nsIMsgDBHdr* msg, void* closure)
{
nsMsgDatabase* db = (nsMsgDatabase*)closure;
PRBool wasRead = PR_TRUE;
nsresult rv = db->IsHeaderRead(msg, &wasRead);
if (NS_FAILED(rv))
return rv;
return !wasRead ? NS_OK : NS_COMFALSE;
}
NS_IMETHODIMP nsMsgThread::EnumerateUnreadMessages(nsMsgKey parentKey, nsISimpleEnumerator* *result)
{
nsresult ret = NS_OK;
nsMsgThreadEnumerator* e = new nsMsgThreadEnumerator(this, parentKey, nsMsgThreadUnreadFilter, m_mdbDB);
if (e == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(e);
*result = e;
return NS_OK;
return ret;
}
NS_IMETHODIMP nsMsgThread::EnumerateMessages(nsMsgKey parentKey, nsISimpleEnumerator* *result)
{

View File

@ -84,18 +84,6 @@ enum nsMsgSortType {
nsMsgSortType_Recipient
};
enum nsMsgViewType {
nsMsgViewType_Any = 0, // this view type matches any other view type,
// for the purpose of matching cached views.
// Else, it's equivalent to ViewAllThreads
nsMsgViewType_AllThreads = 1, // default view, no killed threads
nsMsgViewType_OnlyThreadsWithNew = 2,
nsMsgViewType_OnlyNewHeaders = 4,
nsMsgViewType_WatchedThreadsWithNew = 5,
nsMsgViewType_Cacheless // this would be for cacheless imap
};
/* Flags about a single message. These values are used in the MSG_MessageLine
struct and in a folder's mozilla-status line. The summary file database
should use the same set of flags..

View File

@ -37,3 +37,12 @@ interface nsMsgPriority {
const nsMsgPriorityValue highest = 6;
};
typedef long nsMsgViewTypeValue;
[scriptable, uuid(dac950b0-1dd1-11b2-be06-d4c2003a6927)]
interface nsMsgViewType {
const nsMsgViewTypeValue eShowAll = 0;
const nsMsgViewTypeValue eShowRead = 1;
const nsMsgViewTypeValue eShowUnread = 2;
const nsMsgViewTypeValue eShowWatched = 3;
};