Mozilla/mozilla/cmd/macfe/MailNews/CMessageFolderView.cp
ftang%netscape.com 351bb2c436 check in comment about history code may need to change later. No code change.
git-svn-id: svn://10.0.0.236/trunk@9530 18797224-902f-48f8-a5cc-f745e15eee43
1998-09-08 20:21:23 +00:00

1187 lines
38 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1996 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "CMessageFolderView.h"
// PowerPlant
#include <LTableArrayStorage.h>
#include <LDropFlag.h>
#include "prefapi.h"
#include "shist.h"
#include "uprefd.h"
#include "Secnav.h"
// MacFE
#include "macutil.h"
#include "ufilemgr.h"
// Netscape Mac Libs
#include "UGraphicGizmos.h"
#include "resgui.h"
// Mail/News Specific
#include "UOffline.h"
#include "MailNewsgroupWindow_Defines.h"
#include "CThreadWindow.h"
#include "CMailProgressWindow.h"
#include "LTableViewHeader.h"
#include "CProgressListener.h"
#include "CMessageFolder.h"
#include "CMailNewsContext.h"
#include "CNewsSubscriber.h"
#include "UMailFolderMenus.h"
#include "StGetInfoHandler.h"
#include "UNewFolderDialog.h"
#include "CMessageWindow.h"
#include "UMailSelection.h"
#include "UMessageLibrary.h"
#include "CPrefsDialog.h"
#include "CProxyDragTask.h"
#include "UDeferredTask.h"
#include "CInlineEditField.h"
//========================================================================================
class CFolderWatchingTask
//========================================================================================
: public CDeferredTask
{
public:
CFolderWatchingTask(
CMessageFolderView* inFolderView,
MSG_FolderInfo* inFolderInfo)
: mFolderView(inFolderView)
, mWatchedFolder(inFolderInfo, inFolderView->GetMessagePane())
, mWatchedFolderChildCount( mWatchedFolder.CountSubFolders())
, mAnotherExecuteAttemptCount(0)
{
}
virtual ExecuteResult ExecuteSelf();
protected:
CMessageFolderView* mFolderView;
CMessageFolder mWatchedFolder;
UInt32 mWatchedFolderChildCount;
UInt32 mAnotherExecuteAttemptCount;
};
//----------------------------------------------------------------------------------------
CDeferredTask::ExecuteResult CFolderWatchingTask::ExecuteSelf()
//----------------------------------------------------------------------------------------
{
// This is here for the case when folders were dragged into (or deleted into)
// a folder which was closed in the message center. We need to refresh the
// cache, because the newly added children have changed their level in the
// hierarchy. We don't get notified unless the new parent is expanded.
// Currently, this only goes one folder deep, which covers the most common case
// of folder deletion (move to trash).
if (++mAnotherExecuteAttemptCount >= 500)
return eDoneDelete; // give up and die
CNSContext* context = mFolderView->GetContext();
if (context->GetCurrentCommand() == cmd_MoveMailMessages )
context->SetCurrentCommand(cmd_Nothing);
mWatchedFolder.FolderInfoChanged(mFolderView->GetMessagePane()); // get new backend data
if (!mWatchedFolder.GetFolderInfo())
return eDoneDelete;
UInt32 childCount = mWatchedFolder.CountSubFolders();
if (childCount <= mWatchedFolderChildCount)
return eWaitStepBack; // no change yet, but ok to run another task.
// OK, it's stale. Fix it.
mWatchedFolder.FolderLevelChanged(mFolderView->GetMessagePane());
MSG_ViewIndex index = ::MSG_GetFolderIndex(mFolderView->GetMessagePane(), mWatchedFolder);
if (index != MSG_VIEWINDEXNONE)
mFolderView->RefreshRowRange(index + 1, index + 1);
return eDoneDelete;
} // CFolderWatchingTask::ExecuteSelf
#pragma mark -- CDeleteSelectionTask
//========================================================================================
class CDeleteSelectionTask
//========================================================================================
: public CDeferredTask
{
public:
CDeleteSelectionTask(
CMessageFolderView* inFolderView,
const CMailSelection& inSelection)
: mSelection(inSelection)
, mFolderView(inFolderView)
{}
virtual ExecuteResult ExecuteSelf();
protected:
CPersistentFolderSelection mSelection;
CMessageFolderView* mFolderView;
}; // class CDeleteSelectionTask
//----------------------------------------------------------------------------------------
CDeferredTask::ExecuteResult CDeleteSelectionTask::ExecuteSelf()
//----------------------------------------------------------------------------------------
{
CNetscapeWindow* win = dynamic_cast<CNetscapeWindow*>
(LWindow::FetchWindowObject(mFolderView->GetMacPort()));
// Wait till any pending URLs are finished
if (win->IsAnyContextBusy())
return eWaitStayFront;
const MSG_ViewIndex* indices = mSelection.GetSelectionList();
MSG_ViewIndex numIndices = mSelection.selectionSize;
mFolderView->DoDeleteSelection(mSelection);
return eDoneDelete;
} // CDeleteSelectionTask::ExecuteSelf
#pragma mark -- CDeferredDragTask
//========================================================================================
class CDeferredDragTask
//========================================================================================
: public CDeferredTask
{
public:
CDeferredDragTask(
CMessageFolderView* inFolderView,
const CMessageFolder& inDestFolder,
Boolean inDoCopy)
: mFolderView(inFolderView)
, mDestFolder(inDestFolder)
, mDoCopy(inDoCopy)
{}
protected:
CMessageFolderView* mFolderView;
CMessageFolder mDestFolder;
Boolean mDoCopy; // rather than move
};
//========================================================================================
class CDeferredDragFolderTask
//========================================================================================
: public CDeferredDragTask
{
public:
CDeferredDragFolderTask(
CMessageFolderView* inFolderView,
const CMailSelection& inSelection,
const CMessageFolder& inDestFolder,
Boolean inDoCopy)
: CDeferredDragTask(
inFolderView
, inDestFolder
, inDoCopy)
, mSelection(inSelection)
{}
virtual ExecuteResult ExecuteSelf();
protected:
CPersistentFolderSelection mSelection;
}; // class CDeferredDragFolderTask
//----------------------------------------------------------------------------------------
CDeferredTask::ExecuteResult CDeferredDragFolderTask::ExecuteSelf()
//----------------------------------------------------------------------------------------
{
// display modal dialog
// if (!NET_IsOffline()) // ? 97/08/13 someone removed this line.
// 98/01/26 it's because moving messages can take some time - even offline
{
short stringID = 15; // Copying / Moving Messages
CStr255 commandString;
::GetIndString(commandString, 7099, stringID);
CMailProgressWindow* progressWindow = CMailProgressWindow::CreateModalParasite(
CMailProgressWindow::res_ID_modal,
mSelection.xpPane,
commandString);
if (progressWindow)
progressWindow->SetDelay(0);
}
// copy / move messages
if (mDestFolder.IsTrash())
{
// Special case. Back-end doesn't translate this into a delete, and
// presents an alert unless you're dragging mail folders. But it should
// work for news servers etc. So:
XP_Bool confirmPref; // Don't ever confirm a drag.
PREF_GetBoolPref("mailnews.confirm.moveFoldersToTrash", &confirmPref);
if (confirmPref)
PREF_SetBoolPref("mailnews.confirm.moveFoldersToTrash", FALSE);
mFolderView->DoDeleteSelection(mSelection);
if (confirmPref)
PREF_SetBoolPref("mailnews.confirm.moveFoldersToTrash", confirmPref);
}
else
{
mFolderView->GetContext()->SetCurrentCommand(cmd_MoveMailMessages);
mFolderView->WatchFolderForChildren(mDestFolder);
::MSG_MoveFoldersInto(
mSelection.xpPane,
mSelection.GetSelectionList(),
mSelection.selectionSize,
mDestFolder
);
}
return eDoneDelete;
} // CDeferredDragFolderTask::ExecuteSelf
//========================================================================================
class CDeferredDragMessageTask
//========================================================================================
: public CDeferredDragTask
{
public:
CDeferredDragMessageTask(
CMessageFolderView* inFolderView,
const CMailSelection& inSelection,
const CMessageFolder& inDestFolder,
Boolean inDoCopy)
: CDeferredDragTask(
inFolderView
, inDestFolder
, inDoCopy)
, mSelection(inSelection)
{}
virtual ExecuteResult ExecuteSelf();
protected:
CPersistentMessageSelection mSelection;
}; // class CDeferredDragMessageTask
//----------------------------------------------------------------------------------------
CDeferredTask::ExecuteResult CDeferredDragMessageTask::ExecuteSelf()
//----------------------------------------------------------------------------------------
{
mFolderView->DropMessages(mSelection, mDestFolder, mDoCopy);
return eDoneDelete;
} // CDeferredDragMessageTask::ExecuteSelf
#pragma mark -- CMessageFolderView
//----------------------------------------------------------------------------------------
CMessageFolderView::CMessageFolderView(LStream *inStream)
//----------------------------------------------------------------------------------------
: Inherited(inStream)
, mUpdateMailFolderMenus(false)
{
mAllowDropAfterLastRow = false;
} // CMessageFolderView::CMessageFolderView
//----------------------------------------------------------------------------------------
CMessageFolderView::~CMessageFolderView()
//----------------------------------------------------------------------------------------
{
} // CMessageFolderView::~CMessageFolderView
//----------------------------------------------------------------------------------------
Boolean CMessageFolderView::ItemIsAcceptable(
DragReference inDragRef,
ItemReference inItemRef )
//----------------------------------------------------------------------------------------
{
FlavorFlags flavorFlags;
if (::GetFlavorFlags(inDragRef, inItemRef, kMailNewsSelectionDragFlavor, &flavorFlags) == noErr)
{
CMailSelection selection;
if (!mIsInternalDrop && GetSelectionFromDrag(inDragRef, selection))
mIsInternalDrop = (selection.xpPane == GetMessagePane());
return true;
}
return false;
} // CMessageFolderView::ItemIsAcceptable
//----------------------------------------------------------------------------------------
Boolean CMessageFolderView::GetSelectionAndCopyStatusFromDrag(
DragReference inDragRef,
CMessageFolder& inDestFolder,
CMailSelection& outSelection,
Boolean& outCopy)
// Return true if this is an OK drop operation.
//----------------------------------------------------------------------------------------
{
if (!GetSelectionFromDrag(inDragRef, outSelection))
return false;
Boolean isFolderDrop = (::MSG_GetPaneType(outSelection.xpPane) == MSG_FOLDERPANE);
// Don't do anything if the user aborted by dragging back into the same first row.
// There are other cases, but the backend will alert anyway. In this simple case,
// the back-end alert is annoying.
SInt16 modifiers;
::GetDragModifiers(inDragRef, NULL, &modifiers, NULL);
outCopy = ((modifiers & optionKey) != 0);
MSG_DragEffect effect = outCopy ? MSG_Require_Copy : MSG_Default_Drag;
// Ask the back end for guidance on what is possible:
if (isFolderDrop)
{
effect = ::MSG_DragFoldersIntoStatus(
outSelection.xpPane,
outSelection.GetSelectionList(),
outSelection.selectionSize,
inDestFolder,
effect);
if (effect == MSG_Drag_Not_Allowed && outCopy)
{
// Well, maybe a move is ok
effect = ::MSG_DragFoldersIntoStatus(
outSelection.xpPane,
outSelection.GetSelectionList(),
outSelection.selectionSize,
inDestFolder,
MSG_Default_Drag);
}
}
else
{
effect = ::MSG_DragMessagesIntoFolderStatus(
outSelection.xpPane,
outSelection.GetSelectionList(),
outSelection.selectionSize,
inDestFolder,
effect);
if (effect == MSG_Drag_Not_Allowed && outCopy)
{
// Well, maybe a move is ok
effect = ::MSG_DragMessagesIntoFolderStatus(
outSelection.xpPane,
outSelection.GetSelectionList(),
outSelection.selectionSize,
inDestFolder,
MSG_Default_Drag);
}
}
outCopy = (effect & MSG_Require_Copy) != 0;
return (effect != MSG_Drag_Not_Allowed); // this looks ok as a drop operation.
} // CMessageFolderView::GetSelectionAndCopyStatusFromDrag
//----------------------------------------------------------------------------------------
void CMessageFolderView::DropMessages(
const CMailSelection& inSelection,
const CMessageFolder& inDestFolder,
Boolean inDoCopy)
//----------------------------------------------------------------------------------------
{
// display modal dialog
// if (!NET_IsOffline()) // ? 97/08/13 someone removed this line.
// 98/01/26 it's because moving messages can take some time - even offline
{
short stringID = (inDoCopy ? 19 : 15 ); // Copying / Moving Messages
CStr255 commandString;
::GetIndString(commandString, 7099, stringID);
CMailProgressWindow* progressWindow = CMailProgressWindow::CreateModalParasite(
CMailProgressWindow::res_ID_modal,
inSelection.xpPane,
commandString);
if (progressWindow)
progressWindow->SetDelay(0);
}
// Close any windows associated with these messages, if the preferences
// say we should.
CMessageWindow::NoteSelectionFiledOrDeleted(inSelection);
if (!inDoCopy)
::MSG_MoveMessagesIntoFolder(
inSelection.xpPane,
inSelection.GetSelectionList(),
inSelection.selectionSize,
inDestFolder
);
else
::MSG_CopyMessagesIntoFolder(
inSelection.xpPane,
inSelection.GetSelectionList(),
inSelection.selectionSize,
inDestFolder
);
} // CMessageFolderView::DropMessages
//----------------------------------------------------------------------------------------
Boolean CMessageFolderView::CanDoInlineEditing()
// (override from CStandardFlexTable)
//----------------------------------------------------------------------------------------
{
CMessageFolder folder(mRowBeingEdited, GetMessagePane());
Boolean outEnabled;
Boolean outUsesMark;
Char16 outMark;
Str255 outName;
FindCommandStatus(cmd_RenameFolder, outEnabled, outUsesMark, outMark, outName);
return outEnabled;
}
//----------------------------------------------------------------------------------------
void CMessageFolderView::InlineEditorTextChanged()
// (override from CStandardFlexTable)
//----------------------------------------------------------------------------------------
{
}
//----------------------------------------------------------------------------------------
void CMessageFolderView::InlineEditorDone()
// (override from CStandardFlexTable)
//----------------------------------------------------------------------------------------
{
if (mRowBeingEdited == LArray::index_Bad || !mNameEditor)
return;
CMessageFolder folder(mRowBeingEdited, GetMessagePane());
char oldName[256];
CMailFolderMixin::GetFolderNameForDisplay(oldName, folder);
CStr255 newName;
mNameEditor->GetDescriptor(newName);
if (newName != oldName)
{
char* newNameC = XP_STRDUP(newName);
if (newNameC)
{
::MSG_RenameMailFolder(GetMessagePane(), folder, newNameC);
folder.FolderInfoChanged(GetMessagePane());
XP_FREE(newNameC);
}
}
} // CMessageFolderView::InlineEditorDone
//----------------------------------------------------------------------------------------
Boolean CMessageFolderView::RowCanAcceptDrop(
DragReference inDragRef,
TableIndexT inDropRow)
// (override from CStandardFlexTable)
//----------------------------------------------------------------------------------------
{
Boolean dropOK = false;
SInt16 modifiers;
::GetDragModifiers(inDragRef, NULL, &modifiers, NULL);
Boolean doCopy = ((modifiers & optionKey) != 0);
if (inDropRow >= 1 && inDropRow <= mRows)
{
CMessageFolder destFolder(inDropRow, GetMessagePane());
CMailSelection selection;
dropOK = (GetSelectionAndCopyStatusFromDrag(
inDragRef, destFolder,
selection, doCopy));
}
if (dropOK && doCopy)
{
CursHandle copyDragCursor = ::GetCursor(curs_CopyDrag); // finder's copy-drag cursor
if (copyDragCursor != nil)
::SetCursor(*copyDragCursor);
}
else
::SetCursor(&qd.arrow);
return dropOK;
} // CMessageFolderView::RowCanAcceptDrop
//----------------------------------------------------------------------------------------
Boolean CMessageFolderView::RowCanAcceptDropBetweenAbove(
DragReference inDragRef,
TableIndexT inDropRow)
// (override from CStandardFlexTable)
//----------------------------------------------------------------------------------------
{
if (inDropRow >= 1 && inDropRow <= mRows)
{
CMailSelection selection;
if (GetSelectionFromDrag(inDragRef, selection))
{
// Dropping between rows signifies reordering. This is only allowed when the
// source pane of the drag is our own pane.
if (selection.xpPane != GetMessagePane())
return false;
CMessageFolder destFolder(inDropRow, GetMessagePane());
CMailSelection selection;
Boolean doCopy;
return GetSelectionAndCopyStatusFromDrag(
inDragRef, destFolder,
selection, doCopy);
}
}
return false;
} // CMessageFolderView::RowCanAcceptDropBetweenAbove
//----------------------------------------------------------------------------------------
void CMessageFolderView::ReceiveDragItem(
DragReference inDragRef,
DragAttributes /*inDragAttrs*/,
ItemReference /*inItemRef*/,
Rect& /*inItemBounds*/)
//----------------------------------------------------------------------------------------
{
if (mDropRow == 0) return; // FIXME: when move to top level is implemented, do that!
// What is the destination folder?
CMessageFolder destFolder(mDropRow, GetMessagePane());
// What are the items being dragged?
CMailSelection selection;
Boolean doCopy = false;
if (!GetSelectionAndCopyStatusFromDrag(inDragRef, destFolder, selection, doCopy))
return;
// We have to delay the drag in order to display any confirmation dialog
// from the BE (when moving a folder to the trash, for instance).
// Displaying a dialog in here crashes the Mac.
CDeferredDragTask* task = nil;
MSG_PaneType paneType = ::MSG_GetPaneType(selection.xpPane);
if (paneType == MSG_FOLDERPANE)
CDeferredTaskManager::Post(
new CDeferredDragFolderTask(this, selection, destFolder, doCopy), this);
else if (paneType == MSG_MESSAGEPANE)
CDeferredTaskManager::Post(
new CDeferredDragMessageTask(this, selection, destFolder, doCopy), this);
else // search pane?
DropMessages(selection, destFolder, doCopy); // devil take the hindmost.
} // CMessageFolderView::ReceiveDragItem
//----------------------------------------------------------------------------------------
void CMessageFolderView::WatchFolderForChildren(MSG_FolderInfo* inFolderInfo)
//----------------------------------------------------------------------------------------
{
CFolderWatchingTask* task = new CFolderWatchingTask(this, inFolderInfo);
CDeferredTaskManager::Post(task, this);
} // CMessageFolderView::WatchFolderForChildren
//----------------------------------------------------------------------------------------
void CMessageFolderView::DoAddNewsGroup()
//----------------------------------------------------------------------------------------
{
try
{
MSG_ViewIndex* indexList = NULL;
UInt32 numIndices = 0;
CMailSelection selection;
if (GetSelection(selection))
{
//...unless there's a single item selected, and it's a newsgroup
if (selection.selectionSize == 1)
{
MSG_ViewIndex index = *(MSG_ViewIndex*)selection.GetSelectionList();
MSG_FolderInfo* info = ::MSG_GetFolderInfo(GetMessagePane(), index);
CMessageFolder folder(info, GetMessagePane());
if (folder.IsNewsHost())
{
indexList = &index;
numIndices = 1;
}
}
}
MSG_Command(
GetMessagePane(),
MSG_AddNewsGroup,
indexList,
numIndices);
Refresh(); // works around a bug - we don't get notified.
}
catch(...)
{
}
} // CMessageFolderView::DoOpenNewsHost()
//----------------------------------------------------------------------------------------
void CMessageFolderView::DeleteSelection()
// Delete all selected folders
//----------------------------------------------------------------------------------------
{
CMailSelection selection;
if (GetSelection(selection))
{
// Deletion cannot occur if we are viewing the contents in a thread pane.
// So make a task (which clones the selection) then unselect the selected
// item (triggering an unload of the folder pane). Then post a delete
// task.
CDeleteSelectionTask* task = new CDeleteSelectionTask(this, selection);
UnselectAllCells();
CDeferredTaskManager::Post(task, this);
}
} // CMessageFolderView::DeleteSelection
//----------------------------------------------------------------------------------------
void CMessageFolderView::DoDeleteSelection(const CMailSelection& inSelection)
//----------------------------------------------------------------------------------------
{
try
{
mContext->SetCurrentCommand(cmd_Clear); // in case it was a keystroke
// If there's one mail folder in the selection being deleted, then
// watch the destination folder until the folder count changes. Otherwise
// (eg dragging newsgroups) we will wait forever, in vain...
MSG_ViewIndex* cur = (MSG_ViewIndex*)inSelection.GetSelectionList();
MSG_FolderInfo* folderToWatch = nil;
for (int i = 0; i < inSelection.selectionSize; i++, cur++)
{
MSG_FolderInfo* info = ::MSG_GetFolderInfo(GetMessagePane(), *cur);
CMessageFolder folder(info, GetMessagePane());
if (folder.IsMailFolder())
{
::MSG_GetFoldersWithFlag(
CMailNewsContext::GetMailMaster(),
MSG_FOLDER_FLAG_TRASH,
&folderToWatch,
1);
break;
}
}
MSG_CommandType cmd = UMessageLibrary::GetMSGCommand(cmd_Clear);
#if 1 // (MSG_Delete != MSG_DeleteFolder)
if (cmd == MSG_Delete)
cmd = MSG_DeleteFolder; // This can go away when winfe becomes compliant.
#endif
::MSG_Command(
GetMessagePane(),
cmd,
const_cast<MSG_ViewIndex*>(inSelection.GetSelectionList()),
inSelection.selectionSize);
if (folderToWatch)
WatchFolderForChildren(folderToWatch);
}
catch(...)
{
}
} // CMessageFolderView::DoDeleteSelection()
//----------------------------------------------------------------------------------------
void CMessageFolderView::AddRowDataToDrag(TableIndexT inRow, DragReference inDragRef)
//----------------------------------------------------------------------------------------
{
if (inRow == LArray::index_Bad || inRow > mRows)
return;
Inherited::AddRowDataToDrag(inRow, inDragRef); // does nothing right now
CMessageFolder folder(inRow, GetMessagePane());
// allow newsgroup text drags into compose window
if (folder.IsNewsgroup())
{
MSG_FolderInfo *folderInfo = folder.GetFolderInfo();
URL_Struct *theURLStruct = ::MSG_ConstructUrlForFolder(GetMessagePane(), folderInfo);
if (theURLStruct != nil)
{
OSErr err = ::AddDragItemFlavor( inDragRef, inRow, 'TEXT',
theURLStruct->address, XP_STRLEN(theURLStruct->address), flavorSenderOnly);
NET_FreeURLStruct(theURLStruct);
}
}
} // CMessageFolderView::AddRowToDrag
//----------------------------------------------------------------------------------------
Boolean CMessageFolderView::CellInitiatesDrag(const STableCell& inCell) const
//----------------------------------------------------------------------------------------
{
return (GetCellDataType(inCell) == kFolderNameColumn);
} // CMessageFolderView::CellInitiatesDrag
//----------------------------------------------------------------------------------------
Boolean CMessageFolderView::GetRowDragRgn(TableIndexT inRow, RgnHandle ioHiliteRgn) const
// The drag region is the hilite region plus the icon
// Note that the row we are dragging may or may not be selected, so don't rely
// on the selection for anything.
//----------------------------------------------------------------------------------------
{
::SetEmptyRgn(ioHiliteRgn);
Rect cellRect;
TableIndexT col = GetHiliteColumn();
if ( !col )
col = 1;
STableCell cell(inRow, col);
if (!GetLocalCellRect(cell, cellRect))
return false;
ResIDT iconID = GetIconID(inRow);
if (iconID)
{
GetIconRect(cell, cellRect, cellRect);
::IconIDToRgn(ioHiliteRgn, &cellRect, kAlignNone, iconID);
}
StRegion cellRgn;
GetRowHiliteRgn(inRow, cellRgn);
::UnionRgn(ioHiliteRgn, cellRgn, ioHiliteRgn);
CMessageFolder folder(inRow, GetMessagePane());
// If this row is an expanded folder with children, then we need to
// add each child row to the drag also.
// If one of these child rows is selected, and we are dragging the selection,
// then it will get added twice, but this should not be a problem.
if (folder.CountSubFolders() > 0 && folder.IsOpen())
{
UInt32 folderLevel = folder.GetLevel();
STableCell nextCell(cell.row + 1, 1);
StRegion tempRgn;
while (GetNextCell(nextCell))
{
CMessageFolder subFolder(nextCell.row, GetMessagePane());
UInt32 subFolderLevel = subFolder.GetLevel();
if (subFolderLevel <= folderLevel)
break;
Inherited::GetRowDragRgn(nextCell.row, tempRgn);
::UnionRgn(tempRgn, ioHiliteRgn, ioHiliteRgn);
}
}
return true;
} // CStandardFlexTable::GetRowHiliteRgn
//----------------------------------------------------------------------------------------
void CMessageFolderView::GetInfo()
//----------------------------------------------------------------------------------------
{
CMessageFolder folder(GetSelectedFolder());
if (folder.GetFolderInfo())
UGetInfo::ConductFolderInfoDialog(folder, this);
}
//----------------------------------------------------------------------------------------
void CMessageFolderView::OpenRow(TableIndexT inRow)
// See also CFolderThreadController::ListenToMessage
//----------------------------------------------------------------------------------------
{
CMessageFolder folder(inRow, GetMessagePane());
if (folder.IsMailServer())
{
UGetInfo::ConductFolderInfoDialog(folder, this);
return;
}
if (folder.IsNewsHost())
{
MSG_Host* selectedHost = MSG_GetHostForFolder(folder);
CNewsSubscriber::DoSubscribeNewsGroup(selectedHost);
return;
}
if (!folder.CanContainThreads())
return;
Boolean forceNewWindow = false;
if (GetSelectedRowCount() > 1 && inRow != GetTableSelector()->GetFirstSelectedRow())
{
STableCell cell(inRow, 1);
if (CellIsSelected(cell))
forceNewWindow = true;
}
CThreadWindow* threadWindow
= CThreadWindow::FindAndShow(
folder.GetFolderInfo(),
CThreadWindow::kMakeNew,
cmd_Nothing,
forceNewWindow); // Force new window for multiple selection.
} // CMessageFolderView::OpenRow
//----------------------------------------------------------------------------------------
void CMessageFolderView::GetLongWindowDescription(CStr255& outDescription)
//----------------------------------------------------------------------------------------
{
::GetIndString(outDescription, 7099, 11); // "Message Center For ^0"
char buffer[256]; int bufferLength = sizeof(buffer);
::PREF_GetCharPref("mail.identity.username", buffer, &bufferLength);
::StringParamText(outDescription, buffer);
}
//----------------------------------------------------------------------------------------
void CMessageFolderView::SelectionChanged()
//----------------------------------------------------------------------------------------
{
Inherited::SelectionChanged();
TableIndexT rowCount = GetSelectedRowCount();
URL_Struct* url = nil;
char entryName[128];
entryName[0] = '\0';
if (rowCount == 1)
{
CMailSelection selection;
GetSelection( selection );
MSG_ViewIndex index = *(MSG_ViewIndex*)selection.GetSelectionList();
MSG_FolderInfo* info = MSG_GetFolderInfo(GetMessagePane(), index);
MSG_FolderLine folderLine;
XP_Bool gotIt = ::MSG_GetFolderLineById(
CMailNewsContext::GetMailMaster(),
info,
&folderLine);
if (gotIt)
{
url = ::MSG_ConstructUrlForFolder(GetMessagePane(), info);
strcpy(entryName, folderLine.name);
}
}
else
{
// Use the name in the location bar for any potential bookmarks...
url = ::MSG_ConstructUrlForPane(GetMessagePane());
CStr255 tempString;
GetLongWindowDescription(tempString);
strcpy(entryName, tempString);
}
if (url && *entryName)
{
// i18n problem- we need to convert entryName to UTF8 before call SHIST_CreateHistryEntry
// We didn't do that because mail/news is not alive yet....
History_entry* theNewEntry = SHIST_CreateHistoryEntry(
url,
entryName);
SHIST_AddDocument(*mContext, theNewEntry);
}
XP_FREEIF(url);
}
//----------------------------------------------------------------------------------------
void CMessageFolderView::ListenToMessage(MessageT inMessage, void* ioParam)
//----------------------------------------------------------------------------------------
{
// button messages.
if (!IsOnDuty() || !ObeyCommand(inMessage, ioParam))
{
Inherited::ListenToMessage(inMessage, ioParam);
}
} // CMessageFolderView::ListenToMessage
//----------------------------------------------------------------------------------------
Boolean CMessageFolderView::FindMessageLibraryCommandStatus(
CommandT inCommand,
Boolean &outEnabled,
Boolean &outUsesMark,
Char16 &outMark,
Str255 outName)
// returns false if not a msglib command.
//----------------------------------------------------------------------------------------
{
// Interpret MarkSelectedRead as "mark all read" (ie, in this folder)
if (inCommand == cmd_MarkSelectedRead)
inCommand = cmd_MarkAllRead;
return Inherited::FindMessageLibraryCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
}
//----------------------------------------------------------------------------------------
void CMessageFolderView::FindCommandStatus(
CommandT inCommand,
Boolean &outEnabled,
Boolean &outUsesMark,
Char16 &outMark,
Str255 outName)
//----------------------------------------------------------------------------------------
{
// Preprocessing before calling UMessageLibrary
switch (inCommand)
{
case cmd_NewFolder:
outEnabled = true;
return;
case cmd_NewNewsgroup:
MSG_FolderInfo* folderInfo = GetSelectedFolder();
inCommand = cmd_NewFolder;
if (folderInfo != nil)
{
CMessageFolder folder(folderInfo, GetMessagePane());
if (folder.IsNewsgroup() || folder.IsNewsHost())
inCommand = cmd_NewNewsgroup;
}
break;
case cmd_OpenSelection: // enabled in base class
{
MSG_FolderInfo* folderInfo = GetSelectedFolder();
if (folderInfo != nil)
{
CMessageFolder folder(folderInfo, GetMessagePane());
short strID = 0;
if (folder.IsNewsgroup())
strID = kOpenDiscussionStrID;
else if (folder.IsMailServer())
strID = kOpenMailServerStrID;
else if (folder.IsNewsHost())
strID = kOpenNewsServerStrID;
else if (folder.IsMailFolder())
strID = kOpenFolderStrID;
if (strID != 0)
::GetIndString(outName, kMailNewsMenuStrings, strID);
}
break;
}
case cmd_OpenSelectionNewWindow:
{
MSG_FolderInfo* folderInfo = GetSelectedFolder();
if (folderInfo != nil)
{
CMessageFolder folder(folderInfo, GetMessagePane());
if (folder.IsMailServer() || folder.IsNewsHost())
{
outEnabled = false;
return;
}
}
break;
}
case cmd_GetMoreMessages:
CStr255 cmdStr;
CStr255 numStr;
::GetIndString(cmdStr, kMailNewsMenuStrings, kNextChunkMessagesStrID);
::NumToString(CPrefs::GetLong(CPrefs::NewsArticlesMax), numStr);
cmdStr += numStr;
memcpy(outName, (StringPtr)cmdStr, cmdStr.Length() + 1);
break;
case cmd_Stop:
if (mStillLoading)
{
outEnabled = true; // stop button on, nothing else.
return;
}
break;
#if 0
// 97/10/20. Fall through to the inherited version.
// We don't handle it as a menu command - only internally.
case cmd_NewsGroups: // Expand news host
case cmd_MailNewsFolderWindow: // Expand mail host
outEnabled = true;
return;
#endif // 0
case cmd_GetInfo:
if (GetSelectedRowCount() != 1)
{
outEnabled = false;
return;
}
outEnabled = true;
return;
case cmd_Clear:
folderInfo = GetSelectedFolder();
if (folderInfo != nil) {
CMessageFolder folder(folderInfo, GetMessagePane());
if (!folder.IsMailServer())
outEnabled = true;
}
return;
case cmd_AddToBookmarks:
{
MSG_FolderInfo* folderInfo = GetSelectedFolder();
if (folderInfo != nil)
{
CMessageFolder folder(folderInfo, GetMessagePane());
if (folder.IsIMAPMailFolder() || folder.IsNewsHost())
{
outEnabled = false;
return;
}
}
break; // call inherited::
}
} // switch
if (!mStillLoading && FindMessageLibraryCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName))
return;
switch (inCommand)
{
case cmd_OpenNewsHost:
case cmd_AddNewsgroup:
case cmd_SubscribeNewsgroups:
outEnabled = !mStillLoading;
break;
default:
Inherited::FindCommandStatus(
inCommand, outEnabled, outUsesMark, outMark, outName);
break;
}
} // CMessageFolderView::FindCommandStatus
//----------------------------------------------------------------------------------------
Boolean CMessageFolderView::ObeyCommand(
CommandT inCommand,
void *ioParam)
//----------------------------------------------------------------------------------------
{
if (!mContext)
return false;
Boolean cmdHandled = false;
CNSContext* originalContext = mContext; // in case we close the window & delete it!
CommandT saveCommand = mContext->GetCurrentCommand();
mContext->SetCurrentCommand(inCommand);
switch (inCommand)
{
case msg_TabSelect:
return (IsVisible()); // Allow selection only if pane is visible
#if 0
// This now HAS to be handled by the top commander (application), because the behavior
// has to be different depending on whether we are in a message center window or a 3-pane
// thread window.
case cmd_NewsGroups: // Select first news host
case cmd_MailNewsFolderWindow: // Select first mail host
SelectFirstFolderWithFlags(
inCommand == cmd_NewsGroups
? MSG_FOLDER_FLAG_NEWS_HOST
: MSG_FOLDER_FLAG_MAIL);
cmdHandled = true;
break;
#endif // 0
case cmd_SecurityInfo:
MWContext * context = *mContext;
SECNAV_SecurityAdvisor( context, NULL );
cmdHandled =true;
break;
//-----------------------------------
// News
//----------------------------------------------------------------------------------------
case cmd_OpenNewsHost:
CNewsSubscriber::DoAddNewsHost();
cmdHandled = true;
break;
case cmd_SubscribeNewsgroups:
MSG_Host* selectedHost = MSG_GetHostForFolder(GetSelectedFolder());
CNewsSubscriber::DoSubscribeNewsGroup(selectedHost);
cmdHandled = true;
break;
case cmd_AddNewsgroup:
DoAddNewsGroup();
cmdHandled = true;
break;
//-----------------------------------
// Special cases
//----------------------------------------------------------------------------------------
#if 0
// Not needed - have inline editing now (and the menu item is gone).
case cmd_RenameFolder:
UpdateMailFolderMenusOnNextUpdate();
break;
#endif
case cmd_NewFolder:
case cmd_NewNewsgroup:
{
MSG_FolderInfo* folderInfo = GetSelectedFolder();
CMessageFolder folder(folderInfo, GetMessagePane());
if (folderInfo && (folder.IsNewsgroup() || folder.IsNewsHost()))
inCommand = cmd_NewNewsgroup; // no 'cmdHandled = true' here
else
{
UFolderDialogs::ConductNewFolderDialog(folder);
cmdHandled = true;
}
break;
}
}
//-----------------------------------
// MSGLIB commands
//-----------------------------------
if (!cmdHandled)
cmdHandled = ObeyMessageLibraryCommand(inCommand, ioParam)
|| Inherited::ObeyCommand(inCommand, ioParam);
//-----------------------------------
// Cleanup
//-----------------------------------
// The following test against originalContext protects against the cases (quit, close)
// when the object has been deleted. The test against cmdHandled protects against
// re-entrant calls to ListenToMessage.
if (cmdHandled && mContext == originalContext)
mContext->SetCurrentCommand(cmd_Nothing);
if (! cmdHandled)
mContext->SetCurrentCommand(saveCommand);
return cmdHandled;
} // CMessageFolderView::ObeyCommand
#if defined(QAP_BUILD)
//----------------------------------------------------------------------------------------
void CMessageFolderView::GetQapRowText(
TableIndexT inRow,
char* outText,
UInt16 inMaxBufferLength) const
// Calculate the text and (if ioRect is not passed in as null) a rectangle that fits it.
// Return result indicates if any of the text is visible in the cell
//----------------------------------------------------------------------------------------
{
if (!outText || inMaxBufferLength == 0)
return;
cstring rowText("");
char tempStr[cMaxMailFolderNameLength];
CMessageFolder folder(inRow, GetMessagePane());
short colCount = mTableHeader->CountVisibleColumns();
CMailNewsWindow * myWindow = dynamic_cast<CMailNewsWindow*>(LWindow::FetchWindowObject(GetMacPort()));
if (!myWindow) return;
for (short col = 1; col <= colCount; col ++)
{
STableCell aCell(inRow, col);
LTableHeader::SColumnData * colData = mTableHeader->GetColumnData(col);
if (!colData) break;
LPane * colPane = myWindow->FindPaneByID(colData->paneID);
if (!colPane) break;
// get column name
CStr255 descriptor;
colPane->GetDescriptor(descriptor);
rowText += descriptor;
rowText += "=\042";
// add cell text
switch (GetCellDataType(aCell))
{
case kFolderNameColumn:
Boolean expanded;
if (CellHasDropFlag(aCell, expanded))
{
if (expanded)
rowText += "-";
else
rowText += "+";
}
else
rowText += " ";
CMailFolderMixin::GetFolderNameForDisplay(tempStr, folder);
NET_UnEscape(tempStr);
rowText += tempStr;
break;
case kFolderNumUnreadColumn:
if (folder.CanContainThreads())
if (folder.CountMessages() != 0)
{
sprintf(tempStr, "%d", folder.CountUnseen());
rowText += tempStr;
}
break;
case kFolderNumTotalColumn:
if (folder.CanContainThreads())
if (folder.CountMessages() != 0)
{
sprintf(tempStr, "%d", folder.CountMessages());
rowText += tempStr;
}
break;
}
if (col < colCount)
rowText += "\042 | ";
else
rowText += "\042\r";
}
strncpy(outText, (char*)rowText, inMaxBufferLength);
outText[inMaxBufferLength - 1] = '\0';
} // CMessageFolderView::GetQapRowText
#endif //QAP_BUILD