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;
}