NS_IMETHODIMP nsMsgSearchDBView::OnHdrDeleted(nsIMsgDBHdr *aHdrDeleted, nsMsgKey aParentKey, int32_t aFlags, nsIDBChangeListener *aInstigator) { if (m_viewFlags & nsMsgViewFlagsType::kGroupBySort) return nsMsgGroupView::OnHdrDeleted(aHdrDeleted, aParentKey, aFlags, aInstigator); if (m_viewFlags & nsMsgViewFlagsType::kThreadedDisplay) { nsMsgViewIndex deletedIndex = FindHdr(aHdrDeleted); uint32_t savedFlags = 0; if (deletedIndex != nsMsgViewIndex_None) { savedFlags = m_flags[deletedIndex]; RemoveByIndex(deletedIndex); } nsCOMPtr<nsIMsgThread> thread; GetXFThreadFromMsgHdr(aHdrDeleted, getter_AddRefs(thread)); if (thread) { nsMsgXFViewThread *viewThread = static_cast<nsMsgXFViewThread*>(thread.get()); viewThread->RemoveChildHdr(aHdrDeleted, nullptr); if (deletedIndex == nsMsgViewIndex_None && viewThread->MsgCount() == 1) { // remove the last child of a collapsed thread. Need to find the root, // and remove the thread flags on it. nsCOMPtr<nsIMsgDBHdr> rootHdr; thread->GetRootHdr(nullptr, getter_AddRefs(rootHdr)); if (rootHdr) { nsMsgViewIndex threadIndex = GetThreadRootIndex(rootHdr); if (threadIndex != nsMsgViewIndex_None) AndExtraFlag(threadIndex, ~(MSG_VIEW_FLAG_ISTHREAD | nsMsgMessageFlags::Elided | MSG_VIEW_FLAG_HASCHILDREN)); } } else if (savedFlags & MSG_VIEW_FLAG_HASCHILDREN) { if (savedFlags & nsMsgMessageFlags::Elided) { nsCOMPtr<nsIMsgDBHdr> rootHdr; nsresult rv = thread->GetRootHdr(nullptr, getter_AddRefs(rootHdr)); NS_ENSURE_SUCCESS(rv, rv); nsMsgKey msgKey; uint32_t msgFlags; rootHdr->GetMessageKey(&msgKey); rootHdr->GetFlags(&msgFlags); // promote the new thread root if (viewThread->MsgCount() > 1) msgFlags |= MSG_VIEW_FLAG_ISTHREAD | nsMsgMessageFlags::Elided | MSG_VIEW_FLAG_HASCHILDREN; InsertMsgHdrAt(deletedIndex, rootHdr, msgKey, msgFlags, 0); if (!m_deletingRows) NoteChange(deletedIndex, 1, nsMsgViewNotificationCode::insertOrDelete); } else if (viewThread->MsgCount() > 1) { OrExtraFlag(deletedIndex, MSG_VIEW_FLAG_ISTHREAD | MSG_VIEW_FLAG_HASCHILDREN); } } } } else { return nsMsgDBView::OnHdrDeleted(aHdrDeleted, aParentKey, aFlags, aInstigator); } return NS_OK; }
nsresult nsMsgGroupView::OnNewHeader(nsIMsgDBHdr *newHdr, nsMsgKey aParentKey, bool ensureListed) { if (!(m_viewFlags & nsMsgViewFlagsType::kGroupBySort)) return nsMsgDBView::OnNewHeader(newHdr, aParentKey, ensureListed); // 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(m_viewFlags); bool newThread; nsMsgGroupThread *thread = AddHdrToThread(newHdr, &newThread); if (thread) { // find the view index of (the root node of) the thread nsMsgViewIndex threadIndex = ThreadIndexOfMsgHdr(newHdr); // may need to fix thread counts if (threadIndex != nsMsgViewIndex_None) { if (newThread) { // AddHdrToThread creates the header elided, so we need to un-elide it // if we want it expanded. if(m_viewFlags & nsMsgViewFlagsType::kExpandAll) m_flags[threadIndex] &= ~nsMsgMessageFlags::Elided; } else { m_flags[threadIndex] |= MSG_VIEW_FLAG_HASCHILDREN | MSG_VIEW_FLAG_ISTHREAD; } int32_t numRowsToInvalidate = 1; // if the thread is expanded (not elided), we should add the header to // the view. if (! (m_flags[threadIndex] & nsMsgMessageFlags::Elided)) { uint32_t msgIndexInThread = thread->FindMsgHdr(newHdr); bool insertedAtThreadRoot = !msgIndexInThread; // Add any new display node and potentially fix-up changes in the root. // (If this is a new thread and we are not using a dummy row, the only // node to display is the root node which has already been added by // AddHdrToThread. And since there is just the one, no change in root // could have occurred, so we have nothing to do.) if (!newThread || GroupViewUsesDummyRow()) { // we never want to insert/update the root node, because // AddHdrToThread has already done that for us (in all cases). if (insertedAtThreadRoot) msgIndexInThread++; // If this header is the new parent of the thread... AND // If we are not using a dummy row, this means we need to append our // old node as the first child of the new root. // (If we are using a dummy row, the old node's "content" node already // exists (at position threadIndex + 1) and we need to insert the // "content" copy of the new root node there, pushing our old // "content" node down.) // Example mini-diagrams, wrapping the to-add thing with () // No dummy row; we had: [A], now we have [B], we want [B (A)]. // Dummy row; we had: [A A], now we have [B A], we want [B (B) A]. // (Coming into this we're adding 'B') if (!newThread && insertedAtThreadRoot && !GroupViewUsesDummyRow()) { // grab a copy of the old root node ('A') from the thread so we can // insert it. (offset msgIndexInThread=1 is the right thing; we are // non-dummy.) thread->GetChildHdrAt(msgIndexInThread, &newHdr); } // nothing to do for dummy case, we're already inserting 'B'. nsMsgKey msgKey; uint32_t msgFlags; newHdr->GetMessageKey(&msgKey); newHdr->GetFlags(&msgFlags); InsertMsgHdrAt(threadIndex + msgIndexInThread, newHdr, msgKey, msgFlags, 1); } // the call to NoteChange() has to happen after we add the key // as NoteChange() will call RowCountChanged() which will call our GetRowCount() // (msgIndexInThread states. new thread: 0, old thread at root: 1) if (newThread && GroupViewUsesDummyRow()) NoteChange(threadIndex, 2, nsMsgViewNotificationCode::insertOrDelete); else NoteChange(threadIndex + msgIndexInThread, 1, nsMsgViewNotificationCode::insertOrDelete); numRowsToInvalidate = msgIndexInThread; } // we still need the addition notification for new threads when elided else if (newThread) { NoteChange(threadIndex, 1, nsMsgViewNotificationCode::insertOrDelete); } NoteChange(threadIndex, numRowsToInvalidate, nsMsgViewNotificationCode::changed); } } // if thread is expanded, we need to add hdr to view... return NS_OK; }