NS_IMETHODIMP
nsMsgSearchDBView::OpenWithHdrs(nsISimpleEnumerator *aHeaders,
                                nsMsgViewSortTypeValue aSortType,
                                nsMsgViewSortOrderValue aSortOrder,
                                nsMsgViewFlagsTypeValue aViewFlags,
                                int32_t *aCount)
{
  if (aViewFlags & nsMsgViewFlagsType::kGroupBySort)
    return nsMsgGroupView::OpenWithHdrs(aHeaders, aSortType, aSortOrder, 
                                        aViewFlags, aCount);

  m_sortType = aSortType;
  m_sortOrder = aSortOrder;
  m_viewFlags = aViewFlags;
  SaveSortInfo(m_sortType, m_sortOrder);

  bool hasMore;
  nsCOMPtr<nsISupports> supports;
  nsCOMPtr<nsIMsgDBHdr> msgHdr;
  nsCOMPtr<nsIMsgFolder> folder;
  nsresult rv = NS_OK;
  while (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv = aHeaders->HasMoreElements(&hasMore)) && hasMore)
  {
    rv = aHeaders->GetNext(getter_AddRefs(supports));
    if (NS_SUCCEEDED(rv) && supports)
    {
      msgHdr = do_QueryInterface(supports);
      msgHdr->GetFolder(getter_AddRefs(folder));
      AddHdrFromFolder(msgHdr, folder); 
    }
  }
  *aCount = m_keys.Length();
  return rv;
}
nsresult nsMsgThreadedDBView::InitThreadedView(PRInt32 *pCount)
{
  nsresult rv;
  
  m_keys.Clear();
  m_flags.Clear();
  m_levels.Clear(); 
  m_prevKeys.Clear();
  m_prevFlags.Clear();
  m_prevLevels.Clear();
  m_havePrevView = false;
  nsresult getSortrv = NS_OK; // ### TODO m_db->GetSortInfo(&sortType, &sortOrder);
  
  // list all the ids into m_keys.
  nsMsgKey startMsg = 0; 
  do
  {
    const PRInt32 kIdChunkSize = 400;
    PRInt32  numListed = 0;
    nsMsgKey idArray[kIdChunkSize];
    PRInt32  flagArray[kIdChunkSize];
    char     levelArray[kIdChunkSize];

    rv = ListThreadIds(&startMsg, (m_viewFlags & nsMsgViewFlagsType::kUnreadOnly) != 0, idArray, flagArray, 
      levelArray, kIdChunkSize, &numListed, nsnull);
    if (NS_SUCCEEDED(rv))
    {
      PRInt32 numAdded = AddKeys(idArray, flagArray, levelArray, m_sortType, numListed);
      if (pCount)
        *pCount += numAdded;
    }
    
  } while (NS_SUCCEEDED(rv) && startMsg != nsMsgKey_None);
  
  if (NS_SUCCEEDED(getSortrv))
  {
    rv = InitSort(m_sortType, m_sortOrder);
    SaveSortInfo(m_sortType, m_sortOrder);

  }
  return rv;
}
NS_IMETHODIMP nsMsgGroupView::OpenWithHdrs(nsISimpleEnumerator *aHeaders, nsMsgViewSortTypeValue aSortType,
                                        nsMsgViewSortOrderValue aSortOrder, nsMsgViewFlagsTypeValue aViewFlags,
                                        int32_t *aCount)
{
  nsresult rv = NS_OK;

  m_groupsTable.Clear();
  if (aSortType == nsMsgViewSortType::byThread || aSortType == nsMsgViewSortType::byId
    || aSortType == nsMsgViewSortType::byNone || aSortType == nsMsgViewSortType::bySize)
    return NS_ERROR_INVALID_ARG;

  m_sortType = aSortType;
  m_sortOrder = aSortOrder;
  m_viewFlags = aViewFlags | nsMsgViewFlagsType::kThreadedDisplay | nsMsgViewFlagsType::kGroupBySort;
  SaveSortInfo(m_sortType, m_sortOrder);

  bool hasMore;
  nsCOMPtr <nsISupports> supports;
  nsCOMPtr <nsIMsgDBHdr> msgHdr;
  while (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv = aHeaders->HasMoreElements(&hasMore)) && hasMore)
  {
    rv = aHeaders->GetNext(getter_AddRefs(supports));
    if (NS_SUCCEEDED(rv) && supports)
    {
      bool notUsed;
      msgHdr = do_QueryInterface(supports);
      AddHdrToThread(msgHdr, &notUsed);
    }
  }
  uint32_t expandFlags = 0;
  bool expandAll = m_viewFlags & nsMsgViewFlagsType::kExpandAll;
  uint32_t viewFlag = (m_sortType == nsMsgViewSortType::byDate) ? MSG_VIEW_FLAG_DUMMY : 0;
  if (viewFlag && m_db)
  {
    nsCOMPtr <nsIDBFolderInfo> dbFolderInfo;
    nsresult rv = m_db->GetDBFolderInfo(getter_AddRefs(dbFolderInfo));
    NS_ENSURE_SUCCESS(rv, rv);
    if (dbFolderInfo)
      dbFolderInfo->GetUint32Property("dateGroupFlags",  0, &expandFlags);
  }
  // go through the view updating the flags for threads with more than one message...
  // and if grouped by date, expanding threads that were expanded before.
  for (uint32_t viewIndex = 0; viewIndex < m_keys.Length(); viewIndex++)
  {
    nsCOMPtr <nsIMsgThread> thread;
    GetThreadContainingIndex(viewIndex, getter_AddRefs(thread));
    if (thread)
    {
      uint32_t numChildren;
      thread->GetNumChildren(&numChildren);
      if (numChildren > 1 || viewFlag)
        OrExtraFlag(viewIndex, viewFlag | MSG_VIEW_FLAG_HASCHILDREN);
      if (expandAll || expandFlags)
      {
        nsMsgGroupThread *groupThread = static_cast<nsMsgGroupThread *>((nsIMsgThread *) thread);
        if (expandAll || expandFlags & (1 << groupThread->m_threadKey))
        {
          uint32_t numExpanded;
          ExpandByIndex(viewIndex, &numExpanded);
          viewIndex += numExpanded;
        }
      }
    }
  }
  *aCount = m_keys.Length();
  return rv;
}
NS_IMETHODIMP nsMsgThreadedDBView::Sort(nsMsgViewSortTypeValue sortType, nsMsgViewSortOrderValue sortOrder)
{
  nsresult rv;

  PRInt32 rowCountBeforeSort = GetSize();

  if (!rowCountBeforeSort) 
  {
    // still need to setup our flags even when no articles - bug 98183.
    m_sortType = sortType;
    if (sortType == nsMsgViewSortType::byThread && ! (m_viewFlags & nsMsgViewFlagsType::kThreadedDisplay))
      SetViewFlags(m_viewFlags | nsMsgViewFlagsType::kThreadedDisplay);
    SaveSortInfo(sortType, sortOrder);
    return NS_OK;
  }

  // sort threads by sort order
  bool sortThreads = m_viewFlags & (nsMsgViewFlagsType::kThreadedDisplay | nsMsgViewFlagsType::kGroupBySort);
  
  // if sort type is by thread, and we're already threaded, change sort type to byId
  if (sortType == nsMsgViewSortType::byThread && (m_viewFlags & nsMsgViewFlagsType::kThreadedDisplay) != 0)
    sortType = nsMsgViewSortType::byId;

  nsMsgKey preservedKey;
  nsAutoTArray<nsMsgKey, 1> preservedSelection;
  SaveAndClearSelection(&preservedKey, preservedSelection);
  // if the client wants us to forget our cached id arrays, they
  // should build a new view. If this isn't good enough, we
  // need a method to do that.
  if (sortType != m_sortType || !m_sortValid || sortThreads)
  {
    SaveSortInfo(sortType, sortOrder);
    if (sortType == nsMsgViewSortType::byThread)  
    {
      m_sortType = sortType;
      m_viewFlags |= nsMsgViewFlagsType::kThreadedDisplay;
      m_viewFlags &= nsMsgViewFlagsType::kGroupBySort;
      if ( m_havePrevView)
      {
        // restore saved id array and flags array
        m_keys = m_prevKeys;
        m_flags = m_prevFlags;
        m_levels = m_prevLevels;
        m_sortValid = true;
        
        // the sort may have changed the number of rows
        // before we restore the selection, tell the tree
        // do this before we call restore selection
        // this is safe when there is no selection.
        rv = AdjustRowCount(rowCountBeforeSort, GetSize());
        
        RestoreSelection(preservedKey, preservedSelection);
        if (mTree) mTree->Invalidate();
        return NS_OK;
      }
      else
      {
        // set sort info in anticipation of what Init will do.
        InitThreadedView(nsnull);	// build up thread list.
        if (sortOrder != nsMsgViewSortOrder::ascending)
          Sort(sortType, sortOrder);
        
        // the sort may have changed the number of rows
        // before we update the selection, tell the tree
        // do this before we call restore selection
        // this is safe when there is no selection.
        rv = AdjustRowCount(rowCountBeforeSort, GetSize());
        
        RestoreSelection(preservedKey, preservedSelection);
        if (mTree) mTree->Invalidate();
        return NS_OK;
      }
    }
    else if (sortType  != nsMsgViewSortType::byThread && (m_sortType == nsMsgViewSortType::byThread  || sortThreads)/* && !m_havePrevView*/)
    {
      if (sortThreads)
      {
        SortThreads(sortType, sortOrder);
        sortType = nsMsgViewSortType::byThread; // hack so base class won't do anything
      }
      else
      {
        // going from SortByThread to non-thread sort - must build new key, level,and flags arrays 
        m_prevKeys = m_keys;
        m_prevFlags = m_flags;
        m_prevLevels = m_levels;
        // do this before we sort, so that we'll use the cheap method
        // of expanding.
        m_viewFlags &= ~(nsMsgViewFlagsType::kThreadedDisplay | nsMsgViewFlagsType::kGroupBySort);
        ExpandAll();
        //			m_idArray.RemoveAll();
        //			m_flags.Clear();
        m_havePrevView = true;
      }
    }
  }
  else if (m_sortOrder != sortOrder)// check for toggling the sort
  {
    nsMsgDBView::Sort(sortType, sortOrder);
  }
  if (!sortThreads)
  {
    // call the base class in case we're not sorting by thread
    rv = nsMsgDBView::Sort(sortType, sortOrder);
    SaveSortInfo(sortType, sortOrder);
  }
  // the sort may have changed the number of rows
  // before we restore the selection, tell the tree
  // do this before we call restore selection
  // this is safe when there is no selection.
  rv = AdjustRowCount(rowCountBeforeSort, GetSize());

  RestoreSelection(preservedKey, preservedSelection);
  if (mTree) mTree->Invalidate();
  NS_ENSURE_SUCCESS(rv,rv);
  return NS_OK;
}