fix 462581, problems going between grouped and threaded/unthreaded views in saved search folders, r=standard8, sr=neil

This commit is contained in:
David Bienvenu 2008-11-11 07:11:53 -08:00
Родитель 1cf9d862e5
Коммит 9e0e634ee6
8 изменённых файлов: 83 добавлений и 76 удалений

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

@ -4636,11 +4636,7 @@ nsMsgViewIndex nsMsgDBView::GetInsertIndexHelper(nsIMsgDBHdr *msgHdr, nsTArray<n
EntryInfo2.folder = folders ? folders->ObjectAt(tryIndex) : m_folder.get();
nsCOMPtr <nsIMsgDBHdr> tryHdr;
nsCOMPtr <nsIMsgDatabase> db;
// ### this should get the db from the folder...
GetDBForViewIndex(tryIndex, getter_AddRefs(db));
if (db)
rv = db->GetMsgHdrForKey(EntryInfo2.id, getter_AddRefs(tryHdr));
EntryInfo2.folder->GetMessageHeader(EntryInfo2.id, getter_AddRefs(tryHdr));
if (!tryHdr)
break;
if (fieldType == kCollationKey)
@ -6823,6 +6819,11 @@ NS_IMETHODIMP nsMsgDBView::nsMsgViewHdrEnumerator::GetNext(nsISupports **aItem)
if (m_curHdrIndex >= m_view->GetSize())
return NS_ERROR_FAILURE;
// Ignore dummy header. We won't have empty groups, so
// we know the view index is good.
if (m_view->m_flags[m_curHdrIndex] & MSG_VIEW_FLAG_DUMMY)
++m_curHdrIndex;
nsCOMPtr<nsIMsgDBHdr> nextHdr;
nsresult rv = m_view->GetMsgHdrForViewIndex(m_curHdrIndex++, getter_AddRefs(nextHdr));

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

@ -79,6 +79,7 @@ NS_IMETHODIMP nsMsgGroupView::Open(nsIMsgFolder *aFolder, nsMsgViewSortTypeValue
void nsMsgGroupView::InternalClose()
{
m_groupsTable.Clear();
// nothing to do if we're not grouped.
if (!(m_viewFlags & nsMsgViewFlagsType::kGroupBySort))
return;
@ -114,7 +115,6 @@ void nsMsgGroupView::InternalClose()
dbFolderInfo->SetUint32Property("dateGroupFlags", expandFlags);
}
}
m_groupsTable.Clear();
}
NS_IMETHODIMP nsMsgGroupView::Close()
@ -436,8 +436,35 @@ NS_IMETHODIMP nsMsgGroupView::GetViewType(nsMsgViewTypeValue *aViewType)
return NS_OK;
}
PLDHashOperator
nsMsgGroupView::GroupTableCloner(const nsAString &aKey, nsIMsgThread* aGroupThread, void* aArg)
{
nsMsgGroupView* view = static_cast<nsMsgGroupView*>(aArg);
nsresult rv = view->m_groupsTable.Put(aKey, aGroupThread);
return NS_SUCCEEDED(rv) ? PL_DHASH_NEXT : PL_DHASH_STOP;
}
NS_IMETHODIMP
nsMsgGroupView::CopyDBView(nsMsgDBView *aNewMsgDBView, nsIMessenger *aMessengerInstance,
nsIMsgWindow *aMsgWindow, nsIMsgDBViewCommandUpdater *aCmdUpdater)
{
nsMsgDBView::CopyDBView(aNewMsgDBView, aMessengerInstance, aMsgWindow, aCmdUpdater);
nsMsgGroupView* newMsgDBView = (nsMsgGroupView *) aNewMsgDBView;
// If grouped, we need to clone the group thread hash table.
if (m_viewFlags & nsMsgViewFlagsType::kGroupBySort)
m_groupsTable.EnumerateRead(GroupTableCloner, newMsgDBView);
return NS_OK;
}
// E.g., if the day has changed, we need to close and re-open the view.
nsresult nsMsgGroupView::RebuildView()
// Or, if we're switching between grouping and threading in a cross-folder
// saved search. In that case, we needed to build an enumerator based on the
// old view type, and internally close the view based on its old type, but
// rebuild the new view based on the new view type. So we pass the new
// view flags to OpenWithHdrs.
nsresult nsMsgGroupView::RebuildView(nsMsgViewFlagsTypeValue newFlags)
{
nsCOMPtr <nsISimpleEnumerator> headers;
if (NS_SUCCEEDED(GetMessageEnumerator(getter_AddRefs(headers))))
@ -460,7 +487,7 @@ nsresult nsMsgGroupView::RebuildView()
if (mTree)
mTree->RowCountChanged(0, -oldSize);
DisableChangeUpdates();
nsresult rv = OpenWithHdrs(headers, m_sortType, m_sortOrder, m_viewFlags, &count);
nsresult rv = OpenWithHdrs(headers, m_sortType, m_sortOrder, newFlags, &count);
EnableChangeUpdates();
if (mTree)
mTree->RowCountChanged(0, GetSize());
@ -484,7 +511,7 @@ nsresult nsMsgGroupView::OnNewHeader(nsIMsgDBHdr *newHdr, nsMsgKey aParentKey, P
// check if we're adding a header, and the current day has changed. If it has, we're just going to
// close and re-open the view so things will be correctly categorized.
if (m_dayChanged)
return RebuildView();
return RebuildView(m_viewFlags);
PRBool newThread;
nsMsgGroupThread *thread = AddHdrToThread(newHdr, &newThread);
@ -564,7 +591,7 @@ NS_IMETHODIMP nsMsgGroupView::OnHdrFlagsChanged(nsIMsgDBHdr *aHdrChanged, PRUint
// check if we're adding a header, and the current day has changed. If it has, we're just going to
// close and re-open the view so things will be correctly categorized.
if (m_dayChanged)
return RebuildView();
return RebuildView(m_viewFlags);
nsresult rv = GetThreadContainingMsgHdr(aHdrChanged, getter_AddRefs(thread));
NS_ENSURE_SUCCESS(rv, rv);
@ -584,7 +611,7 @@ NS_IMETHODIMP nsMsgGroupView::OnHdrDeleted(nsIMsgDBHdr *aHdrDeleted, nsMsgKey aP
// check if we're adding a header, and the current day has changed. If it has, we're just going to
// close and re-open the view so things will be correctly categorized.
if (m_dayChanged)
return RebuildView();
return RebuildView(m_viewFlags);
nsCOMPtr <nsIMsgThread> thread;
nsMsgKey keyDeleted;

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

@ -59,6 +59,8 @@ public:
nsMsgViewSortOrderValue aSortOrder, nsMsgViewFlagsTypeValue aViewFlags,
PRInt32 *aCount);
NS_IMETHOD GetViewType(nsMsgViewTypeValue *aViewType);
NS_IMETHOD CopyDBView(nsMsgDBView *aNewMsgDBView, nsIMessenger *aMessengerInstance,
nsIMsgWindow *aMsgWindow, nsIMsgDBViewCommandUpdater *aCmdUpdater);
NS_IMETHOD Close();
NS_IMETHOD OnHdrDeleted(nsIMsgDBHdr *aHdrDeleted, nsMsgKey aParentKey, PRInt32 aFlags,
nsIDBChangeListener *aInstigator);
@ -71,7 +73,7 @@ public:
NS_IMETHOD GetCellText(PRInt32 aRow, nsITreeColumn* aCol, nsAString& aValue);
protected:
void InternalClose();
virtual void InternalClose();
nsMsgGroupThread *AddHdrToThread(nsIMsgDBHdr *msgHdr, PRBool *pNewThread);
nsresult HashHdr(nsIMsgDBHdr *msgHdr, nsString& aHashKey);
nsresult GetAgeBucketValue(nsIMsgDBHdr *aMsgHdr, PRUint32 * aAgeBucket, PRBool rcvDate = PR_FALSE); // helper function to get the age bucket for a hdr, useful when grouped by date
@ -84,8 +86,11 @@ protected:
PRUint32 *pFlags = NULL);
PRBool GroupViewUsesDummyRow(); // returns true if we are grouped by a sort attribute that uses a dummy row
virtual nsresult RebuildView();
virtual nsresult RebuildView(nsMsgViewFlagsTypeValue newFlags);
virtual nsMsgGroupThread *CreateGroupThread(nsIMsgDatabase *db);
PR_STATIC_CALLBACK(PLDHashOperator) GroupTableCloner(const nsAString &aKey,
nsIMsgThread* aGroupThread,
void* aArg);
nsInterfaceHashtable <nsStringHashKey, nsIMsgThread> m_groupsTable;
PRExplodedTime m_lastCurExplodedTime;

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

@ -123,9 +123,20 @@ NS_IMETHODIMP nsMsgQuickSearchDBView::GetViewType(nsMsgViewTypeValue *aViewType)
nsresult nsMsgQuickSearchDBView::AddHdr(nsIMsgDBHdr *msgHdr, nsMsgViewIndex *resultIndex)
{
return (m_viewFlags & nsMsgViewFlagsType::kGroupBySort)
? nsMsgGroupView::OnNewHeader(msgHdr, nsMsgKey_None, PR_TRUE)
: nsMsgDBView::AddHdr(msgHdr, resultIndex);
nsMsgKey msgKey;
msgHdr->GetMessageKey(&msgKey);
nsMsgViewIndex insertIndex = GetInsertIndexHelper(msgHdr, m_origKeys, nsnull,
nsMsgViewSortOrder::ascending, nsMsgViewSortType::byId);
m_origKeys.InsertElementAt(insertIndex, msgKey);
if (m_viewFlags & (nsMsgViewFlagsType::kGroupBySort|
nsMsgViewFlagsType::kThreadedDisplay))
{
nsMsgKey parentKey;
msgHdr->GetThreadParent(&parentKey);
return nsMsgThreadedDBView::OnNewHeader(msgHdr, parentKey, PR_TRUE);
}
else
return nsMsgDBView::AddHdr(msgHdr, resultIndex);
}
nsresult nsMsgQuickSearchDBView::OnNewHeader(nsIMsgDBHdr *newHdr, nsMsgKey aParentKey, PRBool ensureListed)
@ -478,7 +489,6 @@ nsresult nsMsgQuickSearchDBView::SortThreads(nsMsgViewSortTypeValue sortType, ns
threadRootIds.InsertElementAt(threadRootIndex, rootKey);
}
}
m_origKeys.SwapElements(m_keys);
// need to sort the top level threads now by sort order, if it's not by id.
if (sortType != nsMsgViewSortType::byId)
{
@ -519,7 +529,6 @@ nsresult nsMsgQuickSearchDBView::SortThreads(nsMsgViewSortTypeValue sortType, ns
}
}
}
NS_ASSERTION(m_origKeys.Length() == m_keys.Length(), "problem threading quick search");
return NS_OK;
}
@ -628,12 +637,12 @@ nsMsgQuickSearchDBView::OpenWithHdrs(nsISimpleEnumerator *aHeaders,
NS_IMETHODIMP nsMsgQuickSearchDBView::SetViewFlags(nsMsgViewFlagsTypeValue aViewFlags)
{
nsMsgViewFlagsTypeValue saveViewFlags = m_viewFlags;
nsresult rv = nsMsgDBView::SetViewFlags(aViewFlags);
nsresult rv = NS_OK;
// if the grouping has changed, rebuild the view
if (saveViewFlags & nsMsgViewFlagsType::kGroupBySort ^
if (m_viewFlags & nsMsgViewFlagsType::kGroupBySort ^
(aViewFlags & nsMsgViewFlagsType::kGroupBySort))
RebuildView();
rv = RebuildView(aViewFlags);
nsMsgDBView::SetViewFlags(aViewFlags);
return rv;
}

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

@ -158,6 +158,13 @@ NS_IMETHODIMP nsMsgSearchDBView::Close()
return nsMsgGroupView::Close();
}
void nsMsgSearchDBView::InternalClose()
{
m_threadsTable.Clear();
m_hdrsTable.Clear();
return nsMsgGroupView::InternalClose();
}
NS_IMETHODIMP nsMsgSearchDBView::GetCellText(PRInt32 aRow, nsITreeColumn* aCol, nsAString& aValue)
{
const PRUnichar* colID;
@ -972,7 +979,7 @@ NS_IMETHODIMP nsMsgSearchDBView::Sort(nsMsgViewSortTypeValue sortType, nsMsgView
// since it rebuilds the thread objects.
m_sortType = sortType;
m_sortOrder = sortOrder;
return RebuildView();
return RebuildView(m_viewFlags);
}
nsMsgKey preservedKey;
@ -1259,47 +1266,3 @@ nsMsgSearchDBView::ListIdsInThread(nsIMsgThread *threadHdr,
return NS_OK;
}
nsresult nsMsgSearchDBView::RebuildView()
{
if (m_viewFlags & nsMsgViewFlagsType::kGroupBySort)
return nsMsgGroupView::RebuildView();
nsCOMPtr<nsISimpleEnumerator> headers;
if (NS_SUCCEEDED(GetMessageEnumerator(getter_AddRefs(headers))))
{
PRInt32 count;
// ### we need to be remembering headers, not keys.
nsAutoTArray<nsMsgKey, 1> preservedSelection;
nsMsgKey curSelectedKey;
SaveAndClearSelection(&curSelectedKey, preservedSelection);
InternalClose();
PRInt32 oldSize = GetSize();
// this is important, because the tree will ask us for our
// row count, which get determine from the number of keys.
m_keys.Clear();
// be consistent
m_flags.Clear();
m_levels.Clear();
m_folders.Clear();
m_threadsTable.Clear();
m_hdrsTable.Clear();
// this needs to happen after we remove all the keys, since RowCountChanged() will call our GetRowCount()
if (mTree)
mTree->RowCountChanged(0, -oldSize);
DisableChangeUpdates();
nsresult rv = OpenWithHdrs(headers, m_sortType, m_sortOrder, m_viewFlags, &count);
EnableChangeUpdates();
if (mTree)
mTree->RowCountChanged(0, GetSize());
NS_ENSURE_SUCCESS(rv,rv);
// now, restore our desired selection
nsAutoTArray<nsMsgKey, 1> keyArray;
keyArray.AppendElement(curSelectedKey);
return RestoreSelection(curSelectedKey, keyArray);
}
return NS_OK;
}

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

@ -79,7 +79,6 @@ public:
virtual nsresult GetMsgHdrForViewIndex(nsMsgViewIndex index, nsIMsgDBHdr **msgHdr);
virtual nsresult OnNewHeader(nsIMsgDBHdr *newHdr, nsMsgKey parentKey, PRBool ensureListed);
NS_IMETHOD GetFolderForViewIndex(nsMsgViewIndex index, nsIMsgFolder **folder);
virtual nsresult RebuildView();
NS_IMETHOD OnAnnouncerGoingAway(nsIDBChangeAnnouncer *instigator);
@ -87,6 +86,7 @@ public:
virtual nsresult GetFolderFromMsgURI(const char *aMsgURI, nsIMsgFolder **aFolder);
protected:
virtual void InternalClose();
virtual nsresult ListIdsInThread(nsIMsgThread *threadHdr,
nsMsgViewIndex startOfThreadViewIndex,
PRUint32 *pNumListed);

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

@ -746,7 +746,9 @@ void nsMsgThreadedDBView::MoveThreadAt(nsMsgViewIndex threadIndex)
// reload the current message.
// We also need to invalidate the range between where the thread was
// and where it ended up.
DisableChangeUpdates();
PRBool changesDisabled = mSuppressChangeNotification;
if (!changesDisabled)
DisableChangeUpdates();
nsCOMPtr <nsIMsgDBHdr> threadHdr;
@ -797,7 +799,8 @@ void nsMsgThreadedDBView::MoveThreadAt(nsMsgViewIndex threadIndex)
// unfreeze selection.
RestoreSelection(preservedKey, preservedSelection);
EnableChangeUpdates();
if (!changesDisabled)
EnableChangeUpdates();
nsMsgViewIndex lowIndex = threadIndex < newIndex ? threadIndex : newIndex;
nsMsgViewIndex highIndex = lowIndex == threadIndex ? newIndex : threadIndex;
NoteChange(lowIndex, highIndex - lowIndex + childCount,
@ -813,7 +816,7 @@ nsresult nsMsgThreadedDBView::AddMsgToThreadNotInView(nsIMsgThread *threadHdr, n
PRBool msgKilled;
msgHdr->GetIsKilled(&msgKilled);
if (!msgKilled)
rv = AddHdr(msgHdr);
rv = nsMsgDBView::AddHdr(msgHdr);
}
return rv;
}

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

@ -494,15 +494,14 @@ NS_IMETHODIMP nsMsgXFVirtualFolderDBView::GetMsgFolder(nsIMsgFolder **aMsgFolder
NS_IMETHODIMP nsMsgXFVirtualFolderDBView::SetViewFlags(nsMsgViewFlagsTypeValue aViewFlags)
{
nsMsgViewFlagsTypeValue saveViewFlags = m_viewFlags;
nsresult rv = nsMsgDBView::SetViewFlags(aViewFlags);
nsresult rv = NS_OK;
// if the grouping/threading has changed, rebuild the view
if ((saveViewFlags & (nsMsgViewFlagsType::kGroupBySort |
if ((m_viewFlags & (nsMsgViewFlagsType::kGroupBySort |
nsMsgViewFlagsType::kThreadedDisplay)) !=
(aViewFlags & (nsMsgViewFlagsType::kGroupBySort |
nsMsgViewFlagsType::kThreadedDisplay)))
RebuildView();
rv = RebuildView(aViewFlags);
nsMsgDBView::SetViewFlags(aViewFlags);
return rv;
}