nsresult nsMsgThreadsWithUnreadDBView::AddMsgToThreadNotInView(nsIMsgThread *threadHdr, nsIMsgDBHdr *msgHdr, bool ensureListed)
{
  nsresult rv = NS_OK;

  nsCOMPtr <nsIMsgDBHdr> parentHdr;
  PRUint32 msgFlags;
  msgHdr->GetFlags(&msgFlags);
  GetFirstMessageHdrToDisplayInThread(threadHdr, getter_AddRefs(parentHdr));
  if (parentHdr && (ensureListed || !(msgFlags & nsMsgMessageFlags::Read)))
  {
    nsMsgKey key;
    PRUint32 numMsgsInThread;
    rv = AddHdr(parentHdr);
    threadHdr->GetNumChildren(&numMsgsInThread);
    if (numMsgsInThread > 1)
    {
      parentHdr->GetMessageKey(&key);
      nsMsgViewIndex viewIndex = FindViewIndex(key);
      if (viewIndex != nsMsgViewIndex_None)
        OrExtraFlag(viewIndex, nsMsgMessageFlags::Elided | MSG_VIEW_FLAG_HASCHILDREN);
    }
    m_totalUnwantedMessagesInView -= numMsgsInThread;
  }
  else
    m_totalUnwantedMessagesInView++;
  return rv;
}
nsresult nsMsgQuickSearchDBView::SortThreads(nsMsgViewSortTypeValue sortType, nsMsgViewSortOrderValue sortOrder)
{
  // don't need to sort by threads for group view.
  if (m_viewFlags & nsMsgViewFlagsType::kGroupBySort)
    return NS_OK;
  // iterate over the messages in the view, getting the thread id's
  // sort m_keys so we can quickly find if a key is in the view. 
  m_keys.Sort();
  // array of the threads' root hdr keys.
  nsTArray<nsMsgKey> threadRootIds;
  nsCOMPtr <nsIMsgDBHdr> rootHdr;
  nsCOMPtr <nsIMsgDBHdr> msgHdr;
  nsCOMPtr <nsIMsgThread> threadHdr;
  for (uint32_t i = 0; i < m_keys.Length(); i++)
  {
    GetMsgHdrForViewIndex(i, getter_AddRefs(msgHdr));
    m_db->GetThreadContainingMsgHdr(msgHdr, getter_AddRefs(threadHdr));
    if (threadHdr)
    {
      nsMsgKey rootKey;
      threadHdr->GetChildKeyAt(0, &rootKey);
      nsMsgViewIndex threadRootIndex = threadRootIds.BinaryIndexOf(rootKey);
      // if we already have that id in top level threads, ignore this msg.
      if (threadRootIndex != nsMsgViewIndex_None)
        continue;
      // it would be nice if GetInsertIndexHelper always found the hdr, but it doesn't.
      threadHdr->GetChildHdrAt(0, getter_AddRefs(rootHdr));
      if (!rootHdr)
        continue;
      threadRootIndex = GetInsertIndexHelper(rootHdr, threadRootIds, nullptr,
                                             nsMsgViewSortOrder::ascending,
                                             nsMsgViewSortType::byId);
      threadRootIds.InsertElementAt(threadRootIndex, rootKey);
    }
  }
  // need to sort the top level threads now by sort order, if it's not by id.
  if (sortType != nsMsgViewSortType::byId)
  {
    m_keys.SwapElements(threadRootIds);
    nsMsgDBView::Sort(sortType, sortOrder);
    threadRootIds.SwapElements(m_keys);
  }
  m_keys.Clear();
  m_levels.Clear();
  m_flags.Clear();
  // now we've build up the list of thread ids - need to build the view
  // from that. So for each thread id, we need to list the messages in the thread.
  uint32_t numThreads = threadRootIds.Length();
  for (uint32_t threadIndex = 0; threadIndex < numThreads; threadIndex++)
  {
    m_db->GetMsgHdrForKey(threadRootIds[threadIndex], getter_AddRefs(rootHdr));
    if (rootHdr)
    {
      nsCOMPtr <nsIMsgDBHdr> displayRootHdr;
      m_db->GetThreadContainingMsgHdr(rootHdr, getter_AddRefs(threadHdr));
      if (threadHdr)
      {
        nsMsgKey rootKey;
        uint32_t rootFlags;
        GetFirstMessageHdrToDisplayInThread(threadHdr, getter_AddRefs(displayRootHdr));
        if (!displayRootHdr)
          continue;
        displayRootHdr->GetMessageKey(&rootKey);
        displayRootHdr->GetFlags(&rootFlags);
        rootFlags |= MSG_VIEW_FLAG_ISTHREAD;
        m_keys.AppendElement(rootKey);
        m_flags.AppendElement(rootFlags);
        m_levels.AppendElement(0);

        nsMsgViewIndex startOfThreadViewIndex = m_keys.Length();
        nsMsgViewIndex rootIndex = startOfThreadViewIndex - 1;
        uint32_t numListed = 0;
        ListIdsInThreadOrder(threadHdr, rootKey, 1, &startOfThreadViewIndex, &numListed);
        if (numListed > 0)
          m_flags[rootIndex] = rootFlags | MSG_VIEW_FLAG_HASCHILDREN;
      }
    }
  }
  return NS_OK;
}