From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- comm/mailnews/base/src/nsMsgGroupThread.cpp | 731 ++++++++++++++++++++++++++++ 1 file changed, 731 insertions(+) create mode 100644 comm/mailnews/base/src/nsMsgGroupThread.cpp (limited to 'comm/mailnews/base/src/nsMsgGroupThread.cpp') diff --git a/comm/mailnews/base/src/nsMsgGroupThread.cpp b/comm/mailnews/base/src/nsMsgGroupThread.cpp new file mode 100644 index 0000000000..32a132d27a --- /dev/null +++ b/comm/mailnews/base/src/nsMsgGroupThread.cpp @@ -0,0 +1,731 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "msgCore.h" +#include "nsMsgGroupThread.h" +#include "nsMsgDBView.h" +#include "nsMsgMessageFlags.h" +#include "nsMsgUtils.h" +#include "nsSimpleEnumerator.h" + +NS_IMPL_ISUPPORTS(nsMsgGroupThread, nsIMsgThread) + +nsMsgGroupThread::nsMsgGroupThread() { Init(); } + +nsMsgGroupThread::nsMsgGroupThread(nsIMsgDatabase* db) { + m_db = db; + Init(); +} + +void nsMsgGroupThread::Init() { + m_threadKey = nsMsgKey_None; + m_threadRootKey = nsMsgKey_None; + m_numUnreadChildren = 0; + m_flags = 0; + m_newestMsgDate = 0; + m_dummy = false; +} + +nsMsgGroupThread::~nsMsgGroupThread() {} + +NS_IMETHODIMP nsMsgGroupThread::SetThreadKey(nsMsgKey threadKey) { + m_threadKey = threadKey; + // by definition, the initial thread key is also the thread root key. + m_threadRootKey = threadKey; + return NS_OK; +} + +NS_IMETHODIMP nsMsgGroupThread::GetThreadKey(nsMsgKey* aResult) { + NS_ENSURE_ARG_POINTER(aResult); + *aResult = m_threadKey; + return NS_OK; +} + +NS_IMETHODIMP nsMsgGroupThread::GetFlags(uint32_t* aFlags) { + NS_ENSURE_ARG_POINTER(aFlags); + *aFlags = m_flags; + return NS_OK; +} + +NS_IMETHODIMP nsMsgGroupThread::SetFlags(uint32_t aFlags) { + m_flags = aFlags; + return NS_OK; +} + +NS_IMETHODIMP nsMsgGroupThread::SetSubject(const nsACString& aSubject) { + NS_ASSERTION(false, "shouldn't call this"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsMsgGroupThread::GetSubject(nsACString& result) { + NS_ASSERTION(false, "shouldn't call this"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsMsgGroupThread::GetNumChildren(uint32_t* aNumChildren) { + NS_ENSURE_ARG_POINTER(aNumChildren); + *aNumChildren = m_keys.Length(); // - ((m_dummy) ? 1 : 0); + return NS_OK; +} + +uint32_t nsMsgGroupThread::NumRealChildren() { + return m_keys.Length() - ((m_dummy) ? 1 : 0); +} + +NS_IMETHODIMP nsMsgGroupThread::GetNumUnreadChildren( + uint32_t* aNumUnreadChildren) { + NS_ENSURE_ARG_POINTER(aNumUnreadChildren); + *aNumUnreadChildren = m_numUnreadChildren; + return NS_OK; +} + +void nsMsgGroupThread::InsertMsgHdrAt(nsMsgViewIndex index, nsIMsgDBHdr* hdr) { + nsMsgKey msgKey; + hdr->GetMessageKey(&msgKey); + m_keys.InsertElementAt(index, msgKey); +} + +void nsMsgGroupThread::SetMsgHdrAt(nsMsgViewIndex index, nsIMsgDBHdr* hdr) { + nsMsgKey msgKey; + hdr->GetMessageKey(&msgKey); + m_keys[index] = msgKey; +} + +nsMsgViewIndex nsMsgGroupThread::FindMsgHdr(nsIMsgDBHdr* hdr) { + nsMsgKey msgKey; + hdr->GetMessageKey(&msgKey); + return (nsMsgViewIndex)m_keys.IndexOf(msgKey); +} + +NS_IMETHODIMP nsMsgGroupThread::AddChild(nsIMsgDBHdr* child, + nsIMsgDBHdr* inReplyTo, + bool threadInThread, + nsIDBChangeAnnouncer* announcer) { + NS_ASSERTION(false, "shouldn't call this"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsMsgViewIndex nsMsgGroupThread::AddMsgHdrInDateOrder(nsIMsgDBHdr* child, + nsMsgDBView* view) { + nsMsgKey newHdrKey; + child->GetMessageKey(&newHdrKey); + uint32_t insertIndex = 0; + // since we're sorted by date, we could do a binary search for the + // insert point. Or, we could start at the end... + if (m_keys.Length() > 0) { + nsMsgViewSortTypeValue sortType; + nsMsgViewSortOrderValue sortOrder; + (void)view->GetSortType(&sortType); + (void)view->GetSortOrder(&sortOrder); + // historical behavior is ascending date order unless our primary sort is + // on date + nsMsgViewSortOrderValue threadSortOrder = + (sortType == nsMsgViewSortType::byDate && + sortOrder == nsMsgViewSortOrder::descending) + ? nsMsgViewSortOrder::descending + : nsMsgViewSortOrder::ascending; + // new behavior is tricky and uses the secondary sort order if the secondary + // sort is on the date + nsMsgViewSortTypeValue secondarySortType; + nsMsgViewSortOrderValue secondarySortOrder; + (void)view->GetSecondarySortType(&secondarySortType); + (void)view->GetSecondarySortOrder(&secondarySortOrder); + if (secondarySortType == nsMsgViewSortType::byDate) + threadSortOrder = secondarySortOrder; + // sort by date within group. + insertIndex = GetInsertIndexFromView(view, child, threadSortOrder); + } + m_keys.InsertElementAt(insertIndex, newHdrKey); + if (!insertIndex) m_threadRootKey = newHdrKey; + return insertIndex; +} + +nsMsgViewIndex nsMsgGroupThread::GetInsertIndexFromView( + nsMsgDBView* view, nsIMsgDBHdr* child, + nsMsgViewSortOrderValue threadSortOrder) { + return view->GetInsertIndexHelper(child, m_keys, nullptr, threadSortOrder, + nsMsgViewSortType::byDate); +} + +nsMsgViewIndex nsMsgGroupThread::AddChildFromGroupView(nsIMsgDBHdr* child, + nsMsgDBView* view) { + uint32_t newHdrFlags = 0; + uint32_t msgDate; + nsMsgKey newHdrKey = 0; + + child->GetFlags(&newHdrFlags); + child->GetMessageKey(&newHdrKey); + child->GetDateInSeconds(&msgDate); + if (msgDate > m_newestMsgDate) SetNewestMsgDate(msgDate); + + child->AndFlags(~(nsMsgMessageFlags::Watched), &newHdrFlags); + uint32_t numChildren; + + // get the num children before we add the new header. + GetNumChildren(&numChildren); + + // if this is an empty thread, set the root key to this header's key + if (numChildren == 0) m_threadRootKey = newHdrKey; + + if (!(newHdrFlags & nsMsgMessageFlags::Read)) ChangeUnreadChildCount(1); + + return AddMsgHdrInDateOrder(child, view); +} + +nsresult nsMsgGroupThread::ReparentNonReferenceChildrenOf( + nsIMsgDBHdr* topLevelHdr, nsMsgKey newParentKey, + nsIDBChangeAnnouncer* announcer) { + return NS_OK; +} + +NS_IMETHODIMP nsMsgGroupThread::GetChildKeyAt(uint32_t aIndex, + nsMsgKey* aResult) { + NS_ENSURE_ARG_POINTER(aResult); + if (aIndex >= m_keys.Length()) return NS_ERROR_INVALID_ARG; + *aResult = m_keys[aIndex]; + return NS_OK; +} + +NS_IMETHODIMP nsMsgGroupThread::GetChildHdrAt(uint32_t aIndex, + nsIMsgDBHdr** aResult) { + if (aIndex >= m_keys.Length()) return NS_MSG_MESSAGE_NOT_FOUND; + return m_db->GetMsgHdrForKey(m_keys[aIndex], aResult); +} + +NS_IMETHODIMP nsMsgGroupThread::GetChild(nsMsgKey msgKey, + nsIMsgDBHdr** aResult) { + return GetChildHdrAt(m_keys.IndexOf(msgKey), aResult); +} + +NS_IMETHODIMP nsMsgGroupThread::RemoveChildAt(uint32_t aIndex) { + NS_ENSURE_TRUE(aIndex < m_keys.Length(), NS_MSG_MESSAGE_NOT_FOUND); + + m_keys.RemoveElementAt(aIndex); + return NS_OK; +} + +nsresult nsMsgGroupThread::RemoveChild(nsMsgKey msgKey) { + m_keys.RemoveElement(msgKey); + return NS_OK; +} + +NS_IMETHODIMP nsMsgGroupThread::RemoveChildHdr( + nsIMsgDBHdr* child, nsIDBChangeAnnouncer* announcer) { + NS_ENSURE_ARG_POINTER(child); + + uint32_t flags; + nsMsgKey key; + + child->GetFlags(&flags); + child->GetMessageKey(&key); + + // if this was the newest msg, clear the newest msg date so we'll recalc. + uint32_t date; + child->GetDateInSeconds(&date); + if (date == m_newestMsgDate) SetNewestMsgDate(0); + + if (!(flags & nsMsgMessageFlags::Read)) ChangeUnreadChildCount(-1); + nsMsgViewIndex threadIndex = FindMsgHdr(child); + bool wasFirstChild = threadIndex == 0; + nsresult rv = RemoveChildAt(threadIndex); + // if we're deleting the root of a dummy thread, need to update the threadKey + // and the dummy header at position 0 + if (m_dummy && wasFirstChild && m_keys.Length() > 1) { + nsIMsgDBHdr* newRootChild; + rv = GetChildHdrAt(1, &newRootChild); + NS_ENSURE_SUCCESS(rv, rv); + SetMsgHdrAt(0, newRootChild); + } + + return rv; +} + +nsresult nsMsgGroupThread::ReparentChildrenOf(nsMsgKey oldParent, + nsMsgKey newParent, + nsIDBChangeAnnouncer* announcer) { + nsresult rv = NS_OK; + + uint32_t numChildren = 0; + GetNumChildren(&numChildren); + + if (numChildren > 0) { + nsCOMPtr curHdr; + for (uint32_t childIndex = 0; childIndex < numChildren; childIndex++) { + rv = GetChildHdrAt(childIndex, getter_AddRefs(curHdr)); + if (NS_SUCCEEDED(rv) && curHdr) { + nsMsgKey threadParent; + + curHdr->GetThreadParent(&threadParent); + if (threadParent == oldParent) { + nsMsgKey curKey; + + curHdr->SetThreadParent(newParent); + curHdr->GetMessageKey(&curKey); + if (announcer) + announcer->NotifyParentChangedAll(curKey, oldParent, newParent, + nullptr); + // if the old parent was the root of the thread, then only the first + // child gets promoted to root, and other children become children of + // the new root. + if (newParent == nsMsgKey_None) { + m_threadRootKey = curKey; + newParent = curKey; + } + } + } + } + } + return rv; +} + +NS_IMETHODIMP nsMsgGroupThread::MarkChildRead(bool bRead) { + ChangeUnreadChildCount(bRead ? -1 : 1); + return NS_OK; +} + +// this could be moved into utils, because I think it's the same as the db impl. +class nsMsgGroupThreadEnumerator : public nsBaseMsgEnumerator { + public: + // nsIMsgEnumerator support. + NS_IMETHOD GetNext(nsIMsgDBHdr** aItem) override; + NS_IMETHOD HasMoreElements(bool* aResult) override; + + // nsMsgGroupThreadEnumerator methods: + typedef nsresult (*nsMsgGroupThreadEnumeratorFilter)(nsIMsgDBHdr* hdr, + void* closure); + + nsMsgGroupThreadEnumerator(nsMsgGroupThread* thread, nsMsgKey startKey, + nsMsgGroupThreadEnumeratorFilter filter, + void* closure); + int32_t MsgKeyFirstChildIndex(nsMsgKey inMsgKey); + + protected: + virtual ~nsMsgGroupThreadEnumerator(); + + nsresult Prefetch(); + + nsCOMPtr mResultHdr; + RefPtr mThread; + nsMsgKey mThreadParentKey; + nsMsgKey mFirstMsgKey; + int32_t mChildIndex; + bool mDone; + bool mNeedToPrefetch; + nsMsgGroupThreadEnumeratorFilter mFilter; + void* mClosure; + bool mFoundChildren; +}; + +nsMsgGroupThreadEnumerator::nsMsgGroupThreadEnumerator( + nsMsgGroupThread* thread, nsMsgKey startKey, + nsMsgGroupThreadEnumeratorFilter filter, void* closure) + : mDone(false), mFilter(filter), mClosure(closure), mFoundChildren(false) { + mThreadParentKey = startKey; + mChildIndex = 0; + mThread = thread; + mNeedToPrefetch = true; + mFirstMsgKey = nsMsgKey_None; + + nsresult rv = mThread->GetRootHdr(getter_AddRefs(mResultHdr)); + if (NS_SUCCEEDED(rv) && mResultHdr) mResultHdr->GetMessageKey(&mFirstMsgKey); + + uint32_t numChildren; + mThread->GetNumChildren(&numChildren); + + if (mThreadParentKey != nsMsgKey_None) { + nsMsgKey msgKey = nsMsgKey_None; + for (uint32_t childIndex = 0; childIndex < numChildren; childIndex++) { + rv = mThread->GetChildHdrAt(childIndex, getter_AddRefs(mResultHdr)); + if (NS_SUCCEEDED(rv) && mResultHdr) { + mResultHdr->GetMessageKey(&msgKey); + if (msgKey == startKey) { + mChildIndex = MsgKeyFirstChildIndex(msgKey); + mDone = (mChildIndex < 0); + break; + } + + if (mDone) break; + } else + NS_ASSERTION(false, "couldn't get child from thread"); + } + } + +#ifdef DEBUG_bienvenu1 + nsCOMPtr child; + for (uint32_t childIndex = 0; childIndex < numChildren; childIndex++) { + rv = mThread->GetChildHdrAt(childIndex, getter_AddRefs(child)); + if (NS_SUCCEEDED(rv) && child) { + nsMsgKey threadParent; + nsMsgKey msgKey; + // we're only doing one level of threading, so check if caller is + // asking for children of the first message in the thread or not. + // if not, we will tell him there are no children. + child->GetMessageKey(&msgKey); + child->GetThreadParent(&threadParent); + + printf("index = %ld key = %ld parent = %lx\n", childIndex, msgKey, + threadParent); + } + } +#endif +} + +nsMsgGroupThreadEnumerator::~nsMsgGroupThreadEnumerator() {} + +int32_t nsMsgGroupThreadEnumerator::MsgKeyFirstChildIndex(nsMsgKey inMsgKey) { + // look through rest of thread looking for a child of this message. + // If the inMsgKey is the first message in the thread, then all children + // without parents are considered to be children of inMsgKey. + // Otherwise, only true children qualify. + uint32_t numChildren; + nsCOMPtr curHdr; + int32_t firstChildIndex = -1; + + mThread->GetNumChildren(&numChildren); + + for (uint32_t curChildIndex = 0; curChildIndex < numChildren; + curChildIndex++) { + nsresult rv = mThread->GetChildHdrAt(curChildIndex, getter_AddRefs(curHdr)); + if (NS_SUCCEEDED(rv) && curHdr) { + nsMsgKey parentKey; + + curHdr->GetThreadParent(&parentKey); + if (parentKey == inMsgKey) { + firstChildIndex = curChildIndex; + break; + } + } + } +#ifdef DEBUG_bienvenu1 + printf("first child index of %ld = %ld\n", inMsgKey, firstChildIndex); +#endif + return firstChildIndex; +} + +NS_IMETHODIMP nsMsgGroupThreadEnumerator::GetNext(nsIMsgDBHdr** aItem) { + NS_ENSURE_ARG_POINTER(aItem); + nsresult rv = NS_OK; + + if (mNeedToPrefetch) rv = Prefetch(); + + if (NS_SUCCEEDED(rv) && mResultHdr) { + NS_ADDREF(*aItem = mResultHdr); + mNeedToPrefetch = true; + } + return rv; +} + +nsresult nsMsgGroupThreadEnumerator::Prefetch() { + nsresult rv = NS_OK; // XXX or should this default to an error? + mResultHdr = nullptr; + if (mThreadParentKey == nsMsgKey_None) { + rv = mThread->GetRootHdr(getter_AddRefs(mResultHdr)); + NS_ASSERTION(NS_SUCCEEDED(rv) && mResultHdr, + "better be able to get root hdr"); + mChildIndex = 0; // since root can be anywhere, set mChildIndex to 0. + } else if (!mDone) { + uint32_t numChildren; + mThread->GetNumChildren(&numChildren); + + while ((uint32_t)mChildIndex < numChildren) { + rv = mThread->GetChildHdrAt(mChildIndex++, getter_AddRefs(mResultHdr)); + if (NS_SUCCEEDED(rv) && mResultHdr) { + nsMsgKey parentKey; + nsMsgKey curKey; + + if (mFilter && NS_FAILED(mFilter(mResultHdr, mClosure))) { + mResultHdr = nullptr; + continue; + } + + mResultHdr->GetThreadParent(&parentKey); + mResultHdr->GetMessageKey(&curKey); + // if the parent is the same as the msg we're enumerating over, + // or the parentKey isn't set, and we're iterating over the top + // level message in the thread, then leave mResultHdr set to cur msg. + if (parentKey == mThreadParentKey || + (parentKey == nsMsgKey_None && mThreadParentKey == mFirstMsgKey && + curKey != mThreadParentKey)) + break; + mResultHdr = nullptr; + } else + NS_ASSERTION(false, "better be able to get child"); + } + // if (!mResultHdr && mThreadParentKey == mFirstMsgKey && !mFoundChildren && + // numChildren > 1) { + // mThread->ReparentMsgsWithInvalidParent(numChildren, mThreadParentKey); + // } + } + if (!mResultHdr) { + mDone = true; + return NS_ERROR_FAILURE; + } + if (NS_FAILED(rv)) { + mDone = true; + return rv; + } else + mNeedToPrefetch = false; + mFoundChildren = true; + +#ifdef DEBUG_bienvenu1 + nsMsgKey debugMsgKey; + mResultHdr->GetMessageKey(&debugMsgKey); + printf("next for %ld = %ld\n", mThreadParentKey, debugMsgKey); +#endif + + return rv; +} + +NS_IMETHODIMP nsMsgGroupThreadEnumerator::HasMoreElements(bool* aResult) { + NS_ENSURE_ARG_POINTER(aResult); + if (mNeedToPrefetch) Prefetch(); + *aResult = !mDone; + return NS_OK; +} + +NS_IMETHODIMP nsMsgGroupThread::EnumerateMessages(nsMsgKey parentKey, + nsIMsgEnumerator** result) { + NS_ADDREF(*result = new nsMsgGroupThreadEnumerator(this, parentKey, nullptr, + nullptr)); + return NS_OK; +} + +#if 0 +nsresult nsMsgGroupThread::ReparentMsgsWithInvalidParent(uint32_t numChildren, nsMsgKey threadParentKey) +{ + nsresult ret = NS_OK; + // run through looking for messages that don't have a correct parent, + // i.e., a parent that's in the thread! + for (int32_t childIndex = 0; childIndex < (int32_t) numChildren; childIndex++) + { + nsCOMPtr curChild; + ret = GetChildHdrAt(childIndex, getter_AddRefs(curChild)); + if (NS_SUCCEEDED(ret) && curChild) + { + nsMsgKey parentKey; + nsCOMPtr parent; + + curChild->GetThreadParent(&parentKey); + + if (parentKey != nsMsgKey_None) + { + GetChild(parentKey, getter_AddRefs(parent)); + if (!parent) + curChild->SetThreadParent(threadParentKey); + } + } + } + return ret; +} +#endif + +NS_IMETHODIMP nsMsgGroupThread::GetRootHdr(nsIMsgDBHdr** result) { + NS_ENSURE_ARG_POINTER(result); + + *result = nullptr; + int32_t resultIndex = -1; + + if (m_threadRootKey != nsMsgKey_None) { + nsresult ret = GetChildHdrForKey(m_threadRootKey, result, &resultIndex); + if (NS_SUCCEEDED(ret) && *result) + return ret; + else { + printf("need to reset thread root key\n"); + uint32_t numChildren; + nsMsgKey threadParentKey = nsMsgKey_None; + GetNumChildren(&numChildren); + + for (uint32_t childIndex = 0; childIndex < numChildren; childIndex++) { + nsCOMPtr curChild; + ret = GetChildHdrAt(childIndex, getter_AddRefs(curChild)); + if (NS_SUCCEEDED(ret) && curChild) { + nsMsgKey parentKey; + + curChild->GetThreadParent(&parentKey); + if (parentKey == nsMsgKey_None) { + NS_ASSERTION(!(*result), "two top level msgs, not good"); + curChild->GetMessageKey(&threadParentKey); + m_threadRootKey = threadParentKey; + curChild.forget(result); + } + } + } + if (*result) { + return NS_OK; + } + } + // if we can't get the thread root key, we'll just get the first hdr. + // there's a bug where sometimes we weren't resetting the thread root key + // when removing the thread root key. + } + return GetChildHdrAt(0, result); +} + +nsresult nsMsgGroupThread::ChangeUnreadChildCount(int32_t delta) { + m_numUnreadChildren += delta; + return NS_OK; +} + +nsresult nsMsgGroupThread::GetChildHdrForKey(nsMsgKey desiredKey, + nsIMsgDBHdr** result, + int32_t* resultIndex) { + NS_ENSURE_ARG_POINTER(result); + + nsresult rv = NS_OK; // XXX or should this default to an error? + uint32_t numChildren = 0; + GetNumChildren(&numChildren); + + uint32_t childIndex; + for (childIndex = 0; childIndex < numChildren; childIndex++) { + nsCOMPtr child; + rv = GetChildHdrAt(childIndex, getter_AddRefs(child)); + if (NS_SUCCEEDED(rv) && child) { + nsMsgKey msgKey; + // we're only doing one level of threading, so check if caller is + // asking for children of the first message in the thread or not. + // if not, we will tell him there are no children. + child->GetMessageKey(&msgKey); + + if (msgKey == desiredKey) { + child.forget(result); + break; + } + } + } + if (resultIndex) *resultIndex = (int32_t)childIndex; + + return rv; +} + +NS_IMETHODIMP nsMsgGroupThread::GetFirstUnreadChild(nsIMsgDBHdr** result) { + NS_ENSURE_ARG_POINTER(result); + + uint32_t numChildren = 0; + GetNumChildren(&numChildren); + + for (uint32_t childIndex = 0; childIndex < numChildren; childIndex++) { + nsCOMPtr child; + nsresult rv = GetChildHdrAt(childIndex, getter_AddRefs(child)); + if (NS_SUCCEEDED(rv) && child) { + nsMsgKey msgKey; + child->GetMessageKey(&msgKey); + + bool isRead; + rv = m_db->IsRead(msgKey, &isRead); + if (NS_SUCCEEDED(rv) && !isRead) { + child.forget(result); + break; + } + } + } + + return (*result) ? NS_OK : NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP nsMsgGroupThread::GetNewestMsgDate(uint32_t* aResult) { + NS_ENSURE_ARG_POINTER(aResult); + + // if this hasn't been set, figure it out by enumerating the msgs in the + // thread. + if (!m_newestMsgDate) { + nsresult rv = NS_OK; + + uint32_t numChildren = 0; + GetNumChildren(&numChildren); + + for (uint32_t childIndex = 0; childIndex < numChildren; childIndex++) { + nsCOMPtr child; + rv = GetChildHdrAt(childIndex, getter_AddRefs(child)); + if (NS_SUCCEEDED(rv) && child) { + uint32_t msgDate; + child->GetDateInSeconds(&msgDate); + if (msgDate > m_newestMsgDate) m_newestMsgDate = msgDate; + } + } + } + *aResult = m_newestMsgDate; + return NS_OK; +} + +NS_IMETHODIMP nsMsgGroupThread::SetNewestMsgDate(uint32_t aNewestMsgDate) { + m_newestMsgDate = aNewestMsgDate; + return NS_OK; +} + +nsMsgXFGroupThread::nsMsgXFGroupThread() {} + +nsMsgXFGroupThread::~nsMsgXFGroupThread() {} + +NS_IMETHODIMP nsMsgXFGroupThread::GetNumChildren(uint32_t* aNumChildren) { + NS_ENSURE_ARG_POINTER(aNumChildren); + *aNumChildren = m_folders.Length(); + return NS_OK; +} + +NS_IMETHODIMP nsMsgXFGroupThread::GetChildHdrAt(uint32_t aIndex, + nsIMsgDBHdr** aResult) { + if (aIndex >= m_folders.Length()) return NS_MSG_MESSAGE_NOT_FOUND; + return m_folders.ObjectAt(aIndex)->GetMessageHeader(m_keys[aIndex], aResult); +} + +NS_IMETHODIMP nsMsgXFGroupThread::GetChildKeyAt(uint32_t aIndex, + nsMsgKey* aResult) { + NS_ASSERTION(false, "shouldn't call this"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsMsgXFGroupThread::RemoveChildAt(uint32_t aIndex) { + NS_ENSURE_TRUE(aIndex < m_folders.Length(), NS_MSG_MESSAGE_NOT_FOUND); + + nsresult rv = nsMsgGroupThread::RemoveChildAt(aIndex); + NS_ENSURE_SUCCESS(rv, rv); + m_folders.RemoveElementAt(aIndex); + return NS_OK; +} + +void nsMsgXFGroupThread::InsertMsgHdrAt(nsMsgViewIndex index, + nsIMsgDBHdr* hdr) { + nsCOMPtr folder; + hdr->GetFolder(getter_AddRefs(folder)); + m_folders.InsertObjectAt(folder, index); + nsMsgGroupThread::InsertMsgHdrAt(index, hdr); +} + +void nsMsgXFGroupThread::SetMsgHdrAt(nsMsgViewIndex index, nsIMsgDBHdr* hdr) { + nsCOMPtr folder; + hdr->GetFolder(getter_AddRefs(folder)); + m_folders.ReplaceObjectAt(folder, index); + nsMsgGroupThread::SetMsgHdrAt(index, hdr); +} + +nsMsgViewIndex nsMsgXFGroupThread::FindMsgHdr(nsIMsgDBHdr* hdr) { + nsMsgKey msgKey; + hdr->GetMessageKey(&msgKey); + nsCOMPtr folder; + hdr->GetFolder(getter_AddRefs(folder)); + size_t index = 0; + while (true) { + index = m_keys.IndexOf(msgKey, index); + if (index == m_keys.NoIndex || m_folders[index] == folder) break; + index++; + } + return (nsMsgViewIndex)index; +} + +nsMsgViewIndex nsMsgXFGroupThread::AddMsgHdrInDateOrder(nsIMsgDBHdr* child, + nsMsgDBView* view) { + nsMsgViewIndex insertIndex = + nsMsgGroupThread::AddMsgHdrInDateOrder(child, view); + nsCOMPtr folder; + child->GetFolder(getter_AddRefs(folder)); + m_folders.InsertObjectAt(folder, insertIndex); + return insertIndex; +} +nsMsgViewIndex nsMsgXFGroupThread::GetInsertIndexFromView( + nsMsgDBView* view, nsIMsgDBHdr* child, + nsMsgViewSortOrderValue threadSortOrder) { + return view->GetInsertIndexHelper(child, m_keys, &m_folders, threadSortOrder, + nsMsgViewSortType::byDate); +} -- cgit v1.2.3