fix multiple msg load on multiple delete, fix thread order inside thread r=naving, sr=sspitzer 78588 and 76501

This commit is contained in:
bienvenu%netscape.com 2001-05-04 00:31:01 +00:00
Родитель df74b9e7f9
Коммит eb20295d05
5 изменённых файлов: 322 добавлений и 242 удалений

Просмотреть файл

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