зеркало из https://github.com/mozilla/gecko-dev.git
fix multiple msg load on multiple delete, fix thread order inside thread r=naving, sr=sspitzer 78588 and 76501
This commit is contained in:
Родитель
df74b9e7f9
Коммит
eb20295d05
|
@ -80,6 +80,7 @@ NS_INTERFACE_MAP_BEGIN(nsMsgDBView)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIMsgDBView)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDBChangeListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIOutlinerView)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMsgCopyServiceListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsMsgDBView::nsMsgDBView()
|
||||
|
@ -96,7 +97,8 @@ nsMsgDBView::nsMsgDBView()
|
|||
mIsSpecialFolder = PR_FALSE;
|
||||
mIsNews = PR_FALSE;
|
||||
mDeleteModel = nsMsgImapDeleteModels::MoveToTrash;
|
||||
|
||||
m_deletingMsgs = PR_FALSE;
|
||||
mRemovingRow = PR_FALSE;
|
||||
// initialize any static atoms or unicode strings
|
||||
if (gInstanceCount == 0)
|
||||
{
|
||||
|
@ -539,6 +541,27 @@ NS_IMETHODIMP nsMsgDBView::ReloadMessage()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsMsgDBView::UpdateDisplayMessage(nsMsgKey aMsgKey)
|
||||
{
|
||||
nsresult rv;
|
||||
if (mCommandUpdater)
|
||||
{
|
||||
// get the subject and the folder for the message and inform the front end that
|
||||
// we changed the message we are currently displaying.
|
||||
nsMsgViewIndex viewPosition = FindViewIndex(aMsgKey);
|
||||
if (viewPosition != nsMsgViewIndex_None)
|
||||
{
|
||||
nsCOMPtr <nsIMsgDBHdr> msgHdr;
|
||||
rv = GetMsgHdrForViewIndex(viewPosition, getter_AddRefs(msgHdr));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
nsXPIDLString subject;
|
||||
FetchSubject(msgHdr, m_flags[viewPosition], getter_Copies(subject));
|
||||
mCommandUpdater->DisplayMessageChanged(m_folder, subject);
|
||||
} // if view position is valid
|
||||
} // if we have an updater
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// given a msg key, we will load the message for it.
|
||||
NS_IMETHODIMP nsMsgDBView::LoadMessageByMsgKey(nsMsgKey aMsgKey)
|
||||
{
|
||||
|
@ -552,27 +575,13 @@ NS_IMETHODIMP nsMsgDBView::LoadMessageByMsgKey(nsMsgKey aMsgKey)
|
|||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
mMessengerInstance->OpenURL(uri);
|
||||
m_currentlyDisplayedMsgKey = aMsgKey;
|
||||
|
||||
if (mCommandUpdater)
|
||||
{
|
||||
// get the subject and the folder for the message and inform the front end that
|
||||
// we changed the message we are currently displaying.
|
||||
nsMsgViewIndex viewPosition = FindViewIndex(aMsgKey);
|
||||
if (viewPosition != nsMsgViewIndex_None)
|
||||
{
|
||||
nsCOMPtr <nsIMsgDBHdr> msgHdr;
|
||||
rv = GetMsgHdrForViewIndex(viewPosition, getter_AddRefs(msgHdr));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
nsXPIDLString subject;
|
||||
FetchSubject(msgHdr, m_flags[viewPosition], getter_Copies(subject));
|
||||
mCommandUpdater->DisplayMessageChanged(m_folder, subject);
|
||||
} // if view position is valid
|
||||
} // if we have an updater
|
||||
UpdateDisplayMessage(aMsgKey);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsMsgDBView::SelectionChanged()
|
||||
{
|
||||
// if the currentSelection changed then we have a message to display
|
||||
|
@ -580,7 +589,7 @@ NS_IMETHODIMP nsMsgDBView::SelectionChanged()
|
|||
GetNumSelected(&numSelected);
|
||||
|
||||
// if only one item is selected then we want to display a message
|
||||
if (numSelected == 1 && !mSupressMsgDisplay)
|
||||
if (numSelected == 1)
|
||||
{
|
||||
PRInt32 startRange;
|
||||
PRInt32 endRange;
|
||||
|
@ -591,7 +600,13 @@ NS_IMETHODIMP nsMsgDBView::SelectionChanged()
|
|||
{
|
||||
// get the msgkey for the message
|
||||
nsMsgKey msgkey = m_keys.GetAt(startRange);
|
||||
LoadMessageByMsgKey(msgkey);
|
||||
if (!mRemovingRow)
|
||||
{
|
||||
if (!mSupressMsgDisplay)
|
||||
LoadMessageByMsgKey(msgkey);
|
||||
else
|
||||
UpdateDisplayMessage(msgkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1381,7 +1396,8 @@ nsMsgDBView::CopyMessages(nsIMsgWindow *window, nsMsgViewIndex *indices, PRInt32
|
|||
if (msgHdr)
|
||||
messageArray->AppendElement(msgHdr);
|
||||
}
|
||||
rv = destFolder->CopyMessages(m_folder /* source folder */, messageArray, isMove, window, nsnull /* listener */, PR_FALSE /* isFolder */);
|
||||
m_deletingMsgs = isMove;
|
||||
rv = destFolder->CopyMessages(m_folder /* source folder */, messageArray, isMove, window, this /* listener */, PR_FALSE /* isFolder */);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1535,7 +1551,8 @@ nsresult nsMsgDBView::DeleteMessages(nsIMsgWindow *window, nsMsgViewIndex *indic
|
|||
messageArray->AppendElement(msgHdr);
|
||||
|
||||
}
|
||||
m_folder->DeleteMessages(messageArray, window, deleteStorage, PR_FALSE, nsnull);
|
||||
m_deletingMsgs = PR_TRUE;
|
||||
m_folder->DeleteMessages(messageArray, window, deleteStorage, PR_FALSE, this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -2758,6 +2775,8 @@ nsresult nsMsgDBView::GetThreadContainingIndex(nsMsgViewIndex index, nsIMsgThrea
|
|||
{
|
||||
nsCOMPtr <nsIMsgDBHdr> msgHdr;
|
||||
|
||||
NS_ENSURE_TRUE(m_db, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsresult rv = m_db->GetMsgHdrForKey(m_keys[index], getter_AddRefs(msgHdr));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return m_db->GetThreadContainingMsgHdr(msgHdr, resultThread);
|
||||
|
@ -3048,47 +3067,89 @@ PRInt32 nsMsgDBView::FindLevelInThread(nsIMsgDBHdr *msgHdr, nsMsgViewIndex start
|
|||
}
|
||||
}
|
||||
|
||||
nsresult nsMsgDBView::ListIdsInThread(nsIMsgThread *threadHdr, nsMsgViewIndex startOfThreadViewIndex, PRUint32 *pNumListed)
|
||||
nsresult nsMsgDBView::ListIdsInThreadOrder(nsIMsgThread *threadHdr, nsMsgKey parentKey, PRInt32 level, nsMsgViewIndex *viewIndex, PRUint32 *pNumListed)
|
||||
{
|
||||
NS_ENSURE_ARG(threadHdr);
|
||||
// these children ids should be in thread order.
|
||||
PRUint32 i;
|
||||
nsMsgViewIndex viewIndex = startOfThreadViewIndex + 1;
|
||||
*pNumListed = 0;
|
||||
|
||||
PRUint32 numChildren;
|
||||
threadHdr->GetNumChildren(&numChildren);
|
||||
for (i = 1; i < numChildren; i++)
|
||||
{
|
||||
nsCOMPtr <nsIMsgDBHdr> msgHdr;
|
||||
threadHdr->GetChildHdrAt(i, getter_AddRefs(msgHdr));
|
||||
if (msgHdr != nsnull)
|
||||
{
|
||||
nsCOMPtr <nsISimpleEnumerator> msgEnumerator;
|
||||
threadHdr->EnumerateMessages(parentKey, getter_AddRefs(msgEnumerator));
|
||||
// skip the first one.
|
||||
PRBool hasMore;
|
||||
nsCOMPtr <nsISupports> supports;
|
||||
nsCOMPtr <nsIMsgDBHdr> msgHdr;
|
||||
nsresult rv;
|
||||
while (NS_SUCCEEDED(rv = msgEnumerator->HasMoreElements(&hasMore)) && (hasMore == PR_TRUE))
|
||||
{
|
||||
rv = msgEnumerator->GetNext(getter_AddRefs(supports));
|
||||
if (NS_SUCCEEDED(rv) && supports)
|
||||
{
|
||||
msgHdr = do_QueryInterface(supports);
|
||||
nsMsgKey msgKey;
|
||||
PRUint32 msgFlags, newFlags;
|
||||
msgHdr->GetMessageKey(&msgKey);
|
||||
msgHdr->GetFlags(&msgFlags);
|
||||
PRBool isRead = PR_FALSE;
|
||||
m_db->IsRead(msgKey, &isRead);
|
||||
// just make sure flag is right in db.
|
||||
m_db->MarkHdrRead(msgHdr, isRead, nsnull);
|
||||
// if (isRead)
|
||||
// msgHdr->m_flags |= MSG_FLAG_READ;
|
||||
// else
|
||||
// msgHdr->m_flags &= ~MSG_FLAG_READ;
|
||||
m_keys.InsertAt(viewIndex, msgKey);
|
||||
PRBool isRead = PR_FALSE;
|
||||
m_db->IsRead(msgKey, &isRead);
|
||||
// just make sure flag is right in db.
|
||||
m_db->MarkHdrRead(msgHdr, isRead, nsnull);
|
||||
m_keys.InsertAt(*viewIndex, msgKey);
|
||||
// ### TODO - how about hasChildren flag?
|
||||
m_flags.InsertAt(viewIndex, msgFlags & ~MSG_VIEW_FLAGS);
|
||||
m_flags.InsertAt(*viewIndex, msgFlags & ~MSG_VIEW_FLAGS);
|
||||
// ### TODO this is going to be tricky - might use enumerators
|
||||
m_levels.InsertAt(*viewIndex, level);
|
||||
// turn off thread or elided bit if they got turned on (maybe from new only view?)
|
||||
msgHdr->AndFlags(~(MSG_VIEW_FLAG_ISTHREAD | MSG_FLAG_ELIDED), &newFlags);
|
||||
(*pNumListed)++;
|
||||
(*viewIndex)++;
|
||||
ListIdsInThreadOrder(threadHdr, msgKey, level + 1, viewIndex, pNumListed);
|
||||
}
|
||||
}
|
||||
return NS_OK; // we don't want to return the rv from the enumerator when it reaches the end, do we?
|
||||
}
|
||||
|
||||
nsresult nsMsgDBView::ListIdsInThread(nsIMsgThread *threadHdr, nsMsgViewIndex startOfThreadViewIndex, PRUint32 *pNumListed)
|
||||
{
|
||||
NS_ENSURE_ARG(threadHdr);
|
||||
// these children ids should be in thread order.
|
||||
PRUint32 i;
|
||||
nsMsgViewIndex viewIndex = startOfThreadViewIndex + 1;
|
||||
*pNumListed = 0;
|
||||
|
||||
if (m_viewFlags & nsMsgViewFlagsType::kThreadedDisplay)
|
||||
{
|
||||
nsMsgKey parentKey = m_keys[startOfThreadViewIndex];
|
||||
|
||||
return ListIdsInThreadOrder(threadHdr, parentKey, 1, &viewIndex, pNumListed);
|
||||
}
|
||||
// if we're not threaded, just list em out in db order
|
||||
|
||||
PRUint32 numChildren;
|
||||
threadHdr->GetNumChildren(&numChildren);
|
||||
for (i = 1; i < numChildren; i++)
|
||||
{
|
||||
nsCOMPtr <nsIMsgDBHdr> msgHdr;
|
||||
threadHdr->GetChildHdrAt(i, getter_AddRefs(msgHdr));
|
||||
if (msgHdr != nsnull)
|
||||
{
|
||||
nsMsgKey msgKey;
|
||||
PRUint32 msgFlags, newFlags;
|
||||
msgHdr->GetMessageKey(&msgKey);
|
||||
msgHdr->GetFlags(&msgFlags);
|
||||
PRBool isRead = PR_FALSE;
|
||||
m_db->IsRead(msgKey, &isRead);
|
||||
// just make sure flag is right in db.
|
||||
m_db->MarkHdrRead(msgHdr, isRead, nsnull);
|
||||
m_keys.InsertAt(viewIndex, msgKey);
|
||||
// ### TODO - how about hasChildren flag?
|
||||
m_flags.InsertAt(viewIndex, msgFlags & ~MSG_VIEW_FLAGS);
|
||||
// ### TODO this is going to be tricky - might use enumerators
|
||||
PRInt32 level = FindLevelInThread(msgHdr, startOfThreadViewIndex);
|
||||
m_levels.InsertAt(viewIndex, level);
|
||||
// turn off thread or elided bit if they got turned on (maybe from new only view?)
|
||||
if (i > 0)
|
||||
msgHdr->AndFlags(~(MSG_VIEW_FLAG_ISTHREAD | MSG_FLAG_ELIDED), &newFlags);
|
||||
(*pNumListed)++;
|
||||
m_levels.InsertAt(viewIndex, level);
|
||||
// turn off thread or elided bit if they got turned on (maybe from new only view?)
|
||||
if (i > 0)
|
||||
msgHdr->AndFlags(~(MSG_VIEW_FLAG_ISTHREAD | MSG_FLAG_ELIDED), &newFlags);
|
||||
(*pNumListed)++;
|
||||
viewIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3311,7 +3372,10 @@ void nsMsgDBView::NoteChange(nsMsgViewIndex firstLineChanged, PRInt32 numChanged
|
|||
mOutliner->InvalidateRange(firstLineChanged, firstLineChanged + numChanged - 1);
|
||||
break;
|
||||
case nsMsgViewNotificationCode::insertOrDelete:
|
||||
if (numChanged < 0)
|
||||
mRemovingRow = PR_TRUE;
|
||||
mOutliner->RowCountChanged(firstLineChanged, numChanged);
|
||||
mRemovingRow = PR_FALSE;
|
||||
case nsMsgViewNotificationCode::all:
|
||||
ClearHdrCache();
|
||||
break;
|
||||
|
@ -4122,6 +4186,42 @@ nsMsgDBView::GetURIForFirstSelectedMessage(char **uri)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIMsgCopyServiceListener methods
|
||||
NS_IMETHODIMP
|
||||
nsMsgDBView::OnStartCopy()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgDBView::OnProgress(PRUint32 aProgress, PRUint32 aProgressMax)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// believe it or not, these next two are msgcopyservice listener methods!
|
||||
NS_IMETHODIMP
|
||||
nsMsgDBView::SetMessageKey(PRUint32 aMessageKey)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgDBView::GetMessageId(nsCString* aMessageId)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgDBView::OnStopCopy(nsresult aStatus)
|
||||
{
|
||||
m_deletingMsgs = PR_FALSE;
|
||||
m_removedIndices.RemoveAll();
|
||||
return NS_OK;
|
||||
}
|
||||
// end nsIMsgCopyServiceListener methods
|
||||
|
||||
|
||||
nsresult
|
||||
nsMsgDBView::GetKeyForFirstSelectedMessage(nsMsgKey *key)
|
||||
{
|
||||
|
|
|
@ -61,7 +61,7 @@ enum eFieldType {
|
|||
// I think this will be an abstract implementation class.
|
||||
// The classes that implement the outliner support will probably
|
||||
// inherit from this class.
|
||||
class nsMsgDBView : public nsIMsgDBView, public nsIDBChangeListener, public nsIOutlinerView
|
||||
class nsMsgDBView : public nsIMsgDBView, public nsIDBChangeListener, public nsIOutlinerView, public nsIMsgCopyServiceListener
|
||||
{
|
||||
public:
|
||||
nsMsgDBView();
|
||||
|
@ -71,6 +71,7 @@ public:
|
|||
NS_DECL_NSIMSGDBVIEW
|
||||
NS_DECL_NSIDBCHANGELISTENER
|
||||
NS_DECL_NSIOUTLINERVIEW
|
||||
NS_DECL_NSIMSGCOPYSERVICELISTENER
|
||||
|
||||
protected:
|
||||
static nsrefcnt gInstanceCount;
|
||||
|
@ -106,7 +107,8 @@ protected:
|
|||
nsCOMPtr<nsIOutlinerSelection> mOutlinerSelection;
|
||||
PRUint32 mNumSelectedRows; // we cache this to determine when to push command status notifications.
|
||||
PRBool mSupressMsgDisplay; // set when the message pane is collapsed
|
||||
|
||||
PRBool mRemovingRow; // set when we're telling the outline a row is being removed. used to supress msg loading.
|
||||
// during delete/move operations.
|
||||
virtual const char * GetViewName(void) {return "MsgDBView"; }
|
||||
nsresult FetchAuthor(nsIMsgHdr * aHdr, PRUnichar ** aAuthorString);
|
||||
nsresult FetchSubject(nsIMsgHdr * aMsgHdr, PRUint32 aFlags, PRUnichar ** aValue);
|
||||
|
@ -174,9 +176,10 @@ protected:
|
|||
virtual nsresult GetDBForViewIndex(nsMsgViewIndex index, nsIMsgDatabase **db);
|
||||
virtual nsresult GetFolders(nsISupportsArray **folders);
|
||||
|
||||
nsresult ListIdsInThread(nsIMsgThread *threadHdr, nsMsgViewIndex viewIndex, PRUint32 *pNumListed);
|
||||
nsresult ListUnreadIdsInThread(nsIMsgThread *threadHdr, nsMsgViewIndex startOfThreadViewIndex, PRUint32 *pNumListed);
|
||||
PRInt32 FindLevelInThread(nsIMsgDBHdr *msgHdr, nsMsgViewIndex startOfThreadViewIndex);
|
||||
nsresult ListIdsInThread(nsIMsgThread *threadHdr, nsMsgViewIndex viewIndex, PRUint32 *pNumListed);
|
||||
nsresult ListUnreadIdsInThread(nsIMsgThread *threadHdr, nsMsgViewIndex startOfThreadViewIndex, PRUint32 *pNumListed);
|
||||
PRInt32 FindLevelInThread(nsIMsgDBHdr *msgHdr, nsMsgViewIndex startOfThreadViewIndex);
|
||||
nsresult ListIdsInThreadOrder(nsIMsgThread *threadHdr, nsMsgKey parentKey, PRInt32 level, nsMsgViewIndex *viewIndex, PRUint32 *pNumListed);
|
||||
PRInt32 GetSize(void) {return(m_keys.GetSize());}
|
||||
|
||||
// notification api's
|
||||
|
@ -243,6 +246,8 @@ protected:
|
|||
void InitializeAtomsAndLiterals();
|
||||
PRInt32 GetLevelInUnreadView(nsIMsgDBHdr *msgHdr, nsMsgViewIndex startOfThread, nsMsgViewIndex viewIndex);
|
||||
nsresult GetImapDeleteModel(nsIMsgFolder *folder);
|
||||
nsresult UpdateDisplayMessage(nsMsgKey aMsgKey);
|
||||
|
||||
|
||||
void FreeAll(nsVoidArray *ptrs);
|
||||
void ClearHdrCache();
|
||||
|
@ -258,6 +263,11 @@ protected:
|
|||
// we need to store the message key for the message we are currenty displaying to ensure we
|
||||
// don't try to redisplay the same message just because the selection changed (i.e. after a sort)
|
||||
nsMsgKey m_currentlyDisplayedMsgKey;
|
||||
// if we're deleting messages, we want to hold off loading messages on selection changed until the delete is done
|
||||
// and we want to batch notifications.
|
||||
PRBool m_deletingMsgs;
|
||||
// used for batching deletes
|
||||
nsUInt32Array m_removedIndices;
|
||||
|
||||
nsCOMPtr <nsIMsgFolder> m_folder;
|
||||
PRBool mIsSpecialFolder; // for special folders, the Sender column really shows recipients.
|
||||
|
|
|
@ -50,7 +50,6 @@ NS_IMPL_ADDREF_INHERITED(nsMsgSearchDBView, nsMsgDBView)
|
|||
NS_IMPL_RELEASE_INHERITED(nsMsgSearchDBView, nsMsgDBView)
|
||||
NS_IMPL_QUERY_HEAD(nsMsgSearchDBView)
|
||||
NS_IMPL_QUERY_BODY(nsIMsgSearchNotify)
|
||||
NS_IMPL_QUERY_BODY(nsIMsgCopyServiceListener)
|
||||
NS_IMPL_QUERY_TAIL_INHERITING(nsMsgDBView)
|
||||
|
||||
|
||||
|
@ -341,28 +340,7 @@ nsMsgSearchDBView::InitializeGlobalsForDeleteAndFile(nsMsgViewIndex *indices, PR
|
|||
|
||||
}
|
||||
|
||||
// nsIMsgCopyServiceListener methods
|
||||
nsresult
|
||||
nsMsgSearchDBView::OnStartCopy()
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
printf("nsIMsgCopyServiceListener::OnStartCopy()\n");
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMsgSearchDBView::OnProgress(PRUint32 aProgress, PRUint32 aProgressMax)
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
printf("nsIMsgCopyServiceListener::OnProgress() - COPY\n");
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_IMETHODIMP
|
||||
nsMsgSearchDBView::OnStopCopy(nsresult aStatus)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
@ -379,19 +357,6 @@ nsMsgSearchDBView::OnStopCopy(nsresult aStatus)
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMsgSearchDBView::SetMessageKey(PRUint32 aMessageKey)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMsgSearchDBView::GetMessageId(nsCString* aMessageId)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
// end nsIMsgCopyServiceListener methods
|
||||
|
||||
nsresult nsMsgSearchDBView::ProcessRequestsInOneFolder(nsIMsgWindow *window)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
|
|
@ -27,17 +27,16 @@
|
|||
#include "nsIMsgSearchNotify.h"
|
||||
#include "nsIMsgCopyServiceListener.h"
|
||||
|
||||
class nsMsgSearchDBView : public nsMsgDBView, public nsIMsgSearchNotify, public nsIMsgCopyServiceListener
|
||||
class nsMsgSearchDBView : public nsMsgDBView, public nsIMsgSearchNotify
|
||||
{
|
||||
public:
|
||||
nsMsgSearchDBView();
|
||||
virtual ~nsMsgSearchDBView();
|
||||
nsMsgSearchDBView();
|
||||
virtual ~nsMsgSearchDBView();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIMSGSEARCHNOTIFY
|
||||
NS_DECL_NSIMSGCOPYSERVICELISTENER
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIMSGSEARCHNOTIFY
|
||||
|
||||
virtual const char * GetViewName(void) {return "SearchView"; }
|
||||
virtual const char * GetViewName(void) {return "SearchView"; }
|
||||
NS_IMETHOD Open(nsIMsgFolder *folder, nsMsgViewSortTypeValue sortType, nsMsgViewSortOrderValue sortOrder,
|
||||
nsMsgViewFlagsTypeValue viewFlags, PRInt32 *pCount);
|
||||
NS_IMETHOD Close();
|
||||
|
@ -48,6 +47,10 @@ public:
|
|||
NS_IMETHOD GetCellText(PRInt32 aRow, const PRUnichar * aColID, PRUnichar ** aValue);
|
||||
virtual nsresult GetMsgHdrForViewIndex(nsMsgViewIndex index, nsIMsgDBHdr **msgHdr);
|
||||
NS_IMETHOD GetFolderForViewIndex(nsMsgViewIndex index, nsIMsgFolder **folder);
|
||||
|
||||
// override to chain move/copies from next folder in search results
|
||||
NS_IMETHOD OnStopCopy(nsresult aStatus);
|
||||
|
||||
virtual nsresult GetFolders(nsISupportsArray **aFolders);
|
||||
protected:
|
||||
nsresult FetchLocation(PRInt32 aRow, PRUnichar ** aLocationString);
|
||||
|
|
|
@ -69,7 +69,7 @@ nsresult nsMsgThreadedDBView::InitThreadedView(PRInt32 *pCount)
|
|||
nsMsgKey startMsg = 0;
|
||||
do
|
||||
{
|
||||
const PRInt32 kIdChunkSize = 200;
|
||||
const PRInt32 kIdChunkSize = 400;
|
||||
PRInt32 numListed = 0;
|
||||
nsMsgKey idArray[kIdChunkSize];
|
||||
PRInt32 flagArray[kIdChunkSize];
|
||||
|
@ -125,78 +125,80 @@ nsresult nsMsgThreadedDBView::AddKeys(nsMsgKey *pKeys, PRInt32 *pFlags, const ch
|
|||
|
||||
NS_IMETHODIMP nsMsgThreadedDBView::Sort(nsMsgViewSortTypeValue sortType, nsMsgViewSortOrderValue sortOrder)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsMsgKeyArray preservedSelection;
|
||||
SaveSelection(&preservedSelection);
|
||||
|
||||
PRInt32 rowCountBeforeSort = GetSize();
|
||||
|
||||
// if the client wants us to forget our cached id arrays, they
|
||||
// should build a new view. If this isn't good enough, we
|
||||
// need a method to do that.
|
||||
if (sortType != m_sortType || !m_sortValid)
|
||||
{
|
||||
if (sortType == nsMsgViewSortType::byThread)
|
||||
{
|
||||
m_sortType = sortType;
|
||||
m_viewFlags |= nsMsgViewFlagsType::kThreadedDisplay;
|
||||
if ( m_havePrevView)
|
||||
{
|
||||
// restore saved id array and flags array
|
||||
m_keys.RemoveAll();
|
||||
m_keys.InsertAt(0, &m_prevKeys);
|
||||
m_flags.RemoveAll();
|
||||
m_flags.InsertAt(0, &m_prevFlags);
|
||||
m_levels.RemoveAll();
|
||||
m_levels.InsertAt(0, &m_prevLevels);
|
||||
// m_messageDB->SetSortInfo(sortType, sortOrder);
|
||||
m_sortValid = PR_TRUE;
|
||||
|
||||
// the sort may have changed the number of rows
|
||||
// before we restore the selection, tell the outliner
|
||||
// do this before we call restore selection
|
||||
// this is safe when there is no selection.
|
||||
rv = AdjustRowCount(rowCountBeforeSort, GetSize());
|
||||
|
||||
RestoreSelection(&preservedSelection);
|
||||
if (mOutliner) mOutliner->Invalidate();
|
||||
return NS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set sort info in anticipation of what Init will do.
|
||||
InitThreadedView(nsnull); // build up thread list.
|
||||
if (sortOrder != nsMsgViewSortOrder::ascending)
|
||||
Sort(sortType, sortOrder);
|
||||
|
||||
// the sort may have changed the number of rows
|
||||
// before we update the selection, tell the outliner
|
||||
// do this before we call restore selection
|
||||
// this is safe when there is no selection.
|
||||
rv = AdjustRowCount(rowCountBeforeSort, GetSize());
|
||||
|
||||
RestoreSelection(&preservedSelection);
|
||||
if (mOutliner) mOutliner->Invalidate();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
else if (sortType != nsMsgViewSortType::byThread && m_sortType == nsMsgViewSortType::byThread /* && !m_havePrevView*/)
|
||||
{
|
||||
// going from SortByThread to non-thread sort - must build new key, level,and flags arrays
|
||||
m_prevKeys.RemoveAll();
|
||||
m_prevKeys.InsertAt(0, &m_keys);
|
||||
m_prevFlags.RemoveAll();
|
||||
m_prevFlags.InsertAt(0, &m_flags);
|
||||
m_prevLevels.RemoveAll();
|
||||
m_prevLevels.InsertAt(0, &m_levels);
|
||||
ExpandAll();
|
||||
// m_idArray.RemoveAll();
|
||||
// m_flags.RemoveAll();
|
||||
m_havePrevView = PR_TRUE;
|
||||
m_viewFlags &= ~nsMsgViewFlagsType::kThreadedDisplay;
|
||||
}
|
||||
}
|
||||
nsresult rv;
|
||||
|
||||
nsMsgKeyArray preservedSelection;
|
||||
SaveSelection(&preservedSelection);
|
||||
|
||||
PRInt32 rowCountBeforeSort = GetSize();
|
||||
|
||||
// if the client wants us to forget our cached id arrays, they
|
||||
// should build a new view. If this isn't good enough, we
|
||||
// need a method to do that.
|
||||
if (sortType != m_sortType || !m_sortValid)
|
||||
{
|
||||
if (sortType == nsMsgViewSortType::byThread)
|
||||
{
|
||||
m_sortType = sortType;
|
||||
m_viewFlags |= nsMsgViewFlagsType::kThreadedDisplay;
|
||||
if ( m_havePrevView)
|
||||
{
|
||||
// restore saved id array and flags array
|
||||
m_keys.RemoveAll();
|
||||
m_keys.InsertAt(0, &m_prevKeys);
|
||||
m_flags.RemoveAll();
|
||||
m_flags.InsertAt(0, &m_prevFlags);
|
||||
m_levels.RemoveAll();
|
||||
m_levels.InsertAt(0, &m_prevLevels);
|
||||
// m_messageDB->SetSortInfo(sortType, sortOrder);
|
||||
m_sortValid = PR_TRUE;
|
||||
|
||||
// the sort may have changed the number of rows
|
||||
// before we restore the selection, tell the outliner
|
||||
// do this before we call restore selection
|
||||
// this is safe when there is no selection.
|
||||
rv = AdjustRowCount(rowCountBeforeSort, GetSize());
|
||||
|
||||
RestoreSelection(&preservedSelection);
|
||||
if (mOutliner) mOutliner->Invalidate();
|
||||
return NS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set sort info in anticipation of what Init will do.
|
||||
InitThreadedView(nsnull); // build up thread list.
|
||||
if (sortOrder != nsMsgViewSortOrder::ascending)
|
||||
Sort(sortType, sortOrder);
|
||||
|
||||
// the sort may have changed the number of rows
|
||||
// before we update the selection, tell the outliner
|
||||
// do this before we call restore selection
|
||||
// this is safe when there is no selection.
|
||||
rv = AdjustRowCount(rowCountBeforeSort, GetSize());
|
||||
|
||||
RestoreSelection(&preservedSelection);
|
||||
if (mOutliner) mOutliner->Invalidate();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
else if (sortType != nsMsgViewSortType::byThread && m_sortType == nsMsgViewSortType::byThread /* && !m_havePrevView*/)
|
||||
{
|
||||
// going from SortByThread to non-thread sort - must build new key, level,and flags arrays
|
||||
m_prevKeys.RemoveAll();
|
||||
m_prevKeys.InsertAt(0, &m_keys);
|
||||
m_prevFlags.RemoveAll();
|
||||
m_prevFlags.InsertAt(0, &m_flags);
|
||||
m_prevLevels.RemoveAll();
|
||||
m_prevLevels.InsertAt(0, &m_levels);
|
||||
// do this before we sort, so that we'll use the cheap method
|
||||
// of expanding.
|
||||
m_viewFlags &= ~nsMsgViewFlagsType::kThreadedDisplay;
|
||||
ExpandAll();
|
||||
// m_idArray.RemoveAll();
|
||||
// m_flags.RemoveAll();
|
||||
m_havePrevView = PR_TRUE;
|
||||
}
|
||||
}
|
||||
// call the base class in case we're not sorting by thread
|
||||
rv = nsMsgDBView::Sort(sortType, sortOrder);
|
||||
|
||||
|
@ -217,30 +219,30 @@ NS_IMETHODIMP nsMsgThreadedDBView::Sort(nsMsgViewSortTypeValue sortType, nsMsgVi
|
|||
nsresult nsMsgThreadedDBView::ListThreadIds(nsMsgKey *startMsg, PRBool unreadOnly, nsMsgKey *pOutput, PRInt32 *pFlags, char *pLevels,
|
||||
PRInt32 numToList, PRInt32 *pNumListed, PRInt32 *pTotalHeaders)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
// N.B..don't ret before assigning numListed to *pNumListed
|
||||
PRInt32 numListed = 0;
|
||||
|
||||
if (*startMsg > 0)
|
||||
{
|
||||
NS_ASSERTION(m_threadEnumerator != nsnull, "where's our iterator?"); // for now, we'll just have to rely on the caller leaving
|
||||
// the iterator in the right place.
|
||||
}
|
||||
else
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
// N.B..don't ret before assigning numListed to *pNumListed
|
||||
PRInt32 numListed = 0;
|
||||
|
||||
if (*startMsg > 0)
|
||||
{
|
||||
NS_ASSERTION(m_threadEnumerator != nsnull, "where's our iterator?"); // for now, we'll just have to rely on the caller leaving
|
||||
// the iterator in the right place.
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(m_db, "no db");
|
||||
if (!m_db) return NS_ERROR_UNEXPECTED;
|
||||
rv = m_db->EnumerateThreads(getter_AddRefs(m_threadEnumerator));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
PRBool hasMore = PR_FALSE;
|
||||
|
||||
}
|
||||
|
||||
PRBool hasMore = PR_FALSE;
|
||||
|
||||
nsCOMPtr <nsIMsgThread> threadHdr ;
|
||||
PRInt32 threadsRemoved = 0;
|
||||
for (numListed = 0; numListed < numToList
|
||||
PRInt32 threadsRemoved = 0;
|
||||
for (numListed = 0; numListed < numToList
|
||||
&& NS_SUCCEEDED(rv = m_threadEnumerator->HasMoreElements(&hasMore)) && (hasMore == PR_TRUE);)
|
||||
{
|
||||
{
|
||||
nsCOMPtr <nsISupports> supports;
|
||||
rv = m_threadEnumerator->GetNext(getter_AddRefs(supports));
|
||||
if (!NS_SUCCEEDED(rv))
|
||||
|
@ -257,18 +259,18 @@ nsresult nsMsgThreadedDBView::ListThreadIds(nsMsgKey *startMsg, PRBool unreadOnl
|
|||
threadHdr->GetNumUnreadChildren(&numChildren);
|
||||
else
|
||||
threadHdr->GetNumChildren(&numChildren);
|
||||
PRUint32 threadFlags;
|
||||
PRUint32 threadFlags;
|
||||
threadHdr->GetFlags(&threadFlags);
|
||||
if (numChildren != 0) // not empty thread
|
||||
{
|
||||
if (pTotalHeaders)
|
||||
*pTotalHeaders += numChildren;
|
||||
if (unreadOnly)
|
||||
rv = threadHdr->GetFirstUnreadChild(getter_AddRefs(msgHdr));
|
||||
else
|
||||
rv = threadHdr->GetChildAt(0, getter_AddRefs(msgHdr));
|
||||
if (NS_SUCCEEDED(rv) && msgHdr != nsnull && WantsThisThread(threadHdr))
|
||||
{
|
||||
if (numChildren != 0) // not empty thread
|
||||
{
|
||||
if (pTotalHeaders)
|
||||
*pTotalHeaders += numChildren;
|
||||
if (unreadOnly)
|
||||
rv = threadHdr->GetFirstUnreadChild(getter_AddRefs(msgHdr));
|
||||
else
|
||||
rv = threadHdr->GetChildAt(0, getter_AddRefs(msgHdr));
|
||||
if (NS_SUCCEEDED(rv) && msgHdr != nsnull && WantsThisThread(threadHdr))
|
||||
{
|
||||
PRUint32 msgFlags;
|
||||
PRUint32 newMsgFlags;
|
||||
nsMsgKey msgKey;
|
||||
|
@ -276,49 +278,49 @@ nsresult nsMsgThreadedDBView::ListThreadIds(nsMsgKey *startMsg, PRBool unreadOnl
|
|||
msgHdr->GetFlags(&msgFlags);
|
||||
// turn off high byte of msg flags - used for view flags.
|
||||
msgFlags &= ~MSG_VIEW_FLAGS;
|
||||
pOutput[numListed] = msgKey;
|
||||
pLevels[numListed] = 0;
|
||||
// DMB TODO - This will do for now...Until we decide how to
|
||||
// handle thread flags vs. message flags, if we do decide
|
||||
// to make them different.
|
||||
msgHdr->OrFlags(threadFlags & (MSG_FLAG_WATCHED | MSG_FLAG_IGNORED), &newMsgFlags);
|
||||
PRBool isRead = PR_FALSE;
|
||||
|
||||
// make sure DB agrees with newsrc, if we're news.
|
||||
m_db->IsRead(msgKey, &isRead);
|
||||
m_db->MarkHdrRead(msgHdr, isRead, nsnull);
|
||||
// try adding in MSG_VIEW_FLAG_ISTHREAD flag for unreadonly view.
|
||||
pFlags[numListed] = msgFlags | MSG_VIEW_FLAG_ISTHREAD | threadFlags;
|
||||
if (numChildren > 1)
|
||||
pFlags[numListed] |= MSG_VIEW_FLAG_HASCHILDREN;
|
||||
|
||||
numListed++;
|
||||
}
|
||||
// else
|
||||
// NS_ASSERTION(NS_SUCCEEDED(rv) && msgHdr, "couldn't get header for some reason");
|
||||
}
|
||||
else if (threadsRemoved < 10 && !(threadFlags & (MSG_FLAG_WATCHED | MSG_FLAG_IGNORED)))
|
||||
{
|
||||
// ### remove thread.
|
||||
threadsRemoved++; // don't want to remove all empty threads first time
|
||||
// around as it will choke preformance for upgrade.
|
||||
pOutput[numListed] = msgKey;
|
||||
pLevels[numListed] = 0;
|
||||
// DMB TODO - This will do for now...Until we decide how to
|
||||
// handle thread flags vs. message flags, if we do decide
|
||||
// to make them different.
|
||||
msgHdr->OrFlags(threadFlags & (MSG_FLAG_WATCHED | MSG_FLAG_IGNORED), &newMsgFlags);
|
||||
PRBool isRead = PR_FALSE;
|
||||
|
||||
// make sure DB agrees with newsrc, if we're news.
|
||||
m_db->IsRead(msgKey, &isRead);
|
||||
m_db->MarkHdrRead(msgHdr, isRead, nsnull);
|
||||
// try adding in MSG_VIEW_FLAG_ISTHREAD flag for unreadonly view.
|
||||
pFlags[numListed] = msgFlags | MSG_VIEW_FLAG_ISTHREAD | threadFlags;
|
||||
if (numChildren > 1)
|
||||
pFlags[numListed] |= MSG_VIEW_FLAG_HASCHILDREN;
|
||||
|
||||
numListed++;
|
||||
}
|
||||
else
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && msgHdr, "couldn't get header for some reason");
|
||||
}
|
||||
else if (threadsRemoved < 10 && !(threadFlags & (MSG_FLAG_WATCHED | MSG_FLAG_IGNORED)))
|
||||
{
|
||||
// ### remove thread.
|
||||
threadsRemoved++; // don't want to remove all empty threads first time
|
||||
// around as it will choke preformance for upgrade.
|
||||
#ifdef DEBUG_bienvenu
|
||||
printf("removing empty non-ignored non-watched thread\n");
|
||||
printf("removing empty non-ignored non-watched thread\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMore && threadHdr)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMore && threadHdr)
|
||||
{
|
||||
threadHdr->GetThreadKey(startMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
*startMsg = nsMsgKey_None;
|
||||
m_threadEnumerator = nsnull;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*startMsg = nsMsgKey_None;
|
||||
m_threadEnumerator = nsnull;
|
||||
}
|
||||
*pNumListed = numListed;
|
||||
return rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsMsgThreadedDBView::ExpandAll()
|
||||
|
|
Загрузка…
Ссылка в новой задаче