Mozilla/mozilla/cmd/xfe/src/ThreadView.cpp
akkana d42d73c42b 226857: Normandy landing didn't include kini's notification center fix.
git-svn-id: svn://10.0.0.236/trunk@4882 18797224-902f-48f8-a5cc-f745e15eee43
1998-07-02 01:31:12 +00:00

3763 lines
101 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) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
ThreadView.cpp -- presents view of mail threads.
Created: Chris Toshok <toshok@netscape.com>, 7-Aug-96.
*/
#include "MozillaApp.h"
#include "ThreadView.h"
#include "MsgFrame.h"
#include "FolderFrame.h"
#include "FolderMenu.h"
#include "ViewGlue.h"
#if defined(USE_MOTIF_DND)
#include "OutlinerDrop.h"
#endif /* USE_MOTIF_DND */
#include "xpassert.h"
#include "xfe.h"
#include "icondata.h"
#include "msgcom.h"
#if defined(USE_ABCOM)
#include "ABListSearchView.h"
#endif /* USE_ABCOM */
//#include "allxpstr.h"
#include "felocale.h" /* for fe_ConvertToLocalEncoding */
#include "xp_mem.h"
#include "Xfe/Xfe.h"
#include <Xm/ArrowB.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/PanedW.h>
#include "MNSearchFrame.h"
#include "MailFilterDlg.h"
#include "LdapSearchFrame.h"
#include "prefs.h"
#include "prefapi.h"
#ifdef DEBUG_toshok
#define D(x) x
#else
#define D(x)
#endif
#ifdef DEBUG_dora
#define DD(x) x
#else
#define DD(x)
#endif
#define OUTLINER_GEOMETRY_PREF "mail.threadpane.outliner_geometry"
#define MESSAGEPANE_HEIGHT_PREF "mail.threadpane.messagepane_height"
#include "xpgetstr.h"
/*
extern int MSG_HasAttachments(MSG_Pane* pane, MessageKey msgKey, XP_Bool *pHasThem);
*/
extern int XFE_RE;
extern int XFE_WINDOW_TITLE_NEWSGROUP;
extern int XFE_WINDOW_TITLE_FOLDER;
extern int XFE_SIZE_IN_LINES;
extern int XFE_SIZE_IN_BYTES;
extern int XFE_THREAD_OUTLINER_COLUMN_SUBJECT;
extern int XFE_THREAD_OUTLINER_COLUMN_DATE;
extern int XFE_THREAD_OUTLINER_COLUMN_PRIORITY;
extern int XFE_THREAD_OUTLINER_COLUMN_STATUS;
extern int XFE_THREAD_OUTLINER_COLUMN_SENDER;
extern int XFE_THREAD_OUTLINER_COLUMN_RECIPIENT;
extern int XP_STATUS_NEW;
extern int XP_STATUS_REPLIED_AND_FORWARDED;
extern int XP_STATUS_FORWARDED;
extern int XP_STATUS_REPLIED;
extern int MK_MSG_CANCEL_MESSAGE;
extern int MK_MSG_DELETE_SEL_MSGS;
extern int XFE_DND_MESSAGE_ERROR;
const int XFE_ThreadView::OUTLINER_COLUMN_SUBJECT = 0;
const int XFE_ThreadView::OUTLINER_COLUMN_SENDERRECIPIENT = 1;
const int XFE_ThreadView::OUTLINER_COLUMN_UNREADMSG = 2;
const int XFE_ThreadView::OUTLINER_COLUMN_DATE = 3;
const int XFE_ThreadView::OUTLINER_COLUMN_PRIORITY = 4;
const int XFE_ThreadView::OUTLINER_COLUMN_FLAG = 5;
const int XFE_ThreadView::OUTLINER_COLUMN_STATUS = 6;
const int XFE_ThreadView::OUTLINER_COLUMN_SIZE = 7;
// Minimum and maximum sizes for the paned window panes:
#define PANE_MIN 50
#define PANE_MAX 6000
fe_icon XFE_ThreadView::threadonIcon = { 0 };
fe_icon XFE_ThreadView::threadoffIcon = { 0 };
MenuSpec XFE_ThreadView::priority_popup_submenu[] = {
{ xfeCmdSetPriorityHighest, PUSHBUTTON },
{ xfeCmdSetPriorityHigh, PUSHBUTTON },
{ xfeCmdSetPriorityNormal, PUSHBUTTON },
{ xfeCmdSetPriorityLow, PUSHBUTTON },
{ xfeCmdSetPriorityLowest, PUSHBUTTON },
{ NULL }
};
MenuSpec XFE_ThreadView::news_popup_spec[] = {
{ xfeCmdOpenSelected, PUSHBUTTON },
// open in new window
MENU_SEPARATOR,
// Setting the call data to non-null is a signal to commandToString
// not to reset the menu string
{ xfeCmdReplyToSender, PUSHBUTTON, NULL, NULL, False, "reply-to-sender" },
{ xfeCmdReplyToAll, PUSHBUTTON, NULL, NULL, False, "reply-to-all" },
{ xfeCmdReplyToNewsgroup, PUSHBUTTON, NULL, NULL, False, "reply-to-newsgroup" },
{ xfeCmdReplyToSenderAndNewsgroup, PUSHBUTTON, NULL, NULL, False, "reply-to-sender-and-newsgroup" },
{ xfeCmdForwardMessage, PUSHBUTTON },
{ xfeCmdForwardMessageQuoted, PUSHBUTTON },
{ xfeCmdForwardMessageInLine, PUSHBUTTON },
MENU_SEPARATOR,
{ "addToABSubmenu", CASCADEBUTTON,
(MenuSpec *) &addrbk_submenu_spec },
MENU_SEPARATOR,
{ xfeCmdIgnoreThread, PUSHBUTTON },
{ xfeCmdWatchThread, PUSHBUTTON },
MENU_SEPARATOR,
{ "fileSubmenu", DYNA_CASCADEBUTTON, NULL, NULL, False, (void*)xfeCmdMoveMessage, XFE_FolderMenu::generate },
{ xfeCmdDeleteMessage, PUSHBUTTON },
{ xfeCmdSaveMessagesAs, PUSHBUTTON },
{ xfeCmdPrint, PUSHBUTTON },
{ NULL }
};
MenuSpec XFE_ThreadView::mail_popup_spec[] = {
{ xfeCmdOpenSelected, PUSHBUTTON },
MENU_SEPARATOR,
// Setting the call data to non-null is a signal to commandToString
// not to reset the menu string
{ xfeCmdReplyToSender, PUSHBUTTON, NULL, NULL, False, "reply-to-sender" },
{ xfeCmdReplyToAll, PUSHBUTTON, NULL, NULL, False, "reply-to-all" },
{ xfeCmdForwardMessage, PUSHBUTTON },
{ xfeCmdForwardMessageQuoted, PUSHBUTTON },
{ xfeCmdForwardMessageInLine, PUSHBUTTON },
MENU_SEPARATOR,
{ "addToABSubmenu", CASCADEBUTTON,
(MenuSpec *) &addrbk_submenu_spec },
MENU_SEPARATOR,
{ xfeCmdIgnoreThread, PUSHBUTTON },
{ xfeCmdWatchThread, PUSHBUTTON },
MENU_SEPARATOR,
{ "changePriority", CASCADEBUTTON, priority_popup_submenu },
MENU_SEPARATOR,
{ "fileSubmenu", DYNA_CASCADEBUTTON, NULL, NULL, False, (void*)xfeCmdMoveMessage, XFE_FolderMenu::generate },
{ xfeCmdDeleteMessage, PUSHBUTTON },
{ xfeCmdSaveMessagesAs, PUSHBUTTON },
{ xfeCmdPrint, PUSHBUTTON },
{ NULL }
};
MenuSpec XFE_ThreadView::addrbk_submenu_spec[] = {
{ xfeCmdAddSenderToAddressBook, PUSHBUTTON },
{ xfeCmdAddAllToAddressBook, PUSHBUTTON },
// { xfeCmdAddCardToAddressBook, PUSHBUTTON } ?
{ NULL }
};
extern "C" void fe_showSubscribeDialog(XFE_NotificationCenter *toplevel,
Widget parent, MWContext *context,
MSG_Host *host = NULL);
XFE_ThreadView::XFE_ThreadView(XFE_Component *toplevel_component,
Widget parent,
XFE_View *parent_view, MWContext *context,
MSG_Pane *p)
: XFE_MNListView(toplevel_component, parent_view, context, p)
{
/* initialize
*/
m_nLoadingFolders = 0;
m_frameDeleted = False;
/* timer
*/
m_scrollTimer = 0 ;
m_targetIndex = MSG_VIEWINDEXNONE;
#if HANDLE_CMD_QUEUE
m_lastLoadedInd = MSG_VIEWINDEXNONE;
m_lastLoadedKey = MSG_MESSAGEKEYNONE;
m_lineChanged = MSG_VIEWINDEXNONE;
m_selected = NULL;
m_selectedCount = 0;
m_deleted = NULL;
m_deletedCount = 0;
m_collapsed = NULL;
m_collapsedCount = 0;
#endif /* HANDLE_CMD_QUEUE */
Widget panedw;
int num_columns = 8;
XtWidgetGeometry arrow_geo;
static int default_column_widths[] = {30, 20, 3, 20, 9, 3, 15, 6};
panedw = XtVaCreateWidget("panedw",
xmPanedWindowWidgetClass,
parent,
NULL);
// create the outliner message list.
m_outliner = new XFE_Outliner("messageList",
this,
getToplevel(),
panedw,
FALSE, // constantSize
TRUE, // hasHeadings
num_columns,
5,
default_column_widths,
OUTLINER_GEOMETRY_PREF);
// initialize the icons if they haven't already been
{
Pixel bg_pixel;
XtVaGetValues(m_outliner->getBaseWidget(), XmNbackground, &bg_pixel, 0);
initMessageIcons(getToplevel()->getBaseWidget(),
getToplevel()->getFGPixel(),
bg_pixel);
}
// now that we've created the icons, we can size the two icon-only columns to be
// the widths required of the pixmaps.
m_outliner->setColumnWidth ( OUTLINER_COLUMN_UNREADMSG, msgUnreadIcon.width + 2 /* for the outliner's shadow */);
m_outliner->setColumnWidth ( OUTLINER_COLUMN_FLAG, msgFlagIcon.width + 2 /* for the outliner's shadow */);
m_outliner->setPipeColumn( OUTLINER_COLUMN_SUBJECT );
m_outliner->setMultiSelectAllowed( True );
m_outliner->setColumnResizable( OUTLINER_COLUMN_UNREADMSG, False );
m_outliner->setColumnResizable( OUTLINER_COLUMN_FLAG, False );
m_outliner->setHideColumnsAllowed( True );
#if !defined(USE_MOTIF_DND)
fe_dnd_CreateDrop(m_outliner->getBaseWidget(), drop_func, this);
#endif /* USE_MOTIF_DND */
XtVaSetValues(m_outliner->getBaseWidget(),
XmNallowResize, TRUE,
XmNpaneMinimum, PANE_MIN, // should this be a resource?
XmNpaneMaximum, PANE_MAX, // why is the limit in HPaned 1000???
NULL);
m_outliner->show();
// create the arrow button stuff
m_arrowform = XtVaCreateManagedWidget("arrowform",
xmFormWidgetClass,
panedw,
XmNallowResize, FALSE,
XmNskipAdjust, TRUE,
NULL);
m_arrowb = XtVaCreateManagedWidget("arrowb",
xmArrowButtonWidgetClass,
m_arrowform,
XmNleftAttachment, XmATTACH_FORM,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_NONE,
XmNarrowDirection, XmARROW_DOWN,
XmNshadowThickness, 0,
NULL);
XtAddCallback(m_arrowb, XmNactivateCallback, toggleMsgExpansionCallback, this);
// Arrow label should be blank initially.
XmString tempString = XmStringCreateSimple(" ");
m_arrowlabel = XtVaCreateManagedWidget("arrowlabel",
xmLabelWidgetClass,
m_arrowform,
XmNleftAttachment, XmATTACH_WIDGET,
XmNleftWidget, m_arrowb,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNalignment, XmALIGNMENT_BEGINNING,
XmNlabelString, tempString,
NULL);
XmStringFree(tempString);
arrow_geo.request_mode = CWHeight;
XtQueryGeometry(m_arrowform, NULL, &arrow_geo);
XtVaSetValues(m_arrowform,
XmNpaneMaximum, arrow_geo.height,
XmNpaneMinimum, arrow_geo.height,
NULL);
// create the message viewing area.
m_msgview = new XFE_MsgView(toplevel_component, panedw, this, m_contextData);
addView(m_msgview);
XtVaSetValues(m_msgview->getBaseWidget(),
XmNallowResize, TRUE,
XmNpaneMinimum, PANE_MIN, // should this be a resource?
XmNpaneMaximum, PANE_MAX, // why is the limit in PanedW 1000???
NULL);
m_msgview->registerInterest(XFE_MsgView::spacebarAtMsgBottom,
this,
(XFE_FunctionNotification)spaceAtMsgEnd_cb);
m_msgview->registerInterest(XFE_MsgView::messageHasChanged,
this,
(XFE_FunctionNotification)newMessageLoading_cb);
getToplevel()->registerInterest(XFE_Frame::allConnectionsCompleteCallback,
this,
(XFE_FunctionNotification)allConnectionsComplete_cb);
if (!p)
setPane(MSG_CreateThreadPane(m_contextData,
XFE_MNView::m_master));
m_msgExpanded = TRUE;
{
Widget scrolled = XtNameToWidget (m_msgview->getBaseWidget(), "*scroller");
int32 message_pane_desired_height;
PREF_GetIntPref(MESSAGEPANE_HEIGHT_PREF, &message_pane_desired_height);
XtVaSetValues(scrolled,
XmNheight, message_pane_desired_height,
NULL);
m_msgview->show();
}
/* safe default, for now. It'll be overriden (if need be), when
a folder is loaded. */
m_displayingDraft = FALSE;
m_commandPending = noPendingCommand;
m_getNewMsg = False;
m_selectionAfterDeleting = MSG_VIEWINDEXNONE;
m_popup = NULL;
m_folderInfo = NULL;
#if defined(USE_ABCOM)
int error =
AB_SetShowPropertySheetForEntryFunc((MSG_Pane *) m_pane,
&XFE_ABListSearchView::ShowPropertySheetForEntryFunc);
#endif /* USE_ABCOM */
setBaseWidget(panedw);
}
XFE_ThreadView::~XFE_ThreadView()
{
D(printf ("In XFE_ThreadView::~XFE_ThreadView()\n");)
/* save off the height of the message pane. */
{
Dimension message_pane_height;
Widget scrolled = XtNameToWidget (m_msgview->getBaseWidget(), "*scroller");
XtVaGetValues(scrolled,
XmNheight, &message_pane_height,
NULL);
PREF_SetIntPref(MESSAGEPANE_HEIGHT_PREF, (int32)message_pane_height);
}
delete m_outliner;
destroyPane();
if (m_popup)
delete m_popup;
// XFE_View destroys m_msgview for us.
}
void XFE_ThreadView::setGetNewMsg(XP_Bool b)
{
m_getNewMsg = b;
}
fe_icon*
XFE_ThreadView::flagToIcon(int folder_flags, int message_flags)
{
if (folder_flags & MSG_FOLDER_FLAG_NEWSGROUP)
return (message_flags & MSG_FLAG_READ ? &newsPostIcon : &newsNewIcon);
else if (folder_flags & MSG_FOLDER_FLAG_DRAFTS)
return &draftIcon;
else if (message_flags & MSG_FLAG_IMAP_DELETED
|| message_flags & MSG_FLAG_EXPUNGED)
return &deletedIcon;
else if (message_flags & MSG_FLAG_ATTACHMENT)
{
return &mailMessageAttachIcon;
}
else if (folder_flags & MSG_FOLDER_FLAG_TEMPLATES)
{
return &templateIcon;
}
else
{
return (message_flags & MSG_FLAG_READ ? &mailMessageReadIcon : &mailMessageUnreadIcon);
}
}
#if defined(USE_MOTIF_DND)
fe_icon_data*
XFE_ThreadView::flagToIconData(int folder_flags, int message_flags)
{
if (folder_flags & MSG_FOLDER_FLAG_NEWSGROUP)
return (message_flags & MSG_FLAG_READ ? &MN_Newspost : &MN_NewsNew);
else if (folder_flags & MSG_FOLDER_FLAG_DRAFTS)
return &MN_Draftfile;
else if (message_flags & MSG_FLAG_IMAP_DELETED
else if (folder_flags & MSG_FOLDER_FLAG_DRAFTS)
|| message_flags & MSG_FLAG_EXPUNGED)
return &MN_Delete;
else
return (message_flags & MSG_FLAG_READ ? &MN_MailRead : &MN_MailUnread);
}
#endif /* USE_MOTIF_DND */
void
XFE_ThreadView::initMessageIcons(Widget widget,
Pixel bg_pixel,
Pixel fg_pixel)
{
static Boolean init_icons_done = False;
if (init_icons_done)
return;
init_icons_done = True;
if (!mailMessageReadIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&mailMessageReadIcon,
NULL,
MN_MailRead.width, MN_MailRead.height,
MN_MailRead.mono_bits, MN_MailRead.color_bits, MN_MailRead.mask_bits, FALSE);
if (!mailMessageUnreadIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&mailMessageUnreadIcon,
NULL,
MN_MailUnread.width, MN_MailUnread.height,
MN_MailUnread.mono_bits, MN_MailUnread.color_bits, MN_MailUnread.mask_bits, FALSE);
if (!draftIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&draftIcon,
NULL,
MN_Draftfile.width, MN_Draftfile.height,
MN_Draftfile.mono_bits, MN_Draftfile.color_bits, MN_Draftfile.mask_bits, FALSE);
if (!templateIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&templateIcon,
NULL,
MN_Templatefile.width, MN_Templatefile.height,
MN_Templatefile.mono_bits, MN_Templatefile.color_bits, MN_Templatefile.mask_bits, FALSE);
if (!newsPostIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&newsPostIcon,
NULL,
MN_Newspost.width, MN_Newspost.height,
MN_Newspost.mono_bits, MN_Newspost.color_bits, MN_Newspost.mask_bits, FALSE);
if (!newsNewIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&newsNewIcon,
NULL,
MN_NewsNew.width, MN_NewsNew.height,
MN_NewsNew.mono_bits, MN_NewsNew.color_bits, MN_NewsNew.mask_bits, FALSE);
if (!msgReadIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&msgReadIcon,
NULL,
MN_DotRead.width, MN_DotRead.height,
MN_DotRead.mono_bits, MN_DotRead.color_bits, MN_DotRead.mask_bits, FALSE);
if (!msgUnreadIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&msgUnreadIcon,
NULL,
MN_Unread.width, MN_Unread.height,
MN_Unread.mono_bits, MN_Unread.color_bits, MN_Unread.mask_bits, FALSE);
if (!msgFlagIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&msgFlagIcon,
NULL,
MN_Flag.width, MN_Flag.height,
MN_Flag.mono_bits, MN_Flag.color_bits, MN_Flag.mask_bits, FALSE);
if (!mailMessageAttachIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&mailMessageAttachIcon,
NULL,
MN_MailAttach.width, MN_MailAttach.height,
MN_MailAttach.mono_bits, MN_MailAttach.color_bits, MN_MailAttach.mask_bits, FALSE);
if (!threadonIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&threadonIcon,
NULL,
threadon.width, threadon.height,
threadon.mono_bits, threadon.color_bits,
threadon.mask_bits, FALSE);
if (!threadoffIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&threadoffIcon,
NULL,
threadoff.width, threadoff.height,
threadoff.mono_bits, threadoff.color_bits,
threadoff.mask_bits, FALSE);
if (!openSpoolIgnoredIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&openSpoolIgnoredIcon,
NULL,
MN_ThreadIgnoreO.width, MN_ThreadIgnoreO.height,
MN_ThreadIgnoreO.mono_bits, MN_ThreadIgnoreO.color_bits,
MN_ThreadIgnoreO.mask_bits, FALSE);
if (!closedSpoolIgnoredIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&closedSpoolIgnoredIcon,
NULL,
MN_ThreadIgnore.width, MN_ThreadIgnore.height,
MN_ThreadIgnore.mono_bits, MN_ThreadIgnore.color_bits,
MN_ThreadIgnore.mask_bits, FALSE);
if (!openSpoolWatchedIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&openSpoolWatchedIcon,
NULL,
MN_ThreadWatchO.width, MN_ThreadWatchO.height,
MN_ThreadWatchO.mono_bits, MN_ThreadWatchO.color_bits,
MN_ThreadWatchO.mask_bits, FALSE);
if (!closedSpoolWatchedIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&closedSpoolWatchedIcon,
NULL,
MN_ThreadWatch.width, MN_ThreadWatch.height,
MN_ThreadWatch.mono_bits, MN_ThreadWatch.color_bits,
MN_ThreadWatch.mask_bits, FALSE);
if (!openSpoolNewIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&openSpoolNewIcon,
NULL,
MN_ThreadNew/*O*/.width, MN_ThreadNew/*O*/.height,
MN_ThreadNew/*O*/.mono_bits, MN_ThreadNew/*O*/.color_bits,
MN_ThreadNew/*O*/.mask_bits, FALSE);
if (!closedSpoolNewIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&closedSpoolNewIcon,
NULL,
MN_ThreadNew.width, MN_ThreadNew.height,
MN_ThreadNew.mono_bits, MN_ThreadNew.color_bits,
MN_ThreadNew.mask_bits, FALSE);
if (!openSpoolIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&openSpoolIcon,
NULL,
MN_ThreadO.width, MN_ThreadO.height,
MN_ThreadO.mono_bits, MN_ThreadO.color_bits,
MN_ThreadO.mask_bits, FALSE);
if (!closedSpoolIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&closedSpoolIcon,
NULL,
MN_Thread.width, MN_Thread.height,
MN_Thread.mono_bits, MN_Thread.color_bits,
MN_Thread.mask_bits, FALSE);
if (!deletedIcon.pixmap)
fe_NewMakeIcon(widget,
fg_pixel,
bg_pixel,
&deletedIcon,
NULL,
MN_Delete.width, MN_Delete.height,
MN_Delete.mono_bits, MN_Delete.color_bits,
MN_Delete.mask_bits, FALSE);
}
#if HANDLE_CMD_QUEUE
/* It looks like a selectInvalid here
*/
void XFE_ThreadView::processCmdQueue()
{
int count =0;
int *Arr = NULL;
if (m_deletedCount && m_deleted) {
count = m_deletedCount;
Arr = m_deleted;
}/* else if */
#if defined(DEBUG_tao)
printf("\n->XFE_ThreadView::processCmdQueue, count=%d", count);
if (count > 1)
XP_ASSERT(0);
#endif
int lastInd = count?Arr[count-1]:-1;
for (int i=count-2; i >= 0; i--)
if (Arr[i] < lastInd)
lastInd--;
int nLines = MSG_GetNumLines(m_pane);
if (lastInd >= nLines)
/* the worst case is -1 ;
* which we do deal with it in paneChanged already!
*/
lastInd = nLines-1;
if (lastInd >= 0 &&
m_lastLoadedInd != MSG_VIEWINDEXNONE)
showMessage(lastInd);
#if defined(DEBUG_tao)
else
printf("\n->XFE_ThreadView::processCmdQueue,m_lastLoadedInd=%d,",
m_lastLoadedInd);
#endif
/* final step
*/
/* reset
*/
XP_FREEIF(m_selected);
m_selectedCount = 0;
XP_FREEIF(m_deleted);
m_deletedCount = 0;
XP_FREEIF(m_collapsed);
m_collapsedCount = 0;
}
#endif /* HANDLE_CMD_QUEUE */
#if defined(DEL_5_0)
void
XFE_ThreadView::listChangeStarting(XP_Bool /* asynchronous */,
MSG_NOTIFY_CODE notify,
MSG_ViewIndex /* where */,
int32 /* num */)
{
#if defined(DEBUG_tao)
int listChangeDepth = m_outliner->getListChangeDepth()-1;
printf("\n>>XFE_ThreadView::listChangeStarting, depth=%d, m_lastLoadedInd=%d",
listChangeDepth, m_lastLoadedInd);
#endif
if (notify == MSG_NotifyScramble ||
notify == MSG_NotifyAll) {
m_lastLoadedInd = MSG_VIEWINDEXNONE;
}/* if */
else if (notify == MSG_NotifyNone) {
}/* MSG_NotifyNone */
}
#endif /* DEL_5_0 */
void
XFE_ThreadView::listChangeFinished(XP_Bool /* asynchronous */,
MSG_NOTIFY_CODE notify,
MSG_ViewIndex where,
int32 num)
{
int listChangeDepth = m_outliner->getListChangeDepth()-1;
#if defined(DEBUG_tao)
printf("\n>>XFE_ThreadView::listChangeFinished, depth=%d, m_lastLoadedInd=%d",
listChangeDepth, m_lastLoadedInd);
#endif
if (notify == MSG_NotifyNone &&
where == 0 &&
num == 0 &&
listChangeDepth == 0 &&
m_deletedCount &&
m_deleted) {
processCmdQueue();
}/* */
else if (notify == MSG_NotifyScramble ||
notify == MSG_NotifyAll) {
m_lastLoadedInd = MSG_GetMessageIndexForKey(m_pane,
m_lastLoadedKey,
False);
}/* if */
else if (notify == MSG_NotifyChanged) {
m_lineChanged = where;
/* when a msg header info changed on certain row,
backend will use this notification to warn fe.
we are suppose to re-acquire line m_messageLine info
from the backend and invalidate this row on display only
*/
acquireLineData((int)m_lineChanged);
return;
}/* if */
else if (notify == MSG_NotifyInsertOrDelete &&
m_lastLoadedInd != MSG_VIEWINDEXNONE) {
/* there was a msg loaded
*/
if (num < 0) {
/* 1. collapsing ??
*/
if ((m_lineChanged != MSG_VIEWINDEXNONE) &&
(m_lineChanged == (where -1)) && /* essential */
(listChangeDepth == 0)) { /* must be collapsing */
/* collapsed
*/
if ((m_lastLoadedInd >= where) &&
(m_lastLoadedInd < (where-num))) {
/* one of the "reply" is being hidden
* selection would go to thread leader;
* thus needs reload right away
*/
/* load the thread leader: where -1*/
if (!m_deletedCount && !m_deleted) {
m_deleted = (int *) XP_CALLOC(1, sizeof(int));
m_deleted[m_deletedCount++] = where-1;
processCmdQueue();
}/* if */
#if 0
else
XP_ASSERT(0);
#endif
}/* if collapsed */
else {
#if defined(DEBUG_tao)
printf("\n***XFE_ThreadView::listChangeFinished, collapsing not selected\n");
#endif /* DEBUG_tao */
m_lastLoadedInd += num; /* re-adjust */
}/* else */
}/* collapsed */
else if (where == m_lastLoadedInd) {
/* the selected one is gone
*/
if (!m_deletedCount && !m_deleted) {
m_deleted = (int *) XP_CALLOC(1, sizeof(int));
m_deleted[m_deletedCount++] = where;
if (listChangeDepth == 0) // non-nested
#if 1
processCmdQueue();
#endif
}/* if */
#if 0
else
XP_ASSERT(0);
#endif
}/* where == m_lastLoadedInd */
else if (where <= m_lastLoadedInd)
m_lastLoadedInd += num; /* re-adjust */
}/* num < 0 */
else if (num == 0) {
/* SPECIAL case: the header got deleted
*/
/* we do not care deletion on non-focusing line
*/
if (m_lastLoadedInd == where) {
/* deleted
*/
if (!m_deletedCount && !m_deleted) {
m_deleted = (int *) XP_CALLOC(1, sizeof(int));
m_deleted[m_deletedCount++] = where;
processCmdQueue();
}/* if */
#if 0
else
XP_ASSERT(0);
#endif
#if defined(DEBUG_tao)
printf("\n**>SPECIAL case:listChangeFinished=%d, m_deletedCount=%d\n",
where, m_deletedCount);
#endif
}/* m_lastLoadedInd == where */
}/* if num == 0 */
else if (num > 0 && where <= m_lastLoadedInd)
m_lastLoadedInd += num; /* re-adjust */
}/* notify == MSG_NotifyInsertOrDelete */
#if defined(DEBUG_tao)
printf("\n<<XFE_ThreadView::listChangeFinished, m_lastLoadedInd=%d",
m_lastLoadedInd);
#endif
m_lineChanged = MSG_VIEWINDEXNONE;
}/* XFE_ThreadView::listChangeFinished() */
void
XFE_ThreadView::paneChanged(XP_Bool asynchronous,
MSG_PANE_CHANGED_NOTIFY_CODE code,
int32 value)
{
#if defined(DEBUG_tao)
printf("\n XFE_ThreadView::paneChanged, pane=0x%x, asynchronous=%d, code=%d, value=%d",
m_pane, asynchronous, code, value);
#endif
switch (code)
{
case MSG_PaneNotifyFolderDeleted:
{
/* bug 95564: check folderInfo before closing
*/
MSG_FolderInfo *deleted = (MSG_FolderInfo *) value;
DD(printf("Blank out message view...\n");)
#if defined(USE_3PANE)
if (m_folderInfo == deleted) {
/* clear msgPane
*/
m_msgview->loadMessage(deleted, MSG_MESSAGEKEYNONE );
showMessage(-1);
m_outliner->change(0,0,0);
}/* if m_folderInfo == deleted */
#else
m_msgview->loadMessage(deleted, MSG_MESSAGEKEYNONE );
if (m_folderInfo == deleted) {
/* test frame type
*/
XFE_Frame *frame = (XFE_Frame*)m_toplevel;
if (frame &&
FRAME_MAILNEWS_THREAD == frame->getType()) {
/* standalone frame
*/
if (!m_frameDeleted) {
frame->delete_response();
m_frameDeleted = True;
}/* if */
}/* if */
}/* if m_folderInfo == deleted */
#endif /* USE_3PANE */
#if defined(DEBUG_tao)
else
printf("\n---Wrong folder IGNORing MSG_PaneNotifyFolderDeleted\n");
#endif
}
/* shall we update banner or simply return?
*/
return;
case MSG_PaneNotifyCopyFinished:
#if defined(DEBUG_tao)
printf("\n++XFE_ThreadView, MSG_PaneNotifyCopyFinished++\n");
/* It happens in loading mails.
* XP_ASSERT(0);
*/
#endif
break;
case MSG_PaneNotifyMessageLoaded:
#if defined(DEBUG_tao)
printf("\n++XFE_ThreadView, MSG_PaneNotifyMessageLoaded++\n");
XP_ASSERT(0);
#endif
break;
case MSG_PaneNotifyLastMessageDeleted:
/* clear msgPane
*/
showMessage(-1);
break;
case MSG_PaneNotifyMessageDeleted:
{
// If we delete a message from the threadview, and
// there's currently a message view showing that message,
// we need to tell the msg view so it can pop down:
XFE_MozillaApp::theApp()->notifyInterested(msgWasDeleted, (void*)value);
#if HANDLE_CMD_QUEUE
#if defined(DEBUG_tao)
MessageKey id = (MessageKey) value;
MSG_ViewIndex index = MSG_GetMessageIndexForKey(m_pane,
id,
False);
printf("\n MSG_PaneNotifyMessageDeleted,index=%d", index);
#endif
#endif /* HANDLE_CMD_QUEUE */
}
break;
case MSG_PaneNotifyFolderLoadedSync:
case MSG_PaneNotifyFolderLoaded:
{
D(printf ("Inside pane changed -- folder loaded\n");)
#if defined(DEBUG_tao)
if (code == MSG_PaneNotifyFolderLoadedSync)
printf("\n**XFE_ThreadView::paneChanged: code == MSG_PaneNotifyFolderLoadedSync \n");
#endif
if (m_nLoadingFolders > 0) {
/* release the block
*/
m_outliner->setBlockSel(False);
m_nLoadingFolders--;
}/* if */
/* Call this after folder is loaded
*/
if ((code == MSG_PaneNotifyFolderLoaded) &&
m_getNewMsg) {
/* Do it for movemail/pop3 only
*/
if (fe_globalPrefs.mail_server_type != MAIL_SERVER_IMAP)
getNewMail();
/* reset
*/
m_getNewMsg = False;
}/* if */
/* select first msg
*/
if (m_commandPending == noPendingCommand
&& m_outliner->getTotalLines() > 0)
{
m_commandPending = selectByIndex;
m_pendingSelectionIndex = 0;
/* when a msg being loaded after folder loaded, we should change
focus of the three pane UI to thread view bug #109659
*/
getToplevel()->notifyInterested(XFE_MNListView::changeFocus, (void*) this);
/* end of #109659 */
}
/* we only actually handle the command here
* if the folder was loaded synchronously.
*/
if (code == MSG_PaneNotifyFolderLoadedSync)
handlePendingCommand();
XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::MNChromeNeedsUpdating);
notifyInterested(XFE_MNView::bannerNeedsUpdating, (void*)code);
XP_Bool invalidate_needed = False;
if (MSG_GetToggleStatus(m_pane, MSG_SortByThread, NULL, 0) == MSG_Checked)
{
invalidate_needed = m_outliner->getDescendantSelectAllowed() == False;
m_outliner->setDescendantSelectAllowed( True );
m_outliner->setSortColumn(-1, OUTLINER_SortAscending);
}
else
{
invalidate_needed = m_outliner->getDescendantSelectAllowed() == True;
m_outliner->setDescendantSelectAllowed( False );
}
if (invalidate_needed)
m_outliner->invalidate();
}
break;
default:
break;
}
// This can result in flickering of the banner, but if we don't call it,
// the number of unread and total messages isn't updated correctly
XFE_MNListView::paneChanged(asynchronous, code, value);
}
void
XFE_ThreadView::loadFolder(MSG_FolderInfo *folderInfo)
{
MSG_FolderLine folderLine;
char *newsgroup_format = XP_GetString(XFE_WINDOW_TITLE_NEWSGROUP);
char *folder_format = XP_GetString(XFE_WINDOW_TITLE_FOLDER);
char *window_title;
int window_title_length;
// must be valid.
XP_ASSERT(folderInfo);
if (!folderInfo) return;
// only need to do everything below here if the folder being
// loaded is different than what's currently displayed.
if (m_folderInfo != folderInfo) {
// clear the currently display message, since we're in a different folder now.
DD(printf("Load Folder: Blank out message view...\n");)
m_msgview->loadMessage(folderInfo, MSG_MESSAGEKEYNONE );
updateExpandoFlippyText(-1);
m_outliner->deselectAllItems();
MSG_GetFolderLineById(XFE_MNView::getMaster(), folderInfo, &folderLine);
#if defined(USE_MOTIF_DND)
m_outliner->enableDragDrop(this,
NULL, /* no dropping -- of anything but outliner columns. */
XFE_ThreadView::getDragTargets,
XFE_ThreadView::getDragIconData,
XFE_ThreadView::dragConvert);
#endif /* USE_MOTIF_DND */
if (folderLine.flags & MSG_FOLDER_FLAG_NEWSGROUP)
{
// it's a newsgroup
window_title_length = strlen(newsgroup_format) - 2 /* %s */ + strlen(folderLine.name) + 1;
window_title = (char*)XP_CALLOC(sizeof(char), window_title_length);
sprintf (window_title, newsgroup_format, folderLine.name);
m_displayingNewsgroup = TRUE;
m_displayingDraft = FALSE;
#if !defined(USE_MOTIF_DND)
m_outliner->setDragType( FE_DND_NEWS_MESSAGE, &newsPostIcon,
this, (fe_dnd_SourceDropFunc)&XFE_ThreadView::source_drop_func);
#endif /* USE_MOTIF_DND */
}
else
{
window_title_length = strlen(folder_format) - 2 /* %s */ + strlen(folderLine.name) + 1;
window_title = (char*)XP_CALLOC(sizeof(char), window_title_length);
sprintf (window_title, folder_format, folderLine.name);
if (folderLine.flags & MSG_FOLDER_FLAG_DRAFTS)
{
// it's the draft folder
m_displayingDraft = TRUE;
m_displayingNewsgroup = FALSE;
#if !defined(USE_MOTIF_DND)
m_outliner->setDragType(FE_DND_MAIL_MESSAGE, &mailMessageUnreadIcon,
this,
(fe_dnd_SourceDropFunc)&XFE_ThreadView::source_drop_func);
#endif /* USE_MOTIF_DND */
}
else
{
// it's a normal mail folder
m_displayingNewsgroup = FALSE;
m_displayingDraft = FALSE;
#if !defined(USE_MOTIF_DND)
m_outliner->setDragType(FE_DND_MAIL_MESSAGE, &mailMessageUnreadIcon,
this,
(fe_dnd_SourceDropFunc)&XFE_ThreadView::source_drop_func);
#endif /* USE_MOTIF_DND */
}
}
// getContainer()->setTitle(window_title);
XP_FREE(window_title);
D(printf("Loading folder into ThreadView\n");)
/* if it doesn't have categories, we can load it directly
into the threadview's pane. */
m_folderInfo = folderInfo;
/* keep track of on loading folders
*/
if (m_nLoadingFolders == 0) {
m_nLoadingFolders++; // FYI
/* block selection
*/
m_outliner->setBlockSel(True);
}/* if */
else
XP_ASSERT(0);
MSG_LoadFolder(m_pane, m_folderInfo);
XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::MNChromeNeedsUpdating);
/* either open or close the message view, depending on the folder prefs */
{
int32 new_folder_prefs = MSG_GetFolderPrefFlags(m_folderInfo);
if (new_folder_prefs & MSG_FOLDER_PREF_FEVALID)
{
if (new_folder_prefs & MSG_FOLDER_PREF_ONEPANE)
{
if (m_msgview->isShown())
{
toggleMsgExpansion();
}
}
else
{
if (!m_msgview->isShown())
{
toggleMsgExpansion();
}
}
}
}
}/* if diff folder */
else /* if the same loaded folder, we need to invoke handlePendingCommand */
handlePendingCommand();
}
MSG_FolderInfo *
XFE_ThreadView::getFolderInfo()
{
return m_folderInfo;
}
void
XFE_ThreadView::updateExpandoFlippyText(int row)
{
char *subjectStr;
XmString subject;
XmString oldsubject = 0;
char *oldsubjectStr = NULL;
XP_Bool needsChange = TRUE;
#if defined(DEBUG_tao)
printf("\nXFE_ThreadView::updateExpandoFlippyText(row=%d)\n",row);
#endif
if (row == -1)
{
subjectStr = "";
}
else
{
acquireLineData(row);
subjectStr = getColumnText(OUTLINER_COLUMN_SUBJECT);
}
XtVaGetValues (m_arrowlabel,
XmNlabelString, &oldsubject,
NULL);
if (XmStringGetLtoR(oldsubject, XmFONTLIST_DEFAULT_TAG, &oldsubjectStr))
if (oldsubjectStr && !strcmp(oldsubjectStr, subjectStr))
{
needsChange = FALSE;
if (oldsubjectStr) XtFree(oldsubjectStr);
}
if (needsChange)
{
subject = XmStringCreate (subjectStr, XmFONTLIST_DEFAULT_TAG);
XtVaSetValues (m_arrowlabel,
XmNlabelString, subject,
NULL);
XmStringFree (subject);
}
XmStringFree (oldsubject);
XFlush(XtDisplay(m_arrowlabel));
}
//
// show a message at a particular row in the thread's outliner.
// sending -1 to this function will clear the label and the message
// area.
//
void
XFE_ThreadView::showMessage(int row)
{
/* sometimes this can get called before we've loaded a folder. */
if (!m_folderInfo)
return;
if (row > -1) {
m_lastLoadedInd = (MSG_ViewIndex) row;
m_lastLoadedKey = MSG_GetMessageKey(m_pane, row);
#if defined(DEBUG_tao)
printf("\nXFE_ThreadView::showMessage m_lastLoadedInd=%d\n",
m_lastLoadedInd);
#endif
}/* if */
/*
** if the message area is expanded we just load the message, since
** we will turn around and call the makeVisible/selectItemExclusive/etc
** in our newMessageLoading method.
** If the message area isn't expanded, we handle it here.
*/
if (m_msgExpanded)
{
MSG_ViewIndex index;
MessageKey key;
MSG_FolderInfo *info = NULL;
MSG_GetCurMessage(m_msgview->getPane(), &info, &key, &index);
if (key != m_lastLoadedKey) {
m_msgview->loadMessage(m_folderInfo,
(row == -1 ?
MSG_MESSAGEKEYNONE :
MSG_GetMessageKey(m_pane, row)));
}/* if */
}
else
{
if (row != -1)
{
m_outliner->makeVisible(row);
m_outliner->selectItemExclusive(row);
}
}
updateExpandoFlippyText(row);
}
char *
XFE_ThreadView::commandToString(CommandType cmd, void * calldata, XFE_CommandInfo* info)
{
#define IS_CMD(command) cmd == (command)
if (IS_CMD(xfeCmdToggleMessageExpansion))
{
if (m_msgview->isShown())
return stringFromResource("hideMsgAreaCmdString");
else
return stringFromResource("showMsgAreaCmdString");
}
else if (IS_CMD(xfeCmdDeleteAny) || IS_CMD(xfeCmdDeleteMessage) || IS_CMD(xfeCmdCancelMessages)) {
if (isDisplayingNews())
return XP_GetString(MK_MSG_CANCEL_MESSAGE);
else
return XP_GetString(MK_MSG_DELETE_SEL_MSGS);
}
else if ( calldata &&
(IS_CMD(xfeCmdReplyToSender)
|| IS_CMD(xfeCmdReplyToAll)
|| IS_CMD(xfeCmdReplyToNewsgroup)
|| IS_CMD(xfeCmdReplyToSenderAndNewsgroup) ) )
{
// if calldata is non-null for a Reply button,
// that's a signal not to change the
// widget name in the resources file:
return 0;
}
else
return XFE_MNListView::commandToString(cmd, calldata, info);
#undef IS_CMD
}
Boolean
XFE_ThreadView::isCommandSelected(CommandType cmd, void *calldata, XFE_CommandInfo*)
{
#define IS_CMD(command) cmd == (command)
if (IS_CMD(xfeCmdShowAllHeaders)
|| IS_CMD(xfeCmdShowNormalHeaders)
|| IS_CMD(xfeCmdShowBriefHeaders)
|| IS_CMD(xfeCmdWrapLongLines)
|| IS_CMD(xfeCmdViewAttachmentsInline)
|| IS_CMD(xfeCmdEditMessage)
|| IS_CMD(xfeCmdOpenSelected)
|| IS_CMD(xfeCmdUpdateMessageCount)
|| IS_CMD(xfeCmdViewAttachmentsAsLinks))
{
return m_msgExpanded && m_msgview->isCommandSelected(cmd);
}
else if (IS_CMD(xfeCmdPrintSetup)
|| IS_CMD(xfeCmdPrintPreview))
return True;
else if (IS_CMD(xfeCmdSortAscending))
{
return ( MSG_GetToggleStatus( m_pane, MSG_SortBackward, NULL, 0 )
!= MSG_Checked );
}
else if (IS_CMD(xfeCmdSortDescending))
{
return ( MSG_GetToggleStatus( m_pane, MSG_SortBackward, NULL, 0 )
== MSG_Checked );
}
else
return XFE_MNListView::isCommandSelected(cmd, calldata);
#undef IS_CMD
}
Boolean
XFE_ThreadView::isCommandEnabled(CommandType cmd, void *calldata, XFE_CommandInfo* info)
{
#define IS_CMD(command) cmd == (command)
if (IS_CMD(xfeCmdDeleteAny)|| IS_CMD(xfeCmdDeleteMessage)) {
/* Given a flag or set of flags, returns the number of folders that have
* that flag set. If the result pointer is not NULL, fills it in with the
* list of folders (providing up to resultsize entries).
*/
int32 resultsize = MSG_GetFoldersWithFlag(XFE_MNView::getMaster(),
MSG_FOLDER_FLAG_TRASH,
NULL,
0);
if (resultsize == 0)
return False;
}/* IS_CMD(xfeCmdDeleteMessage */
const int *selected;
int count;
m_outliner->getSelection(&selected, &count);
#if defined(USE_ABCOM)
if ((IS_CMD(xfeCmdAddSenderToAddressBook)||
IS_CMD(xfeCmdAddAllToAddressBook)) &&
count > 0) {
XP_List *abList = AB_AcquireAddressBookContainers(m_contextData);
XP_ASSERT(abList);
int nDirs = XP_ListCount(abList);
XP_Bool selectable = False;
if (!nDirs)
return selectable;
/* XFE always returns the first one
*/
AB_ContainerInfo *destAB =
(AB_ContainerInfo *) XP_ListGetObjectNum(abList,1);
XP_ASSERT(destAB);
int error = MSG_AddToAddressBookStatus(m_pane,
commandToMsgCmd(cmd),
(MSG_ViewIndex*)selected,
count,
&selectable, NULL, NULL, NULL,
destAB);
error = AB_ReleaseContainersList(abList);
return selectable;
}/* if */
#endif /* USE_ABCOM */
// DeleteMessage stands for CancelMessage in the ThreadView,
// so intercept it early:
if ( (IS_CMD(xfeCmdDeleteAny) ||
IS_CMD(xfeCmdDeleteMessage) || IS_CMD(xfeCmdCancelMessages))
&& isDisplayingNews() )
{
XP_Bool selectable = False;
MSG_CommandStatus(m_pane, MSG_CancelMessage,
/* just need some integer pointer here...*/
(MSG_ViewIndex*)selected, count,
&selectable, NULL, NULL, NULL);
return selectable;
}
// Check if selectThread should be enabled or not...
if ( IS_CMD(xfeCmdSelectThread))
{
Boolean status =
MSG_GetToggleStatus(m_pane, MSG_SortByThread, NULL, 0)==MSG_Checked;
return ((count > 0) && status);
}
if ( !m_displayingNewsgroup && IS_CMD(xfeCmdEditConfiguration) )
{
// Manage Mail Account
return True;
}
if ( m_displayingNewsgroup && IS_CMD(xfeCmdModerateDiscussion) )
{
// Moderate Newsgroup Discussion
return True;
}
if (IS_CMD(xfeCmdUndo)
|| IS_CMD(xfeCmdRedo)) {
XP_Bool selectable = False;
MSG_CommandType msg_cmd = commandToMsgCmd(cmd);
MSG_CommandStatus(m_pane, msg_cmd,
/* just need some integer pointer here...*/
(MSG_ViewIndex*)selected, count,
&selectable, NULL, NULL, NULL);
#if defined(DEBUG_tao_)
if (IS_CMD(xfeCmdUndo))
printf("\n XFE_ThreadView, MSG_CommandStatus:: m_pane=%x, xfeCmdUndo=%d", m_pane, selectable);
else if (IS_CMD(xfeCmdRedo))
printf("\n XFE_ThreadView, MSG_CommandStatus:: m_pane=%x, xfeCmdRedo=%d", m_pane, selectable);
#endif
return selectable;
}
MSG_MotionType nav_cmd;
nav_cmd = commandToMsgNav(cmd);
if ((nav_cmd != (MSG_MotionType)~0)&&
(!(IS_CMD(xfeCmdBack)||IS_CMD(xfeCmdForward))))
{
XP_Bool selectable = FALSE;
if (count == 1)
MSG_NavigateStatus(m_pane, nav_cmd, selected[0],
&selectable, NULL);
return selectable;
}
else if (IS_CMD(xfeCmdToggleMessageExpansion))
{
return True;
}
else if (IS_CMD(xfeCmdGetNextNNewMsgs))
{
return m_displayingNewsgroup;
}
else if (IS_CMD(xfeCmdEditPreferences))
{
return True;
}
// Always available even if nothing is selected:
else if (IS_CMD(xfeCmdComposeArticle)
|| IS_CMD(xfeCmdComposeArticleHTML)
|| IS_CMD(xfeCmdComposeArticlePlain)
|| IS_CMD(xfeCmdPrintSetup)
|| IS_CMD(xfeCmdPrintPreview)
|| IS_CMD(xfeCmdUpdateMessageCount))
{
return True;
}
// the move and copy commands are available if there are messages selected.
else if (IS_CMD(xfeCmdMoveMessage)
|| IS_CMD(xfeCmdCopyMessage)
|| IS_CMD(xfeCmdSetPriorityHighest)
|| IS_CMD(xfeCmdSetPriorityHigh)
|| IS_CMD(xfeCmdSetPriorityNormal)
|| IS_CMD(xfeCmdSetPriorityLow)
|| IS_CMD(xfeCmdSetPriorityLowest)
|| IS_CMD(xfeCmdSetPriorityNone)
|| IS_CMD(xfeCmdEditMessage)
|| IS_CMD(xfeCmdOpenSelected))
{
return (count > 0);
}
// the sort commands are always available, if there are messages
else if (IS_CMD(xfeCmdSortBySender)
|| IS_CMD(xfeCmdSortByDate)
|| IS_CMD(xfeCmdSortBySubject)
|| IS_CMD(xfeCmdSortByPriority)
|| IS_CMD(xfeCmdSortByThread)
|| IS_CMD(xfeCmdSortByMessageNumber)
|| IS_CMD(xfeCmdSortBySize)
|| IS_CMD(xfeCmdSortByFlag)
|| IS_CMD(xfeCmdSortByStatus)
|| IS_CMD(xfeCmdSortByUnread)
|| IS_CMD(xfeCmdSortAscending)
|| IS_CMD(xfeCmdSortDescending)
|| IS_CMD(xfeCmdMarkMessageByDate))
{
return MSG_GetNumLines(m_pane) > 0;
}
// commands that work on the msgview.
else if (IS_CMD(xfeCmdShowAllHeaders)
|| IS_CMD(xfeCmdPrint)
|| IS_CMD(xfeCmdShowNormalHeaders)
|| IS_CMD(xfeCmdShowBriefHeaders)
|| IS_CMD(xfeCmdWrapLongLines)
|| IS_CMD(xfeCmdViewAttachmentsInline)
|| IS_CMD(xfeCmdViewAttachmentsAsLinks)
|| IS_CMD(xfeCmdViewPageSource)
|| IS_CMD(xfeCmdFindInObject)
|| IS_CMD(xfeCmdFindAgain))
{
return m_msgExpanded && m_msgview->isCommandEnabled(cmd);
}
else if (IS_CMD(xfeCmdSearch))
{
return !XP_IsContextBusy(m_contextData);
}
else if (IS_CMD(xfeCmdExpand)
|| IS_CMD(xfeCmdExpandAll)
|| IS_CMD(xfeCmdCollapse)
|| IS_CMD(xfeCmdCollapseAll))
return True;
else
{
return XFE_MNListView::isCommandEnabled(cmd, calldata, info);
}
#undef IS_CMD
}
Boolean
XFE_ThreadView::handlesCommand(CommandType cmd, void *calldata, XFE_CommandInfo*)
{
#define IS_CMD(command) cmd == (command)
if (IS_CMD(xfeCmdToggleMessageExpansion)
|| IS_CMD(xfeCmdGetNewMessages)
|| IS_CMD(xfeCmdGetNextNNewMsgs)
|| IS_CMD(xfeCmdAddSenderToAddressBook)
|| IS_CMD(xfeCmdAddAllToAddressBook)
|| IS_CMD(xfeCmdEditMessage)
|| IS_CMD(xfeCmdSendMessagesInOutbox)
|| IS_CMD(xfeCmdPrint)
|| IS_CMD(xfeCmdSaveAs)
|| IS_CMD(xfeCmdReplyToSender)
|| IS_CMD(xfeCmdReplyToSenderAndNewsgroup)
|| IS_CMD(xfeCmdReplyToAll)
|| IS_CMD(xfeCmdForwardMessage)
|| IS_CMD(xfeCmdForwardMessageQuoted)
|| IS_CMD(xfeCmdForwardMessageInLine)
|| IS_CMD(xfeCmdNextMessage)
|| IS_CMD(xfeCmdNextUnreadMessage)
|| IS_CMD(xfeCmdPreviousMessage)
|| IS_CMD(xfeCmdPreviousUnreadMessage)
|| IS_CMD(xfeCmdDeleteAny)
|| IS_CMD(xfeCmdDeleteMessage)
|| IS_CMD(xfeCmdSortBySender)
|| IS_CMD(xfeCmdSortByDate)
|| IS_CMD(xfeCmdSortBySubject)
|| IS_CMD(xfeCmdSortByPriority)
|| IS_CMD(xfeCmdSortByThread)
|| IS_CMD(xfeCmdSortByMessageNumber)
|| IS_CMD(xfeCmdSortBySize)
|| IS_CMD(xfeCmdSortByFlag)
|| IS_CMD(xfeCmdSortByStatus)
|| IS_CMD(xfeCmdSortByUnread)
|| IS_CMD(xfeCmdSortAscending)
|| IS_CMD(xfeCmdSortDescending)
|| IS_CMD(xfeCmdViewNew)
|| IS_CMD(xfeCmdViewAllThreads)
|| IS_CMD(xfeCmdViewThreadsWithNew)
|| IS_CMD(xfeCmdViewWatchedThreadsWithNew)
|| IS_CMD(xfeCmdShowAllHeaders)
|| IS_CMD(xfeCmdShowNormalHeaders)
|| IS_CMD(xfeCmdShowBriefHeaders)
|| IS_CMD(xfeCmdViewAttachmentsInline)
|| IS_CMD(xfeCmdViewAttachmentsAsLinks)
|| IS_CMD(xfeCmdRot13Message)
|| IS_CMD(xfeCmdMarkMessageRead)
|| IS_CMD(xfeCmdMarkMessageUnread)
|| IS_CMD(xfeCmdMarkMessageByDate)
|| IS_CMD(xfeCmdMarkThreadRead)
|| IS_CMD(xfeCmdMarkAllMessagesRead)
|| IS_CMD(xfeCmdMarkMessage)
|| IS_CMD(xfeCmdUnmarkMessage)
|| IS_CMD(xfeCmdToggleThreadKilled)
|| IS_CMD(xfeCmdToggleThreadWatched)
|| IS_CMD(xfeCmdRenameFolder)
|| IS_CMD(xfeCmdSearch)
|| IS_CMD(xfeCmdSearchAddress)
|| IS_CMD(xfeCmdEditPreferences)
|| IS_CMD(xfeCmdWrapLongLines)
/* priorities. */
|| IS_CMD(xfeCmdSetPriorityHighest)
|| IS_CMD(xfeCmdSetPriorityHigh)
|| IS_CMD(xfeCmdSetPriorityNormal)
|| IS_CMD(xfeCmdSetPriorityLow)
|| IS_CMD(xfeCmdSetPriorityLowest)
|| IS_CMD(xfeCmdSetPriorityNone)
/* we handle these command to place more constraints on it being sensitive. */
|| IS_CMD(xfeCmdViewPageSource)
|| IS_CMD(xfeCmdFindInObject)
|| IS_CMD(xfeCmdFindAgain)
|| IS_CMD(xfeCmdShowPopup)
|| IS_CMD(xfeCmdModerateDiscussion)
|| IS_CMD(xfeCmdEditMessage)
|| IS_CMD(xfeCmdOpenSelected)
|| IS_CMD(xfeCmdUpdateMessageCount)
|| IS_CMD(xfeCmdNewFolder)
|| IS_CMD(xfeCmdCompressAllFolders)
|| IS_CMD(xfeCmdCompressFolders)
|| IS_CMD(xfeCmdAddNewsgroup)
|| IS_CMD(xfeCmdPrintSetup)
|| IS_CMD(xfeCmdPrintPreview)
|| IS_CMD(xfeCmdExpand)
|| IS_CMD(xfeCmdExpandAll)
|| IS_CMD(xfeCmdCollapse)
|| IS_CMD(xfeCmdCollapseAll)
|| IS_CMD(xfeCmdToggleKilledThreads)
|| IS_CMD(xfeCmdSelectThread)
|| IS_CMD(xfeCmdEditConfiguration)
|| IS_CMD(xfeCmdModerateDiscussion)
|| IS_CMD(xfeCmdMommy))
{
return TRUE;
}
else
{
return XFE_MNListView::handlesCommand(cmd, calldata);
}
#undef IS_CMD
}
void
XFE_ThreadView::addCollapsed(int where)
{
if (m_collapsedCount && m_collapsed)
m_collapsed = (int *) XP_REALLOC(m_collapsed,
(m_collapsedCount+1)*sizeof(int));
else
m_collapsed = (int *) XP_CALLOC(1, sizeof(int));
m_collapsed[m_collapsedCount++] = where+1;
#if defined(DEBUG_tao)
printf("\n-->addCollapsed=%d, m_collapsedCount=%d\n",
where+1, m_collapsedCount);
#endif
}
XP_Bool
XFE_ThreadView::isCollapsed(int where)
{
if (!m_collapsedCount || !m_collapsed)
return False;
for (int i=0; i < m_collapsedCount; i++)
if (m_collapsed[i] == where) {
/* clear it
* thread children's pos > 0
*/
m_collapsed[i] = 0-where;
return True;
}/* for i */
return False;
}
void
XFE_ThreadView::doCommand(CommandType cmd,
void *calldata, XFE_CommandInfo* info)
{
#define IS_CMD(command) cmd == (command)
const int *selected;
int count;
m_outliner->getSelection(&selected, &count);
if (IS_CMD(xfeCmdToggleMessageExpansion))
{
toggleMsgExpansion();
getToplevel()->notifyInterested(XFE_View::chromeNeedsUpdating);
}
#if defined(USE_ABCOM)
else if ((IS_CMD(xfeCmdAddSenderToAddressBook)||
IS_CMD(xfeCmdAddAllToAddressBook)) &&
count > 0) {
XP_List *abList = AB_AcquireAddressBookContainers(m_contextData);
XP_ASSERT(abList);
int nDirs = XP_ListCount(abList);
if (nDirs) {
/* XFE always returns the first one
*/
AB_ContainerInfo *destAB =
(AB_ContainerInfo *) XP_ListGetObjectNum(abList,1);
XP_ASSERT(destAB);
int error = MSG_AddToAddressBook(m_pane,
commandToMsgCmd(cmd),
(MSG_ViewIndex*)selected,
count,
destAB);
error = AB_ReleaseContainersList(abList);
}/* if */
}/* if */
#endif /* USE_ABCOM */
else if (IS_CMD(xfeCmdMommy))
{
fe_showFoldersWithSelected(XtParent(getToplevel()->getBaseWidget()),
/* Tao: we might need to check if this returns a
* non-NULL frame
*/
ViewGlue_getFrame(m_contextData),
NULL,
m_folderInfo);
}
else if (IS_CMD(xfeCmdShowPopup))
{
XEvent *event = info->event;
int x, y, clickrow;
Widget w = XtWindowToWidget(event->xany.display, event->xany.window);
if (m_popup)
delete m_popup;
if (w == NULL) w = m_widget;
/* Need to make the view that has the pop up the current focus so that menu items
can be enabled on the context menu again */
getToplevel()->notifyInterested(XFE_MNListView::changeFocus, (void*) this);
m_popup = new XFE_PopupMenu("popup",(XFE_Frame*)m_toplevel, // XXXXXXX
XfeAncestorFindApplicationShell(w));
if (m_displayingNewsgroup)
m_popup->addMenuSpec(news_popup_spec);
else
m_popup->addMenuSpec(mail_popup_spec);
m_outliner->translateFromRootCoords(event->xbutton.x_root,
event->xbutton.y_root,
&x, &y);
clickrow = m_outliner->XYToRow(x, y);
if (clickrow != -1) /* if it was actually in the outliner's content rows. */
{
if (! m_outliner->isSelected(clickrow))
{
m_outliner->selectItemExclusive(clickrow);
showMessage(clickrow);
}
}
m_popup->position(event);
m_popup->show();
}
else if (IS_CMD(xfeCmdGetNewMessages))
{
getNewMail();
}
else if (IS_CMD(xfeCmdAddNewsgroup))
{
// Code pasted from FolderView.cpp
D( printf ("MSG_FolderPane::addNewsgroup()\n");)
/* We can use folder info in ThreadView to get to Host */
MSG_Host *host = NULL;
host = MSG_GetHostForFolder(m_folderInfo);
fe_showSubscribeDialog(getToplevel(), getToplevel()->getBaseWidget(), m_contextData, host);
}
else if (IS_CMD(xfeCmdGetNextNNewMsgs))
{
getNewNews();
}
else if (IS_CMD(xfeCmdMarkMessageByDate))
{
markReadByDate();
}
else if (IS_CMD(xfeCmdEditPreferences))
{
fe_showMailNewsPreferences(getToplevel(), m_contextData);
}
else if (IS_CMD(xfeCmdShowAllHeaders)
|| IS_CMD(xfeCmdPrint)
|| IS_CMD(xfeCmdShowNormalHeaders)
|| IS_CMD(xfeCmdShowBriefHeaders)
|| IS_CMD(xfeCmdWrapLongLines)
|| IS_CMD(xfeCmdViewAttachmentsInline)
|| IS_CMD(xfeCmdViewAttachmentsAsLinks)
/* pass to msgview
*/
|| IS_CMD(xfeCmdBack)
|| IS_CMD(xfeCmdForward))
{
m_msgview->doCommand(cmd);
}
else if (IS_CMD(xfeCmdSetPriorityHighest)
|| IS_CMD(xfeCmdSetPriorityHigh)
|| IS_CMD(xfeCmdSetPriorityNormal)
|| IS_CMD(xfeCmdSetPriorityLow)
|| IS_CMD(xfeCmdSetPriorityLowest)
|| IS_CMD(xfeCmdSetPriorityNone))
{
MSG_PRIORITY priority = commandToPriority(cmd);
MessageKey key;
int i;
for (i = 0; i < count; i ++)
{
key = MSG_GetMessageKey(m_pane, (MSG_ViewIndex)selected[i]);
MSG_SetPriority(m_pane, key, priority);
}
}
else if (IS_CMD(xfeCmdMoveMessage))
{
MSG_FolderInfo *info = (MSG_FolderInfo*)calldata;
if (info)
{
MSG_FolderLine folderLine;
MSG_GetFolderLineById(XFE_MNView::getMaster(), info, &folderLine);
if ( folderLine.flags & MSG_FOLDER_FLAG_NEWSGROUP)
{
MSG_CopyMessagesIntoFolder(m_pane, (MSG_ViewIndex*)selected, count, info);
}
else
{
MSG_MoveMessagesIntoFolder(m_pane, (MSG_ViewIndex*)selected, count, info);
}
}
}
else if (IS_CMD(xfeCmdCopyMessage))
{
MSG_FolderInfo *info = (MSG_FolderInfo*)calldata;
if (info)
MSG_CopyMessagesIntoFolder(m_pane, (MSG_ViewIndex*)selected, count, info);
}
else if (isDisplayingNews()
&& (IS_CMD(xfeCmdDeleteMessage) || IS_CMD(xfeCmdCancelMessages) ||
IS_CMD(xfeCmdDeleteAny) ))
{
// If this is a news article, then Delete Message
// is really Cancel Message:
MSG_Command(m_pane, MSG_CancelMessage,
(MSG_ViewIndex*)selected, count);
}
else if (IS_CMD(xfeCmdExpand))
{
MSG_MessageLine mline;
MSG_GetThreadLineByIndex(m_pane, (MSG_ViewIndex)selected[0], 1,
&mline);
if ((mline.numChildren > (uint16)0)
&& ((mline.flags & MSG_FLAG_ELIDED) != (uint32)0))
MSG_ToggleExpansion(m_pane, (MSG_ViewIndex)selected[0], NULL);
}
else if (IS_CMD(xfeCmdCollapse))
{
MSG_MessageLine mline;
MSG_GetThreadLineByIndex(m_pane, (MSG_ViewIndex)selected[0], 1,
&mline);
if ((mline.numChildren > (uint16)0)
&& ((mline.flags & MSG_FLAG_ELIDED) == (uint32)0)) {
if (mline.numChildren == 1)
addCollapsed(selected[0]);
MSG_ToggleExpansion(m_pane, (MSG_ViewIndex)selected[0], NULL);
}/* if */
}
else if (IS_CMD(xfeCmdExpandAll))
{
// Note that in the following loop, getTotalLines()
// may grow each time we expand, but that's okay.
int i;
for (i=0; i < getOutliner()->getTotalLines(); ++i)
{
MSG_MessageLine mline;
MSG_GetThreadLineByIndex(m_pane, i, 1, &mline);
if ((mline.numChildren != (uint16)0)
&& ((mline.flags & MSG_FLAG_ELIDED) != (uint32)0))
MSG_ToggleExpansion(m_pane, (MSG_ViewIndex)i, NULL);
}
}
else if (IS_CMD(xfeCmdCollapseAll))
{
// Note that in the following loop, getTotalLines()
// may shrink each time we collapse, but that's okay.
int i;
for (i=0; i < getOutliner()->getTotalLines(); ++i)
{
MSG_MessageLine mline;
MSG_GetThreadLineByIndex(m_pane, i, 1, &mline);
if (mline.numChildren != (uint16)0)
{
// Now collapse the parent:
if ((mline.flags & MSG_FLAG_ELIDED) == (uint32)0) {
if (mline.numChildren == 1)
addCollapsed(i);
MSG_ToggleExpansion(m_pane, (MSG_ViewIndex)i, NULL);
}/* if */
}
}
}
else if (IS_CMD(xfeCmdDeleteMessage) || IS_CMD(xfeCmdDeleteAny) )
{
if (count == 1)
/* stop loading since we are deleting this message:
* shall we check if it is stopable?
*/
XP_InterruptContext(m_contextData);
{
MSG_Command(m_pane, MSG_DeleteMessage, (MSG_ViewIndex*)selected, count);
}
XFE_MozillaApp::theApp()->
notifyInterested(XFE_MNView::folderChromeNeedsUpdating,
getFolderInfo());
}
else if (IS_CMD(xfeCmdEditMailFilterRules))
{
fe_showMailFilterDlg(getToplevel()->getBaseWidget(),
m_contextData,m_pane);
}
else if (IS_CMD(xfeCmdSearchAddress))
{
fe_showLdapSearch(XfeAncestorFindApplicationShell(getToplevel()->getBaseWidget()),
/* Tao: we might need to check if this returns a
* non-NULL frame
*/
ViewGlue_getFrame(m_contextData),
(Chrome*)NULL);
}
else if (IS_CMD(xfeCmdSelectThread))
{
// Call Select Thread
selectThread();
}
else if (IS_CMD(xfeCmdViewNew)
|| IS_CMD(xfeCmdViewThreadsWithNew)
|| IS_CMD(xfeCmdViewWatchedThreadsWithNew)
|| IS_CMD(xfeCmdViewAllThreads)
|| IS_CMD(xfeCmdToggleKilledThreads)
|| IS_CMD(xfeCmdSortBySender)
|| IS_CMD(xfeCmdSortByDate)
|| IS_CMD(xfeCmdSortBySubject)
|| IS_CMD(xfeCmdSortByPriority)
|| IS_CMD(xfeCmdSortByThread)
|| IS_CMD(xfeCmdSortByMessageNumber)
|| IS_CMD(xfeCmdSortBySize)
|| IS_CMD(xfeCmdSortByFlag)
|| IS_CMD(xfeCmdSortByStatus)
|| IS_CMD(xfeCmdSortByUnread))
{
D(printf ("Changing view.\n");)
MSG_CommandType msg_cmd = commandToMsgCmd(cmd);
if (msg_cmd != (MSG_CommandType)~0)
{
MSG_Command(m_pane, msg_cmd, (MSG_ViewIndex*)selected, count);
/* make sure one of the selected items is still visible. */
m_outliner->getSelection(&selected, &count);
if (count > 0)
m_outliner->makeVisible(selected[0]);
if (IS_CMD(xfeCmdSortByMessageNumber))
m_outliner->setSortColumn(-1, m_outliner->getSortDirection());
}
}
else if (IS_CMD(xfeCmdOpenSelected))
{
int i;
MessageKey key;
for (i = 0; i < count; i ++)
{
key = MSG_GetMessageKey(m_pane, (MSG_ViewIndex)selected[i]);
fe_showMsg(XtParent(getToplevel()->getBaseWidget()),
/* Tao: we might need to check if this returns a
* non-NULL frame
*/
ViewGlue_getFrame(m_contextData),
NULL, m_folderInfo, key, FALSE);
}
}
else if (IS_CMD(xfeCmdSearch))
{
// We don't need to call XtParent on the base widget because
// the base widget is the real toplevel widget already...dora 12/31/96
fe_showMNSearch(XfeAncestorFindApplicationShell(getToplevel()->getBaseWidget()),
/* Tao: we might need to check if this returns a
* non-NULL frame
*/
ViewGlue_getFrame(m_contextData),
NULL, this, m_folderInfo);
}
else if (IS_CMD(xfeCmdSortDescending))
{
if ( MSG_GetToggleStatus( m_pane, MSG_SortBackward, NULL, 0 )
!= MSG_Checked )
{
MSG_Command(m_pane, MSG_SortBackward, NULL, 0);
/* make sure one of the selected items is still visible. */
m_outliner->getSelection(&selected, &count);
if (count > 0)
m_outliner->makeVisible(selected[0]);
}
}
else if (IS_CMD(xfeCmdSortAscending))
{
if ( MSG_GetToggleStatus( m_pane, MSG_SortBackward, NULL, 0 )
== MSG_Checked )
{
MSG_Command(m_pane, MSG_SortBackward, NULL, 0);
/* make sure one of the selected items is still visible. */
m_outliner->getSelection(&selected, &count);
if (count > 0)
m_outliner->makeVisible(selected[0]);
}
}
else
{
MSG_CommandType msg_cmd = commandToMsgCmd(cmd);
MSG_MotionType nav_cmd = commandToMsgNav(cmd);
if (info) {
CONTEXT_DATA(m_contextData)->stealth_cmd =
((info->event->type == ButtonRelease) &&
(info->event->xkey.state & ShiftMask));
}
if (nav_cmd == (MSG_MotionType)~0)
{
if ((msg_cmd == (MSG_CommandType)~0) ||
(msg_cmd == MSG_MailNew) ||
(msg_cmd == MSG_PostNew) )
{
XFE_MNListView::doCommand(cmd, calldata, info);
}
else {
MSG_Command(m_pane, msg_cmd, (MSG_ViewIndex*)selected, count);
/* single pane; count ==1
*/
if (IS_CMD(xfeCmdUndo)
|| IS_CMD(xfeCmdRedo)) {
MessageKey key = MSG_MESSAGEKEYNONE;
MSG_FolderInfo *folder = NULL;
if (!m_pane || !m_outliner)
return;
UndoStatus undoStatus =
MSG_GetUndoStatus(m_pane);
if ( UndoComplete == undoStatus ) {
if (MSG_GetUndoMessageKey(m_pane,
&folder, &key)
&& folder) {
if (m_folderInfo == folder) {
/* same folder
* select the message right away!
*/
MSG_ViewIndex index =
MSG_GetMessageIndexForKey(m_pane,
key,
TRUE);
if (index != MSG_VIEWINDEXNONE) {
showMessage(index);
}
}/* if */
else {
#if HANDLE_CMD_QUEUE
/* need to load new folder
*/
/* XFE: let handlePendingCmd() deal with
* this part
*/
m_commandPending = selectByKey;
m_pendingSelectionKey = key;
loadFolder(folder);
#endif /* HANDLE_CMD_QUEUE */
}/* if */
}/* if */
}/* if UndoComplete == undoStatus */
}/* if */
}/* else */
}
else
{
MSG_ViewIndex index, threadIndex;
MessageKey resultId;
MSG_FolderInfo *new_finfo;
if (count == 1)
{
m_outliner->setBlockSel(True);
MSG_ViewNavigate(m_pane, nav_cmd, selected[0],
&resultId, &index, &threadIndex,
&new_finfo);
m_outliner->setBlockSel(False);
// ViewNavigate gives a NULL folderinfo if the folder
// info won't be changing.
if (new_finfo &&
new_finfo != m_folderInfo)
{
/* insert here any navigational commands that can span folders, and
add corresponding entry in pendingCommand */
switch (nav_cmd)
{
case MSG_NextUnreadMessage:
m_commandPending = selectFirstUnread;
break;
case MSG_PreviousUnreadMessage:
m_commandPending = selectLastUnread;
break;
default:
XP_ASSERT(0);
break;
}
loadFolder(new_finfo);
}
else
{
int numLines = MSG_GetNumLines(m_pane),
idx = (int) index;
if (idx >=0 && idx < numLines)
showMessage(idx);
}
}
}
XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating,
getFolderInfo());
}
#undef IS_CMD
}
char *XFE_ThreadView::getColumnTextByMsgLine(MSG_MessageLine *msgLine, int column)
{
static char buf[1024]; /* ## Sigh... */
static char from_buf[1024]; /* ## Sigh... */
static char size_buf[100]; /* ## Sigh... */
char *tmp = NULL;
switch (column)
{
case OUTLINER_COLUMN_SUBJECT:
{
tmp = IntlDecodeMimePartIIStr(msgLine->subject, fe_LocaleCharSetID,
FALSE);
if (msgLine->flags & MSG_FLAG_HAS_RE)
{
XP_SAFE_SPRINTF(buf, sizeof(buf),
"%s", XP_GetString( XFE_RE ) );
XP_STRNCAT_SAFE(buf,
(tmp ? tmp : msgLine->subject),
sizeof(buf) - XP_STRLEN(buf));
if (tmp) XP_FREE(tmp);
return buf;
}
else
{
if (tmp)
{
XP_STRNCPY_SAFE(buf, tmp, sizeof(buf));
XP_FREE(tmp);
return buf;
}
else
{
XP_STRNCPY_SAFE(buf, msgLine->subject, sizeof(buf));
return buf;
}
}
}
case OUTLINER_COLUMN_SENDERRECIPIENT:
{
tmp = IntlDecodeMimePartIIStr(msgLine->author, fe_LocaleCharSetID, FALSE);
if (tmp)
{
XP_STRNCPY_SAFE(from_buf, tmp, sizeof(from_buf));
XP_FREE(tmp);
return from_buf;
}
else
{
XP_STRNCPY_SAFE(from_buf, msgLine->author, sizeof(from_buf));
return from_buf;
}
}
case OUTLINER_COLUMN_DATE:
{
if (msgLine->date == 0)
{
return "";
}
else
{
return (char*)MSG_FormatDate(m_pane, msgLine->date);
}
}
case OUTLINER_COLUMN_PRIORITY:
{
return priorityToString(msgLine->priority);
}
case OUTLINER_COLUMN_SIZE:
{
XP_SAFE_SPRINTF(size_buf, sizeof(size_buf),
"%ld", msgLine->messageLines);
return size_buf;
}
case OUTLINER_COLUMN_STATUS:
{
if (msgLine->flags & MSG_FLAG_NEW)
return XP_GetString(XP_STATUS_NEW);
else if ((msgLine->flags & MSG_FLAG_REPLIED)&&
(msgLine->flags & MSG_FLAG_FORWARDED))
return XP_GetString(XP_STATUS_REPLIED_AND_FORWARDED);
else if (msgLine->flags & MSG_FLAG_FORWARDED)
return XP_GetString(XP_STATUS_FORWARDED);
else if (msgLine->flags & MSG_FLAG_REPLIED)
return XP_GetString(XP_STATUS_REPLIED);
return NULL; /* ### */
}
case OUTLINER_COLUMN_UNREADMSG:
{
return NULL; // we don't have a string in this column -- only an icon.
}
case OUTLINER_COLUMN_FLAG:
{
return NULL; // we don't have a string in this column -- only an icon.
}
default:
XP_ASSERT(0);
return NULL;
}
}
/* Outlinable interface methods */
char *XFE_ThreadView::getCellTipString(int row, int column)
{
/* returned string will be duplicated by outliner
*/
char *tmp = 0;
if (row < 0) {
/* header
*/
tmp = getColumnHeaderText(column);
}/* if */
else {
/* content
*/
MSG_MessageLine* msgLine =
(MSG_MessageLine *) XP_CALLOC(1,
sizeof(MSG_MessageLine));
if (!MSG_GetThreadLineByIndex(m_pane, row, 1, msgLine))
return NULL;
/* static array; do not free
*/
tmp = getColumnTextByMsgLine(msgLine, column);
XP_FREEIF(msgLine);
}/* else */
if (tmp &&
(!m_outliner->isColTextFit(tmp, row, column)))
return tmp;
return NULL;
}
char *XFE_ThreadView::getCellDocString(int /* row */, int /* column */)
{
return NULL;
}
void *
XFE_ThreadView::ConvFromIndex(int index)
{
MessageKey id = MSG_GetMessageKey(m_pane, index);
return (void*)id;
}
int
XFE_ThreadView::ConvToIndex(void *item)
{
MessageKey id = (MessageKey)item;
MSG_ViewIndex index;
index = MSG_GetMessageIndexForKey(m_pane, id, False);
if (index == MSG_VIEWINDEXNONE)
{
MSG_MessageLine line;
if (!MSG_GetThreadLineById(m_pane, id, &line))
{
/* error while looking up line for this message.
punt */
return -1;
}
else
{
MSG_ViewIndex thread_index =
MSG_GetMessageIndexForKey(m_pane, line.threadId, False);
if (MSG_ExpansionDelta(m_pane, thread_index) > 0)
{
MSG_ToggleExpansion(m_pane, thread_index, NULL);
index = MSG_GetMessageIndexForKey(m_pane,
id, False);
}
return index;
}
}
else
{
return index;
}
}
void *
XFE_ThreadView::acquireLineData(int line)
{
m_ancestorInfo = NULL;
if (!MSG_GetThreadLineByIndex(m_pane, line, 1, &m_messageLine))
return NULL;
m_ancestorInfo = new OutlinerAncestorInfo[ m_messageLine.level + 1 ];
int i = m_messageLine.level;
int idx = line + 1;
while ( i > 0 ) {
if ( idx < m_outliner->getTotalLines()) {
int level = MSG_GetThreadLevelByIndex( m_pane, idx );
if ( level == i ) {
m_ancestorInfo[i].has_prev = TRUE;
m_ancestorInfo[i].has_next = TRUE;
i--;
idx++;
} else if ( level < i ) {
m_ancestorInfo[i].has_prev = FALSE;
m_ancestorInfo[i].has_next = FALSE;
i--;
} else {
idx++;
}
} else {
m_ancestorInfo[i].has_prev = FALSE;
m_ancestorInfo[i].has_next = FALSE;
i--;
}
}
m_ancestorInfo[0].has_prev = FALSE;
m_ancestorInfo[0].has_next = FALSE;
return &m_messageLine;
}
void
XFE_ThreadView::getTreeInfo(Boolean *expandable,
Boolean *is_expanded,
int *depth,
OutlinerAncestorInfo **ancestor)
{
XP_Bool is_line_expandable;
XP_Bool is_line_expanded;
is_line_expandable = (m_messageLine.numChildren > 0);
if (is_line_expandable)
{
is_line_expanded = (m_messageLine.flags & MSG_FLAG_ELIDED) == 0;
}
else
{
is_line_expanded = FALSE;
}
if ( ancestor )
*ancestor = m_ancestorInfo;
if (depth)
*depth = m_messageLine.level;
if (expandable)
*expandable = is_line_expandable;
if (is_expanded)
*is_expanded = is_line_expanded;
}
EOutlinerTextStyle
XFE_ThreadView::getColumnStyle(int /*column*/)
{
if (m_messageLine.flags & MSG_FLAG_EXPIRED)
return OUTLINER_Default ; /* Don't boldface dummy messages. */
else if ((m_messageLine.flags & MSG_FLAG_ELIDED) && m_messageLine.numNewChildren > 0)
return OUTLINER_Bold; /* boldface toplevel thread messages with unread children. */
else
return (m_messageLine.flags & MSG_FLAG_READ) ? OUTLINER_Default : OUTLINER_Bold;
}
char *
XFE_ThreadView::getColumnText(int column)
{
static char buf_a[1024]; /* ## Sigh... */
static char from_buf_a[1024]; /* ## Sigh... */
static char size_buf_a[100]; /* ## Sigh... */
char *tmp = NULL;
switch (column)
{
case OUTLINER_COLUMN_SUBJECT:
{
tmp = IntlDecodeMimePartIIStr(m_messageLine.subject, fe_LocaleCharSetID, FALSE);
if (m_messageLine.flags & MSG_FLAG_HAS_RE)
{
XP_STRNCPY_SAFE (buf_a, XP_GetString( XFE_RE ), sizeof(buf_a) );
XP_STRNCAT_SAFE (buf_a,
(tmp ? tmp : m_messageLine.subject),
sizeof(buf_a) - XP_STRLEN(buf_a));
if (tmp) XP_FREE(tmp);
return buf_a;
}
else
{
if (tmp)
{
XP_STRNCPY_SAFE(buf_a, tmp, sizeof(buf_a));
XP_FREE(tmp);
return buf_a;
}
else
{
return m_messageLine.subject;
}
}
}
case OUTLINER_COLUMN_SENDERRECIPIENT:
{
tmp = IntlDecodeMimePartIIStr(m_messageLine.author, fe_LocaleCharSetID, FALSE);
if (tmp)
{
XP_STRNCPY_SAFE(from_buf_a, tmp, sizeof(from_buf_a));
XP_FREE(tmp);
return from_buf_a;
}
else
{
return m_messageLine.author;
}
}
case OUTLINER_COLUMN_DATE:
{
if (m_messageLine.date == 0)
{
return "";
}
else
{
return (char*)MSG_FormatDate(m_pane, m_messageLine.date);
}
}
case OUTLINER_COLUMN_PRIORITY:
{
return priorityToString(m_messageLine.priority);
}
case OUTLINER_COLUMN_SIZE:
{
XP_SAFE_SPRINTF(size_buf_a, sizeof(size_buf_a),
"%ld", m_messageLine.messageLines);
return size_buf_a;
}
case OUTLINER_COLUMN_STATUS:
{
if (m_messageLine.flags & MSG_FLAG_NEW)
return XP_GetString(XP_STATUS_NEW);
else if ((m_messageLine.flags & MSG_FLAG_REPLIED)&&
(m_messageLine.flags & MSG_FLAG_FORWARDED))
return XP_GetString(XP_STATUS_REPLIED_AND_FORWARDED);
else if (m_messageLine.flags & MSG_FLAG_FORWARDED)
return XP_GetString(XP_STATUS_FORWARDED);
else if (m_messageLine.flags & MSG_FLAG_REPLIED)
return XP_GetString(XP_STATUS_REPLIED);
return NULL; /* ### */
}
case OUTLINER_COLUMN_UNREADMSG:
{
return NULL; // we don't have a string in this column -- only an icon.
}
case OUTLINER_COLUMN_FLAG:
{
return NULL; // we don't have a string in this column -- only an icon.
}
default:
XP_ASSERT(0);
return NULL;
}
}
fe_icon *
XFE_ThreadView::getColumnIcon(int column)
{
switch (column)
{
case OUTLINER_COLUMN_SUBJECT:
{
MSG_FolderLine folderLine;
MSG_GetFolderLineById(XFE_MNView::getMaster(), m_folderInfo, &folderLine);
return flagToIcon(folderLine.flags, m_messageLine.flags);
}
case OUTLINER_COLUMN_UNREADMSG:
return (m_messageLine.flags & MSG_FLAG_READ ? &msgReadIcon : &msgUnreadIcon);
case OUTLINER_COLUMN_FLAG:
return (m_messageLine.flags & MSG_FLAG_MARKED ? &msgFlagIcon : &msgReadIcon);
case -1: /* OUTLINER_DESCENDANT_SELECT_COLUMN */
{
if (m_messageLine.flags & MSG_FLAG_IGNORED)
{
return (m_messageLine.flags & MSG_FLAG_ELIDED ? &closedSpoolIgnoredIcon : &openSpoolIgnoredIcon);
}
else if (m_messageLine.flags & MSG_FLAG_WATCHED)
{
return (m_messageLine.flags & MSG_FLAG_ELIDED ? &closedSpoolWatchedIcon : &openSpoolWatchedIcon);
}
else if (m_messageLine.numChildren > 0)
{
if (m_messageLine.flags & MSG_FLAG_NEW
|| m_messageLine.numNewChildren > 0)
return (m_messageLine.flags & MSG_FLAG_ELIDED ? &closedSpoolNewIcon : &openSpoolNewIcon);
else
return (m_messageLine.flags & MSG_FLAG_ELIDED ? &closedSpoolIcon : &openSpoolIcon);
}
else
{
return NULL;
}
}
default:
return 0;
}
}
char *
XFE_ThreadView::getColumnName(int column)
{
switch (column)
{
case OUTLINER_COLUMN_SUBJECT:
return "Subject";
case OUTLINER_COLUMN_UNREADMSG:
return "Unread";
case OUTLINER_COLUMN_FLAG:
return "Flag";
case OUTLINER_COLUMN_DATE:
return "Date";
case OUTLINER_COLUMN_PRIORITY:
return "Priority";
case OUTLINER_COLUMN_SIZE:
return "Size";
case OUTLINER_COLUMN_STATUS:
return "Status";
case OUTLINER_COLUMN_SENDERRECIPIENT:
return "Sender";
default:
XP_ASSERT(0);
return 0;
}
}
char *
XFE_ThreadView::getColumnHeaderText(int column)
{
switch (column)
{
case OUTLINER_COLUMN_SUBJECT:
return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_SUBJECT);
case OUTLINER_COLUMN_UNREADMSG:
return 0;
case OUTLINER_COLUMN_FLAG:
return 0;
case OUTLINER_COLUMN_DATE:
return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_DATE);
case OUTLINER_COLUMN_PRIORITY:
return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_PRIORITY);
case OUTLINER_COLUMN_SIZE:
{
if (m_displayingNewsgroup)
return XP_GetString(XFE_SIZE_IN_LINES);
else
return XP_GetString(XFE_SIZE_IN_BYTES);
}
case OUTLINER_COLUMN_STATUS:
return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_STATUS);
case OUTLINER_COLUMN_SENDERRECIPIENT:
if (MSG_DisplayingRecipients(m_pane))
return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_RECIPIENT);
else
return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_SENDER);
default:
// XP_ASSERT(0);
return 0;
}
}
fe_icon *
XFE_ThreadView::getColumnHeaderIcon(int column)
{
switch (column)
{
case OUTLINER_COLUMN_UNREADMSG:
return &msgUnreadIcon;
case OUTLINER_COLUMN_FLAG:
return &msgFlagIcon;
case OUTLINER_COLUMN_SUBJECT:
if (MSG_GetToggleStatus(m_pane, MSG_SortByThread, NULL, 0) == MSG_Checked)
return &threadonIcon;
else
return &threadoffIcon;
default:
return 0;
}
}
EOutlinerTextStyle
XFE_ThreadView::getColumnHeaderStyle(int column)
{
MSG_CommandType sort_type = (MSG_CommandType)~0;
switch (column)
{
case OUTLINER_COLUMN_SENDERRECIPIENT:
sort_type = MSG_SortBySender;
break;
case OUTLINER_COLUMN_DATE:
sort_type = MSG_SortByDate;
break;
case OUTLINER_COLUMN_SUBJECT:
sort_type = MSG_SortBySubject;
break;
case OUTLINER_COLUMN_PRIORITY:
sort_type = MSG_SortByPriority;
break;
case OUTLINER_COLUMN_SIZE:
sort_type = MSG_SortBySize;
break;
case OUTLINER_COLUMN_STATUS:
sort_type = MSG_SortByStatus;
break;
case OUTLINER_COLUMN_UNREADMSG:
sort_type = MSG_SortByUnread;
break;
case OUTLINER_COLUMN_FLAG:
sort_type = MSG_SortByFlagged;
break;
}
if (sort_type == (MSG_CommandType)~0)
{
return OUTLINER_Default;
}
else
{
XP_Bool checked = MSG_GetToggleStatus(m_pane, sort_type, NULL, 0) == MSG_Checked;
XP_Bool backward = MSG_GetToggleStatus(m_pane, MSG_SortBackward, NULL, 0) == MSG_Checked;
if (checked)
{
m_outliner->setSortColumn(column,
backward ? OUTLINER_SortDescending : OUTLINER_SortAscending);
return OUTLINER_Bold;
}
else
{
return OUTLINER_Default;
}
}
}
void
XFE_ThreadView::releaseLineData()
{
delete [] m_ancestorInfo;
m_ancestorInfo = NULL;
}
XFE_CALLBACK_DEFN(XFE_ThreadView, allConnectionsComplete)(XFE_NotificationCenter *,
void *,
void *)
{
D(printf ("in all connections complete.\n");)
#if HANDLE_CMD_QUEUE
#if defined(DEBUG_tao)
printf("\n XFE_ThreadView::allConnectionsComplete\n");
#endif
if (m_deletedCount &&
m_deleted)
processCmdQueue();
#endif /* HANDLE_CMD_QUEUE */
handlePendingCommand();
}
void
XFE_ThreadView::setPendingCmdSelByKey(PendingCommand cmd, MessageKey key)
{
m_commandPending = cmd;
m_pendingSelectionKey = key;
}
void
XFE_ThreadView::handlePendingCommand()
{
switch (m_commandPending)
{
case invalidateThreadAndSelection:
/* for this case, we loop backward to the message with level 1 -- the toplevel
message in this thread, find it's num_children, and invalidate all those
lines. This fixes pipe updates and lots of other things. */
{
D(printf("handlePendingCommand(invalidateThreadAndSelection)\n");)
/* tao: Obselete deletion code; assert!
*/
XP_ASSERT(0);
break;
}
case getNewMessages:
{
D(printf("handlePendingCommand(getNewMessages)\n");)
m_commandPending = noPendingCommand;
doCommand(xfeCmdGetNewMessages);
break;
}
case selectByIndex:
{
D(printf("handlePendingCommand(selectByIndex)\n");)
D(printf(" pending selection index is %d\n", m_pendingSelectionIndex);)
m_commandPending = noPendingCommand;
if (m_pendingSelectionIndex != MSG_VIEWINDEXNONE)
showMessage(m_pendingSelectionIndex);
break;
}
case selectByKey:
{
D(printf("handlePendingCommand(selectByKey,%d)\n", m_pendingSelectionKey);)
m_commandPending = noPendingCommand;
if (m_pendingSelectionKey != MSG_MESSAGEKEYNONE)
{
/* 87274: Caldera: "Go to Message Folder" fails when
* messages are threaded.
*
* Fix: call MSG_xxxForKey() to expand the thread
* when needed.
*/
MSG_ViewIndex index =
MSG_GetMessageIndexForKey(m_pane,
m_pendingSelectionKey,
True);
D(printf (" pending selection index is %d\n", index);)
if (index != MSG_VIEWINDEXNONE)
showMessage(index);
}
break;
}
case selectFirstUnread:
{
D(printf("handlePendingCommand(selectFirstUnread)\n");)
MSG_ViewIndex index, threadIndex;
MessageKey resultId;
m_commandPending = noPendingCommand;
m_outliner->setBlockSel(True);
MSG_ViewNavigate(m_pane, MSG_FirstUnreadMessage, MSG_VIEWINDEXNONE/* ??? */,
&resultId, &index, &threadIndex, NULL);
m_outliner->setBlockSel(False);
showMessage(index);
break;
}
case selectLastUnread:
{
D(printf("handlePendingCommand(selectLastUnread)\n");)
MSG_ViewIndex index, threadIndex;
MessageKey resultId;
m_commandPending = noPendingCommand;
MSG_ViewNavigate(m_pane, MSG_LastUnreadMessage, MSG_VIEWINDEXNONE/* ??? */,
&resultId, &index, &threadIndex, NULL);
showMessage(index);
break;
}
case scrollToFirstNew:
{
D(printf("handlePendingCommand(scrollToFirstNew)\n");)
MessageKey resultId, resultingThread;
MSG_ViewIndex resultIndex = 0;
m_commandPending = noPendingCommand;
/* note: We don't expand threads here -- we scroll to the message that
starts the thread. */
/* after we do a get new mail, we end up here. We try to scroll to the
first new one. */
MSG_DataNavigate(m_pane, MSG_FirstNew, MSG_MESSAGEKEYNONE/*???*/,
&resultId, &resultingThread);
/* if there wasn't a new message, we scroll to the first unread message */
if (resultId == MSG_MESSAGEKEYNONE
|| resultingThread == MSG_MESSAGEKEYNONE)
MSG_DataNavigate(m_pane, MSG_FirstUnreadMessage, MSG_MESSAGEKEYNONE/*???*/,
&resultId, &resultingThread);
/* if there wasn't an unread message, we scroll to the last item. */
if (m_outliner->getTotalLines() > 0)
{
if (resultId == MSG_MESSAGEKEYNONE
|| resultingThread == MSG_MESSAGEKEYNONE)
{
resultIndex = (MSG_ViewIndex)m_outliner->getTotalLines() - 1;
}
else
{
resultIndex =
MSG_GetMessageIndexForKey(m_pane,
resultingThread,
False);
if (resultIndex == MSG_VIEWINDEXNONE)
resultIndex = m_outliner->getTotalLines() - 1;
}
m_outliner->makeVisible((int)resultIndex);
}
break;
}
case noPendingCommand: // we should be so lucky
D(printf ("no pending command to execute\n");)
break;
default:
XP_ASSERT(0);
break;
}
}
void
XFE_ThreadView::Buttonfunc(const OutlineButtonFuncData *data)
{
/*
** Broadcast the view is currently in focus because
** of the button clicking
*/
getToplevel()->notifyInterested(XFE_MNListView::changeFocus, (void*) this);
if (data->row == -1) // heading row.
{
const int *selected;
int count;
m_outliner->setDescendantSelectAllowed(False);
switch (data->column)
{
case OUTLINER_COLUMN_SUBJECT:
if (data->x < (threadonIcon.width + /* hack -- shadowthickness */ 4))
{
if (isCommandEnabled(xfeCmdSortByThread))
{
m_outliner->setSortColumn(-1,
OUTLINER_SortAscending);
m_outliner->setDescendantSelectAllowed(True);
doCommand(xfeCmdSortByThread);
}
}
else
{
if (isCommandEnabled(xfeCmdSortBySubject))
{
if (m_outliner->getSortColumn() == data->column)
m_outliner->toggleSortDirection();
doCommand(xfeCmdSortBySubject);
}
}
break;
case OUTLINER_COLUMN_SENDERRECIPIENT:
if (isCommandEnabled(xfeCmdSortBySender))
{
if (m_outliner->getSortColumn() == data->column)
m_outliner->toggleSortDirection();
doCommand(xfeCmdSortBySender);
}
break;
case OUTLINER_COLUMN_DATE:
if (isCommandEnabled(xfeCmdSortByDate))
{
if (m_outliner->getSortColumn() == data->column)
m_outliner->toggleSortDirection();
doCommand(xfeCmdSortByDate);
}
break;
case OUTLINER_COLUMN_PRIORITY:
if (isCommandEnabled(xfeCmdSortByPriority))
{
if (m_outliner->getSortColumn() == data->column)
m_outliner->toggleSortDirection();
doCommand(xfeCmdSortByPriority);
}
break;
case OUTLINER_COLUMN_STATUS:
if (isCommandEnabled(xfeCmdSortByStatus))
{
if (m_outliner->getSortColumn() == data->column)
m_outliner->toggleSortDirection();
doCommand(xfeCmdSortByStatus);
}
break;
case OUTLINER_COLUMN_SIZE:
if (isCommandEnabled(xfeCmdSortBySize))
{
if (m_outliner->getSortColumn() == data->column)
m_outliner->toggleSortDirection();
doCommand(xfeCmdSortBySize);
}
break;
case OUTLINER_COLUMN_UNREADMSG:
if (isCommandEnabled(xfeCmdSortByUnread))
{
if (m_outliner->getSortColumn() == data->column)
m_outliner->toggleSortDirection();
doCommand(xfeCmdSortByUnread);
}
break;
case OUTLINER_COLUMN_FLAG:
if (isCommandEnabled(xfeCmdSortByFlag))
{
if (m_outliner->getSortColumn() == data->column)
m_outliner->toggleSortDirection();
doCommand(xfeCmdSortByFlag);
}
break;
}
m_outliner->getSelection(&selected, &count);
if (count >= 1)
{
D(printf ("Making %d visible\n", selected[0]);)
m_outliner->makeVisible(selected[0]);
}
}
else // content row.
{
if (data->clicks == 2)
{
m_outliner->selectItemExclusive(data->row);
if ( m_displayingDraft )
{
MSG_OpenDraft(m_pane, m_folderInfo,
MSG_GetMessageKey(m_pane, data->row));
}
else
{
// ok. we're going to display a message in a message frame.
// what is left to determine is whether or not we will be
// popping up another window or reusing an existing one (if
// there is one.) This behavior is governed by two things:
// 1. fe_globalPrefs.reuse_msg_window and,
// 2. data->alt (whether the alt key was down or not...)
fe_showMsg(XtParent(getToplevel()->getBaseWidget()),
/* Tao: we might need to check if this returns a
* non-NULL frame
*/
ViewGlue_getFrame(m_contextData),
(Chrome*)NULL,
m_folderInfo,
MSG_GetMessageKey(m_pane, data->row),
(( fe_globalPrefs.reuse_msg_window
&& !data->shift)
|| (!fe_globalPrefs.reuse_msg_window
&& data->shift))
);
}
}
else if (data->clicks == 1)
{
const int *selected;
int count;
m_outliner->getSelection(&selected, &count);
#if defined(DEBUG_tao_)
printf("\n+++ data->clicks count=%d\n", count);
#endif
if (data->ctrl)
{
m_outliner->toggleSelected(data->row);
m_outliner->getSelection(&selected, &count);
#if defined(DEBUG_tao_)
printf("\n+++ data->clicks count=%d\n", count);
#endif
if (count == 1)
showMessage(selected[0]);
else if (count == 0 ||
count > 1)
showMessage(-1);
}
else if (data->shift)
{
// select the range.
if (count == 0) /* there wasn't anything selected yet. */
{
m_outliner->selectItemExclusive(data->row);
// clear the message area/label
showMessage(-1);
}
else if (count == 1) /* there was only one, so we select the range from
that item to the new one. */
{
m_outliner->selectRangeByIndices(selected[0], data->row);
// clear the message area/label
showMessage(-1);
}
else /* we had a range of items selected, so let's do something really
nice with them. */
{
m_outliner->trimOrExpandSelection(data->row);
// clear the message area/label
showMessage(-1);
}
}
else
{
// handle the columns that don't actually move the selection here
if (data->column == OUTLINER_COLUMN_UNREADMSG)
{
MSG_Command(m_pane, MSG_ToggleMessageRead, (MSG_ViewIndex*)&data->row, 1);
}
else if (data->column == OUTLINER_COLUMN_FLAG)
{
MSG_MessageLine line;
if (!MSG_GetThreadLineByIndex(m_pane, data->row, 1, &line))
return;
if (line.flags & MSG_FLAG_MARKED)
MSG_Command(m_pane, MSG_UnmarkMessages, (MSG_ViewIndex*)&data->row, 1);
else
MSG_Command(m_pane, MSG_MarkMessages, (MSG_ViewIndex*)&data->row, 1);
}
else
{
if ((int) m_targetIndex != data->row) {
//
m_targetIndex = MSG_VIEWINDEXNONE;
if (m_scrollTimer)
XtRemoveTimeOut(m_scrollTimer);
m_scrollTimer = 0;
}/* if */
// we've selected a message, update the label and load it into
// our message view.
showMessage(data->row);
}
}
XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating,
getFolderInfo());
}
}
}
void
XFE_ThreadView::Flippyfunc(const OutlineFlippyFuncData *data)
{
int delta = MSG_ExpansionDelta(m_pane, data->row);
XP_Bool need_to_select_top = FALSE;
if (data->do_selection) // we do descendant selection
{
MSG_MessageLine line;
if (delta > 0)
MSG_ToggleExpansion(m_pane, data->row, NULL);
MSG_GetThreadLineByIndex(m_pane, data->row, 1, &line);
m_outliner->deselectAllItems();
m_outliner->selectRangeByIndices(data->row, data->row + line.numChildren);
showMessage(-1);
}
else if (delta != 0) // actually to flippy stuff.
{
if (delta < 0)
{
if (delta == -1)
addCollapsed(data->row);
int i;
delta = -delta;
for (i = data->row + 1; i < data->row + 1 + delta; i ++)
{
if (m_outliner->isSelected(i))
{
need_to_select_top = TRUE;
m_outliner->deselectItem(i);
}
}
}
MSG_ToggleExpansion(m_pane, data->row, NULL);
if (need_to_select_top)
m_outliner->selectItem(data->row);
}
}
XFE_CALLBACK_DEFN(XFE_ThreadView, spaceAtMsgEnd)(XFE_NotificationCenter*,
void *, void *)
{
if (isCommandEnabled(xfeCmdNextUnreadMessage))
doCommand(xfeCmdNextUnreadMessage);
else if (isCommandEnabled(xfeCmdNextUnreadCollection))
doCommand(xfeCmdNextUnreadCollection);
}
static void
click_timer_func(XtPointer closure, XtIntervalId *)
{
XFE_ThreadView *v = (XFE_ThreadView *) closure;
if (v)
v->selectTimer();
}
void
XFE_ThreadView::selectTimer()
{
if (m_targetIndex != MSG_VIEWINDEXNONE)
m_outliner->makeVisible(m_targetIndex);
//
m_targetIndex = MSG_VIEWINDEXNONE;
if (m_scrollTimer)
XtRemoveTimeOut(m_scrollTimer);
m_scrollTimer = 0;
}
XFE_CALLBACK_DEFN(XFE_ThreadView, newMessageLoading)(XFE_NotificationCenter*,
void *, void*)
{
if (m_commandPending == noPendingCommand)
{
MSG_FolderInfo *info = m_msgview->getFolderInfo();
MessageKey key = m_msgview->getMessageKey();
#if defined(DEBUG_tao)
printf("--newMessageLoading, m_pane=0x%x, m_lastLoadedKey=0x%x,key=0x%x", m_pane, m_lastLoadedKey, key);
#endif
if (info != m_folderInfo)
{
m_commandPending = selectByKey;
m_pendingSelectionKey = key;
loadFolder(info);
}
else
{
MSG_ViewIndex index = MSG_GetMessageIndexForKey(m_pane,
key,
False);
int numLines = MSG_GetNumLines(m_pane);
if (m_outliner->getTotalLines() != numLines)
m_outliner->change(0, numLines, numLines);
#if 1
m_targetIndex = index;
int intvl0 = XtGetMultiClickTime(XtDisplay(m_widget)),
intvl = intvl0 + intvl0/2;
#if defined(DEBUG_tao)
printf("--newMessageLoading, intvl0=%d, intvl=%d",
intvl0, intvl);
#endif
m_scrollTimer = XtAppAddTimeOut(fe_XtAppContext, intvl,
click_timer_func, this);
#else
/* 97010: selecting the last mail/news article
* show the wrong one.
*
* Take out to prevent improper auto-selection... -tao
*/
m_outliner->makeVisible(index);
#endif
m_outliner->selectItemExclusive(index);
updateExpandoFlippyText(index);
}
notifyInterested(XFE_View::chromeNeedsUpdating);
}
}
void
XFE_ThreadView::toggleMsgExpansion()
{
int32 folder_prefs = 0;
if (m_folderInfo)
{
folder_prefs = MSG_GetFolderPrefFlags(m_folderInfo);
folder_prefs |= MSG_FOLDER_PREF_FEVALID;
}
if (m_msgExpanded)
{
// we are currently expanded
Dimension message_pane_height;
XtVaGetValues(m_msgview->getBaseWidget(),
XmNheight, &message_pane_height,
NULL);
D(printf ("Saving message pane height as %d\n", message_pane_height);)
PREF_SetIntPref(MESSAGEPANE_HEIGHT_PREF, (int32)message_pane_height);
m_msgview->hide();
m_msgExpanded = FALSE;
// Set maximum heights so that the sash will go away:
Dimension height;
XtVaGetValues(m_arrowform,
XmNheight, &height,
NULL);
XtVaSetValues(m_arrowform,
XmNpaneMinimum, height,
XmNpaneMaximum, height,
NULL);
XtVaSetValues(m_arrowb,
XmNarrowDirection, XmARROW_UP,
NULL);
folder_prefs |= MSG_FOLDER_PREF_ONEPANE;
notifyInterested(XFE_View::chromeNeedsUpdating);
}
else
{
const int *selected;
int count;
int32 message_pane_desired_height;
Dimension message_pane_minimum_height;
Dimension message_pane_resulting_height;
Dimension panedw_spacing;
Dimension panedw_marginheight;
Dimension panedw_height;
Dimension arrow_form_height;
Dimension minimum_height_of_outliner;
int resulting_height_of_outliner;
XP_Bool need_to_resize_frame = False;
// we are currently unexpanded
XtVaSetValues(m_arrowb,
XmNarrowDirection, XmARROW_DOWN,
NULL);
XtVaGetValues(m_widget,
XmNspacing, &panedw_spacing,
XmNmarginHeight, &panedw_marginheight,
XmNheight, &panedw_height,
NULL);
XtVaGetValues(m_arrowform,
XmNheight, &arrow_form_height,
NULL);
XtVaGetValues(m_outliner->getBaseWidget(),
XmNpaneMinimum, &minimum_height_of_outliner,
NULL);
XtVaGetValues(m_msgview->getBaseWidget(),
XmNpaneMinimum, &message_pane_minimum_height,
NULL);
PREF_GetIntPref(MESSAGEPANE_HEIGHT_PREF, &message_pane_desired_height);
D(printf ("Message pane wants to be %d high.\n", message_pane_desired_height);)
resulting_height_of_outliner = (panedw_height
- (2 * panedw_spacing) /* space between the outliner and arrow
and between the arrow and message */
- (2 * panedw_marginheight)
- arrow_form_height
- message_pane_desired_height);
D(printf ("This will make the outliner %d high.\n", resulting_height_of_outliner);)
if (resulting_height_of_outliner < (int)minimum_height_of_outliner)
{
D(printf (" This is not ok.\n");)
resulting_height_of_outliner = minimum_height_of_outliner;
message_pane_resulting_height = (message_pane_desired_height
- (minimum_height_of_outliner
- resulting_height_of_outliner));
if (message_pane_resulting_height < message_pane_minimum_height)
{
message_pane_resulting_height = message_pane_minimum_height;
need_to_resize_frame = True;
}
D(printf (" The message pane will instead be sized to %d, and the window will%s be resized", message_pane_resulting_height, need_to_resize_frame ? "" : " not");)
}
if (need_to_resize_frame)
XtVaSetValues(getToplevel()->getBaseWidget(),
XmNallowShellResize, True,
NULL);
XtVaSetValues(m_msgview->getBaseWidget(),
XmNskipAdjust, TRUE,
NULL);
m_msgview->show();
XtVaSetValues(m_msgview->getBaseWidget(),
XmNskipAdjust, FALSE,
XmNpaneMinimum, PANE_MIN,
XmNpaneMaximum, PANE_MAX,
NULL);
if (need_to_resize_frame)
XtVaSetValues(getToplevel()->getBaseWidget(),
XmNallowShellResize, False,
NULL);
XtVaSetValues(m_outliner->getBaseWidget(),
XmNpaneMinimum, PANE_MIN,
XmNpaneMaximum, PANE_MAX,
NULL);
m_msgExpanded = TRUE;
folder_prefs &= ~MSG_FOLDER_PREF_ONEPANE;
m_outliner->getSelection(&selected, &count);
if (count == 1)
showMessage(selected[0]);
else
showMessage(-1);
XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating, getFolderInfo());
}
if (m_folderInfo)
MSG_SetFolderPrefFlags(m_folderInfo, folder_prefs);
}
void
XFE_ThreadView::toggleMsgExpansionCallback(Widget, XtPointer clientData, XtPointer)
{
XFE_ThreadView *obj = (XFE_ThreadView*)clientData;
obj->toggleMsgExpansion();
}
#if !defined(USE_MOTIF_DND)
void
XFE_ThreadView::sourcedropfunc(fe_dnd_Source */*source*/, fe_dnd_Message msg, void *closure)
{
MSG_FolderInfo *info = (MSG_FolderInfo*)closure;
// messages can be copied or moved. The closure to this function will always
// be a MSG_FolderInfo*.
// XXX assume that nothing could have changed the selected between the time
// we started dragging and now... don't know how smart this is...
const char *name = MSG_GetFolderNameFromID(info);
const int *indices;
int count;
m_outliner->getSelection(&indices, &count);
/* New Code to take on the new Drag and Drop APIs with effect for both mail/news. However,
the effect checking on news articles are not completed in BE yet. Coredump will
be encountered when filing news articles. */
if (msg == FE_DND_MESSAGE_DELETE)
{
// delete the messages.
}
else
{
MSG_DragEffect requireEffect = MSG_Default_Drag;
MSG_DragEffect effect =
MSG_DragMessagesIntoFolderStatus(m_pane,
(MSG_ViewIndex*)indices, count,
info, requireEffect);
if (effect == MSG_Require_Move )
{
if (msg == FE_DND_MESSAGE_COPY )
{
DD(printf("### ThreadView::sourcedropfunc(req MOVE): FE_DND_MESSAGE_COPY To \n");)
MSG_CopyMessagesInto(m_pane, (MSG_ViewIndex*)indices, count, name);
}
else
{
DD(printf("### ThreadView::sourcedropfunc(req MOVE): FE_DND_MESSAGE_MOVE To \n");)
MSG_MoveMessagesInto(m_pane, (MSG_ViewIndex*)indices, count, name);
}
}
else if ( effect == MSG_Require_Copy )
{
DD(printf("### ThreadView::sourcedropfunc(req COPY): FE_DND_MESSAGE_COPY To \n");)
MSG_CopyMessagesInto(m_pane, (MSG_ViewIndex*)indices, count, name);
}
else if ( effect == MSG_Drag_Not_Allowed )
{
DD(printf("### ThreadView::sourcedropfunc: Not Allowed \n");)
char tmp[128];
XP_SAFE_SPRINTF(tmp, sizeof(tmp),
"%s",
XP_GetString(XFE_DND_MESSAGE_ERROR));
XFE_Progress (m_contextData, tmp);
}
else /* should not reach here. the effect status should be with in
the defined range. Please double check if you try to refer
to any enum outside the effect enum scope */
XP_ASSERT(0);
}
/* now we need to modify the chrome of windows viewing either folder */
XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating, m_folderInfo);
XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating, info);
}
void
XFE_ThreadView::source_drop_func(fe_dnd_Source *src, fe_dnd_Message msg, void *closure)
{
XFE_ThreadView *obj = (XFE_ThreadView*)src->closure;
obj->sourcedropfunc(src, msg, closure);
}
void
XFE_ThreadView::dropfunc(Widget /*dropw*/, fe_dnd_Event type,
fe_dnd_Source *source, XEvent *event)
{
m_outliner->handleDragEvent(event, type, source);
}
void
XFE_ThreadView::drop_func(Widget dropw, void *closure, fe_dnd_Event type,
fe_dnd_Source *source, XEvent* event)
{
XFE_ThreadView *obj = (XFE_ThreadView*)closure;
obj->dropfunc(dropw, type, source, event);
}
#endif /* USE_MOTIF_DND */
void
XFE_ThreadView::openWithKey(MessageKey key )
{
m_commandPending = selectByKey;
m_pendingSelectionKey = key;
}
#if defined(USE_MOTIF_DND)
fe_icon_data *
XFE_ThreadView::GetDragIconData(int row, int /*column*/)
{
D(printf("XFE_ThreadView::GetDragIconData()\n");)
if (row == -1) return &MN_MailRead;
else
{
MSG_FolderLine folderLine;
int flags = m_messageLine.flags;
MSG_GetFolderLineById(XFE_MNView::getMaster(), m_folderInfo, &folderLine);
acquireLineData(row);
flags = m_messageLine.flags;
releaseLineData();
return flagToIconData(folderLine.flags, flags);
}
}
fe_icon_data *
XFE_ThreadView::getDragIconData(void *this_ptr,
int row,
int column)
{
D(printf("XFE_ThreadView::getDragIconData()\n");)
XFE_ThreadView *thread_view = (XFE_ThreadView*)this_ptr;
return thread_view->GetDragIconData(row, column);
}
void
XFE_ThreadView::GetDragTargets(int row, int column,
Atom **targets,
int *num_targets)
{
D(printf("XFE_ThreadView::GetDragTargets()\n");)
int flags;
XP_ASSERT(row > -1);
if (row == -1)
{
*targets = NULL;
*num_targets = 0;
}
else
{
acquireLineData(row);
flags = m_messageLine.flags;
releaseLineData();
*num_targets = 5;
*targets = new Atom[ *num_targets ];
(*targets)[1] = XFE_DragBase::_XA_NETSCAPE_URL;
(*targets)[2] = XA_STRING;
if (isDisplayingNews())
(*targets)[0] = XFE_OutlinerDrop::_XA_NETSCAPE_NEWS_MESSAGE;
else
(*targets)[0] = XFE_OutlinerDrop::_XA_NETSCAPE_MAIL_MESSAGE;
}
}
void
XFE_ThreadView::getDragTargets(void *this_ptr,
int row,
int column,
Atom **targets,
int *num_targets)
{
D(printf("XFE_ThreadView::getDragTargets()\n");)
XFE_ThreadView *thread_view = (XFE_ThreadView*)this_ptr;
thread_view->GetDragTargets(row, column, targets, num_targets);
}
char *
XFE_ThreadView::DragConvert(Atom atom)
{
if (atom == XFE_DragBase::_XA_NETSCAPE_URL)
{
// translate drag data to NetscapeURL format
XFE_URLDesktopType urlData;
char *result;
const int *selection;
int count;
int i;
m_outliner->getSelection(&selection, &count);
urlData.createItemList(count);
for (i = 0; i < count; i ++)
{
MessageKey key = MSG_GetMessageKey(m_pane, selection[i]);
URL_Struct *url = MSG_ConstructUrlForMessage(m_pane,
key);
urlData.url(i,url->address);
NET_FreeURLStruct(url);
}
result = XtNewString(urlData.getString());
return result;
}
else if (atom == XFE_OutlinerDrop::_XA_NETSCAPE_MAIL_MESSAGE
|| atom == XFE_OutlinerDrop::_XA_NETSCAPE_NEWS_MESSAGE)
{
char result[100];
const int *selection;
int count;
m_outliner->getSelection(&selection, &count);
if (count < 1) return XtNewString("0"); /* XXX ? */
sprintf (result, "%d", selection[0]);
return (char*)XtNewString(result); /* XXX fixme */
}
else if (atom == XA_STRING)
{
#if notyet
char *result;
URL_Struct *url = MSG_ConstructUrlForMessage(m_pane,
m_dragmessage);
result = XtNewString(url->address);
NET_FreeURLStruct(url);
return result;
#endif
}
}
char *
XFE_ThreadView::dragConvert(void *this_ptr,
Atom atom)
{
XFE_ThreadView *thread_view = (XFE_ThreadView*)this_ptr;
return thread_view->DragConvert(atom);
}
#endif /* USE_MOTIF_DND */
void
XFE_ThreadView::selectThread()
{
const int *selected;
int i,count;
MessageKey *keys;
m_outliner->getSelection(&selected, &count);
if ( count <= 0 ) return;
keys = new MessageKey[count];
for ( i = 0; i < count ; i++ )
{
keys[i] = MSG_GetMessageKey(m_pane, selected[i]);
}
m_outliner->deselectAllItems();
for ( i = 0; i < count; i++ )
{
MSG_ViewIndex index = MSG_ThreadIndexOfMsg( m_pane, keys[ i ] );
int delta = MSG_ExpansionDelta(m_pane, index);
if ( delta > 0 )
MSG_ToggleExpansion(m_pane, index, NULL);
else
delta = -delta;
m_outliner->selectRangeByIndices(index, index+delta);
}
delete[] keys;
showMessage(-1);
}