示例#1
0
// E.g., if the day has changed, we need to close and re-open the view.
// 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))))
  {
    int32_t count;
    m_dayChanged = false;
    nsAutoTArray<nsMsgKey, 1> preservedSelection;
    nsMsgKey curSelectedKey;
    SaveAndClearSelection(&curSelectedKey, preservedSelection);
    InternalClose();
    int32_t 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();

    // this needs to happen after we remove all the keys, since RowCountChanged() will call our GetRowCount()
    if (mTree)
      mTree->RowCountChanged(0, -oldSize);
    SetSuppressChangeNotifications(true);
    nsresult rv = OpenWithHdrs(headers, m_sortType, m_sortOrder, newFlags, &count);
    SetSuppressChangeNotifications(false);
    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;
}
示例#2
0
// This method removes the thread at threadIndex from the view 
// and puts it back in its new position, determined by the sort order.
// And, if the selection is affected, save and restore the selection.
void nsMsgSearchDBView::MoveThreadAt(nsMsgViewIndex threadIndex)
{
  bool updatesSuppressed = mSuppressChangeNotification;
  // Turn off tree notifications so that we don't reload the current message.
  if (!updatesSuppressed)
    SetSuppressChangeNotifications(true);

  nsCOMPtr<nsIMsgDBHdr> threadHdr;
  GetMsgHdrForViewIndex(threadIndex, getter_AddRefs(threadHdr));

  uint32_t saveFlags = m_flags[threadIndex];
  bool threadIsExpanded = !(saveFlags & nsMsgMessageFlags::Elided);
  int32_t childCount = 0;
  nsMsgKey preservedKey;
  nsAutoTArray<nsMsgKey, 1> preservedSelection;
  int32_t selectionCount;
  int32_t currentIndex;
  bool hasSelection = mTree && mTreeSelection &&
                        ((NS_SUCCEEDED(mTreeSelection->GetCurrentIndex(&currentIndex)) &&
                         currentIndex >= 0 && (uint32_t)currentIndex < GetSize()) ||
                         (NS_SUCCEEDED(mTreeSelection->GetRangeCount(&selectionCount)) &&
                          selectionCount > 0));


  if (hasSelection)
    SaveAndClearSelection(&preservedKey, preservedSelection);

  if (threadIsExpanded)
  {
    ExpansionDelta(threadIndex, &childCount);
    childCount = -childCount;
  }
  nsTArray<nsMsgKey> threadKeys;
  nsTArray<uint32_t> threadFlags;
  nsTArray<uint8_t> threadLevels;
  nsCOMArray<nsIMsgFolder> threadFolders;

  if (threadIsExpanded)
  {
    threadKeys.SetCapacity(childCount);
    threadFlags.SetCapacity(childCount);
    threadLevels.SetCapacity(childCount);
    threadFolders.SetCapacity(childCount);
    for (nsMsgViewIndex index = threadIndex + 1; 
        index < (nsMsgViewIndex) GetSize() && m_levels[index]; index++)
    {
      threadKeys.AppendElement(m_keys[index]);
      threadFlags.AppendElement(m_flags[index]);
      threadLevels.AppendElement(m_levels[index]);
      threadFolders.AppendObject(m_folders[index]);
    }
    uint32_t collapseCount;
    CollapseByIndex(threadIndex, &collapseCount);
  }
  nsMsgDBView::RemoveByIndex(threadIndex);
  m_folders.RemoveObjectAt(threadIndex);
  nsMsgViewIndex newIndex = GetIndexForThread(threadHdr);
  NS_ASSERTION(newIndex == m_levels.Length() || !m_levels[newIndex],
                "inserting into middle of thread");
  if (newIndex == nsMsgViewIndex_None)
    newIndex = 0;
  nsMsgKey msgKey;
  uint32_t msgFlags;
  threadHdr->GetMessageKey(&msgKey);
  threadHdr->GetFlags(&msgFlags);
  InsertMsgHdrAt(newIndex, threadHdr, msgKey, msgFlags, 0);

  if (threadIsExpanded)
  {
    m_keys.InsertElementsAt(newIndex + 1, threadKeys);
    m_flags.InsertElementsAt(newIndex + 1, threadFlags);
    m_levels.InsertElementsAt(newIndex + 1, threadLevels);
    m_folders.InsertObjectsAt(threadFolders, newIndex + 1);
  }
  m_flags[newIndex] = saveFlags;
  // unfreeze selection.
  if (hasSelection)
    RestoreSelection(preservedKey, preservedSelection);

  if (!updatesSuppressed)
    SetSuppressChangeNotifications(false);
  nsMsgViewIndex lowIndex = threadIndex < newIndex ? threadIndex : newIndex;
  nsMsgViewIndex highIndex = lowIndex == threadIndex ? newIndex : threadIndex;
  NoteChange(lowIndex, highIndex - lowIndex + childCount + 1,
             nsMsgViewNotificationCode::changed);
}
// This method removes the thread at threadIndex from the view 
// and puts it back in its new position, determined by the sort order.
// And, if the selection is affected, save and restore the selection.
void nsMsgThreadedDBView::MoveThreadAt(nsMsgViewIndex threadIndex)
{
  // we need to check if the thread is collapsed or not...
  // We want to turn off tree notifications so that we don't
  // reload the current message.
  // We also need to invalidate the range between where the thread was
  // and where it ended up.
  bool changesDisabled = mSuppressChangeNotification;
  if (!changesDisabled)
    SetSuppressChangeNotifications(true);

  nsCOMPtr <nsIMsgDBHdr> threadHdr;

  GetMsgHdrForViewIndex(threadIndex, getter_AddRefs(threadHdr));
  PRInt32 childCount = 0;

  nsMsgKey preservedKey;
  nsAutoTArray<nsMsgKey, 1> preservedSelection;
  PRInt32 selectionCount;
  PRInt32 currentIndex;
  bool hasSelection = mTree && mTreeSelection &&
                        ((NS_SUCCEEDED(mTreeSelection->GetCurrentIndex(&currentIndex)) &&
                         currentIndex >= 0 && (PRUint32)currentIndex < GetSize()) ||
                         (NS_SUCCEEDED(mTreeSelection->GetRangeCount(&selectionCount)) &&
                          selectionCount > 0));
  if (hasSelection)
    SaveAndClearSelection(&preservedKey, preservedSelection);
  PRUint32 saveFlags = m_flags[threadIndex];
  bool threadIsExpanded = !(saveFlags & nsMsgMessageFlags::Elided);

  if (threadIsExpanded)
  {
    ExpansionDelta(threadIndex, &childCount);
    childCount = -childCount;
  }
  nsTArray<nsMsgKey> threadKeys;
  nsTArray<PRUint32> threadFlags;
  nsTArray<PRUint8> threadLevels;

  if (threadIsExpanded)
  {
    threadKeys.SetCapacity(childCount);
    threadFlags.SetCapacity(childCount);
    threadLevels.SetCapacity(childCount);
    for (nsMsgViewIndex index = threadIndex + 1; 
        index < GetSize() && m_levels[index]; index++)
    {
      threadKeys.AppendElement(m_keys[index]);
      threadFlags.AppendElement(m_flags[index]);
      threadLevels.AppendElement(m_levels[index]);
    }
    PRUint32 collapseCount;
    CollapseByIndex(threadIndex, &collapseCount);
  }
  nsMsgDBView::RemoveByIndex(threadIndex);
  nsMsgViewIndex newIndex = nsMsgViewIndex_None;
  AddHdr(threadHdr, &newIndex);

  // AddHdr doesn't always set newIndex, and getting it to do so
  // is going to require some refactoring.
  if (newIndex == nsMsgViewIndex_None)
    newIndex = FindHdr(threadHdr);

  if (threadIsExpanded)
  {
    m_keys.InsertElementsAt(newIndex + 1, threadKeys);
    m_flags.InsertElementsAt(newIndex + 1, threadFlags);
    m_levels.InsertElementsAt(newIndex + 1, threadLevels);
  }
  if (newIndex == nsMsgViewIndex_None)
  {
     NS_WARNING("newIndex=-1 in MoveThreadAt");
     newIndex = 0;
  }
  m_flags[newIndex] = saveFlags;
  // unfreeze selection.
  if (hasSelection)
    RestoreSelection(preservedKey, preservedSelection);

  if (!changesDisabled)
    SetSuppressChangeNotifications(false);
  nsMsgViewIndex lowIndex = threadIndex < newIndex ? threadIndex : newIndex;
  nsMsgViewIndex highIndex = lowIndex == threadIndex ? newIndex : threadIndex;
  NoteChange(lowIndex, highIndex - lowIndex + childCount + 1,
             nsMsgViewNotificationCode::changed);
}
nsresult nsMsgThreadedDBView::SortThreads(nsMsgViewSortTypeValue sortType, nsMsgViewSortOrderValue sortOrder)
{
  NS_PRECONDITION(m_viewFlags & nsMsgViewFlagsType::kThreadedDisplay, "trying to sort unthreaded threads");

  PRUint32 numThreads = 0;
  // the idea here is that copy the current view,  then build up an m_keys and m_flags array of just the top level
  // messages in the view, and then call nsMsgDBView::Sort(sortType, sortOrder).
  // Then, we expand the threads in the result array that were expanded in the original view (perhaps by copying
  // from the original view, but more likely just be calling expand).
  for (PRUint32 i = 0; i < m_keys.Length(); i++)
  {
    if (m_flags[i] & MSG_VIEW_FLAG_ISTHREAD)
    {
      if (numThreads < i)
      {
        m_keys[numThreads] = m_keys[i];
        m_flags[numThreads] = m_flags[i];
      }
      m_levels[numThreads] = 0;
      numThreads++;
    }
  }
  m_keys.SetLength(numThreads);
  m_flags.SetLength(numThreads);
  m_levels.SetLength(numThreads);
  //m_viewFlags &= ~nsMsgViewFlagsType::kThreadedDisplay;
  m_sortType = nsMsgViewSortType::byNone; // sort from scratch
  nsMsgDBView::Sort(sortType, sortOrder);
  m_viewFlags |= nsMsgViewFlagsType::kThreadedDisplay;
  SetSuppressChangeNotifications(true);
  // Loop through the original array, for each thread that's expanded, find it in the new array
  // and expand the thread. We have to update MSG_VIEW_FLAG_HAS_CHILDREN because
  // we may be going from a flat sort, which doesn't maintain that flag,
  // to a threaded sort, which requires that flag.
  for (PRUint32 j = 0; j < m_keys.Length(); j++)
  {
    PRUint32 flags = m_flags[j];
    if ((flags & (MSG_VIEW_FLAG_HASCHILDREN | nsMsgMessageFlags::Elided)) == MSG_VIEW_FLAG_HASCHILDREN)
    {
      PRUint32 numExpanded;
      m_flags[j] = flags | nsMsgMessageFlags::Elided;
      ExpandByIndex(j, &numExpanded);
      j += numExpanded;
      if (numExpanded > 0)
        m_flags[j - numExpanded] = flags | MSG_VIEW_FLAG_HASCHILDREN;
    }
    else if (flags & MSG_VIEW_FLAG_ISTHREAD && ! (flags & MSG_VIEW_FLAG_HASCHILDREN))
    {
      nsCOMPtr <nsIMsgDBHdr> msgHdr;
      nsCOMPtr <nsIMsgThread> pThread;
      m_db->GetMsgHdrForKey(m_keys[j], getter_AddRefs(msgHdr));
      if (msgHdr)
      {
        m_db->GetThreadContainingMsgHdr(msgHdr, getter_AddRefs(pThread));
        if (pThread)
        {
          PRUint32 numChildren;
          pThread->GetNumChildren(&numChildren);
          if (numChildren > 1)
            m_flags[j] = flags | MSG_VIEW_FLAG_HASCHILDREN | nsMsgMessageFlags::Elided;
        }
      }
    }
  }
  SetSuppressChangeNotifications(false);

  return NS_OK;
}