gecko-dev/cmd/xfe/src/MsgView.cpp
1998-06-22 21:19:46 +00:00

1326 lines
36 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.
*/
/*
MsgView.cpp -- class for displaying the actual text (well, html) of a message.
Created: Chris Toshok <toshok@netscape.com>, 7-Aug-96.
*/
#include "MsgView.h"
#include "FolderMenu.h"
#include "xpassert.h"
#include "xfe.h"
#include "msgcom.h"
#include "xpgetstr.h"
#include "prefapi.h"
#if defined(USE_ABCOM)
#include "ABListSearchView.h"
#endif
#include "ViewGlue.h"
#include "MNSearchFrame.h"
#include "ThreadFrame.h"
#include "ThreadView.h"
#include "ThreePaneView.h"
#include "MozillaApp.h" // to get the MsgFrame
#include "Xfe/Xfe.h"
#include <intl_csi.h> /* to get/set doc_csid/win_csid */
#include "prefs.h"
#include <Xm/Label.h>
#ifdef DEBUG_toshok
#define D(x) x
#else
#define D(x)
#endif
extern int MK_MSG_CANCEL_MESSAGE;
extern "C"
{
void fe_print_cb (Widget widget, XtPointer closure, XtPointer call_data);
}
MenuSpec XFE_MsgView::separator_spec[] = {
MENU_SEPARATOR,
{ NULL }
};
MenuSpec XFE_MsgView::repl_spec[] = {
// 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 },
{ NULL }
};
MenuSpec XFE_MsgView::addr_spec[] = {
{ "addToAddrBkSubmenu", CASCADEBUTTON, (MenuSpec*)&addToAddrbk_submenu_spec },
{ NULL }
};
MenuSpec XFE_MsgView::filemsg_spec[] = {
{ "fileSubmenu", DYNA_CASCADEBUTTON, NULL, NULL, False, (void*)xfeCmdMoveMessage, XFE_FolderMenu::generate },
{ xfeCmdDeleteMessage, PUSHBUTTON },
{ xfeCmdSaveMessagesAs, PUSHBUTTON },
{ xfeCmdPrint, PUSHBUTTON },
{ NULL }
};
MenuSpec XFE_MsgView::openLinkNew_spec[] = {
{ xfeCmdOpenLinkNew , PUSHBUTTON },
{ NULL },
};
MenuSpec XFE_MsgView::openLinkEdit_spec[] = {
{ xfeCmdOpenLinkEdit, PUSHBUTTON },
{ NULL },
};
MenuSpec XFE_MsgView::showImage_spec[] = {
{ xfeCmdShowImage, PUSHBUTTON },
{ NULL },
};
MenuSpec XFE_MsgView::stopLoading_spec[] = {
{ xfeCmdStopLoading, PUSHBUTTON },
{ NULL },
};
MenuSpec XFE_MsgView::openImage_spec[] = {
{ xfeCmdOpenImage, PUSHBUTTON },
{ NULL },
};
MenuSpec XFE_MsgView::saveLink_spec[] = {
{ xfeCmdSaveLink, PUSHBUTTON },
{ NULL },
};
MenuSpec XFE_MsgView::saveImage_spec[] = {
{ xfeCmdSaveImage, PUSHBUTTON },
{ NULL },
};
MenuSpec XFE_MsgView::copy_spec[] = {
{ xfeCmdCopy, PUSHBUTTON },
{ NULL },
};
MenuSpec XFE_MsgView::copyLink_spec[] = {
{ xfeCmdCopyLink, PUSHBUTTON },
{ NULL },
};
MenuSpec XFE_MsgView::copyImage_spec[] = {
{ xfeCmdCopyImage, PUSHBUTTON },
{ NULL },
};
MenuSpec XFE_MsgView::addToAddrbk_submenu_spec[] = {
{ xfeCmdAddSenderToAddressBook, PUSHBUTTON },
{ xfeCmdAddAllToAddressBook, PUSHBUTTON },
{ NULL }
};
const char *XFE_MsgView::messageHasChanged = "XFE_MsgView::messageHasChanged";
const char *XFE_MsgView::lastMsgDeleted = "XFE_MsgView::lastMsgDeleted";
const char *XFE_MsgView::spacebarAtMsgBottom = "XFE_MsgView::spacebarAtMsgBottom";
XFE_MsgView::XFE_MsgView(XFE_Component *toplevel_component,
Widget parent,
XFE_View *parent_view,
MWContext *context,
MSG_Pane *p)
: XFE_MNView(toplevel_component, parent_view, context, p)
{
m_frameDeleted = False;
m_updateThread = False;
// create common parent for pane and attachment panel
Widget panedW=XmCreatePanedWindow(parent,"msgViewPane",NULL,0);
XtVaSetValues(panedW,
XmNshadowThickness,0,
XmNmarginWidth,0,
XmNmarginHeight,0,
NULL);
m_htmlView = new XFE_HTMLView(toplevel_component, panedW, this, m_contextData);
addView(m_htmlView);
// create attachment panel
m_attachApplHeight=0;
m_attachUserHeight=0;
m_attachPanel = new XFE_ReadAttachPanel(m_contextData);
m_attachPanel->createWidgets(panedW);
XtVaSetValues(m_attachPanel->getBaseWidget(),XmNskipAdjust,TRUE,NULL);
m_attachPanel->setPaneHeight(1);
/* test frame type
*/
XFE_Frame *frame = (XFE_Frame*)m_toplevel;
if (frame &&
FRAME_MAILNEWS_MSG == frame->getType()) {
/* standalone frame
*/
frame->registerInterest(XFE_Frame::allConnectionsCompleteCallback,
this,
(XFE_FunctionNotification)allConnectionsComplete_cb);
}/* if */
m_htmlView->registerInterest(XFE_HTMLView::spacebarAtPageBottom,
this,
(XFE_FunctionNotification)spaceAtMsgEnd_cb);
m_htmlView->registerInterest(XFE_HTMLView::popupNeedsShowing,
this,
(XFE_FunctionNotification)showPopup_cb);
XFE_MozillaApp::theApp()->registerInterest(XFE_MozillaApp::refreshMsgWindow,
this,
(XFE_FunctionNotification)refresh_cb);
if (!p)
setPane(MSG_CreateMessagePane(m_contextData,
XFE_MNView::getMaster()));
m_folderInfo = NULL;
m_messageKey = MSG_MESSAGEKEYNONE;
m_popup = NULL;
m_htmlView->show();
#if defined(USE_ABCOM)
int error =
AB_SetShowPropertySheetForEntryFunc((MSG_Pane *) m_pane,
&XFE_ABListSearchView::ShowPropertySheetForEntryFunc);
#endif /* USE_ABCOM */
setBaseWidget(panedW);
}
XFE_MsgView::~XFE_MsgView()
{
if (m_attachPanel) {
delete m_attachPanel;
m_attachPanel=NULL;
}
if (m_popup)
delete m_popup;
/* unregister from frame
*/
/* test frame type
*/
XFE_Frame *frame = (XFE_Frame*)m_toplevel;
if (frame &&
FRAME_MAILNEWS_MSG == frame->getType()) {
/* standalone frame
*/
frame->unregisterInterest(XFE_Frame::allConnectionsCompleteCallback,
this,
(XFE_FunctionNotification)allConnectionsComplete_cb);
}/* if */
m_htmlView->unregisterInterest(XFE_HTMLView::spacebarAtPageBottom,
this,
(XFE_FunctionNotification)spaceAtMsgEnd_cb);
m_htmlView->unregisterInterest(XFE_HTMLView::popupNeedsShowing,
this,
(XFE_FunctionNotification)showPopup_cb);
XFE_MozillaApp::theApp()->unregisterInterest(XFE_MozillaApp::refreshMsgWindow,
this,
(XFE_FunctionNotification)refresh_cb);
destroyPane();
// XFE_View destroys m_htmlView for us.
}
XFE_CALLBACK_DEFN(XFE_MsgView, allConnectionsComplete)(XFE_NotificationCenter *,
void *,
void *)
{
/* 1. check if deleted/filed
*/
if (m_updateThread) {
/* 2. get threadframe with
* XFE_ThreadFrame::frameForInfo(MSG_FolderInfo *info)
*/
MSG_FolderInfo *folderInfo = MSG_GetCurFolder(m_pane);
XFE_ThreadFrame *tFrame =
XFE_ThreadFrame::frameForInfo(folderInfo);
if (tFrame) {
/* 3. urge to update msg line and body
*/
#ifdef USE_3PANE
XFE_ThreadView *tview = 0;
XFE_ThreePaneView* tpview = (XFE_ThreePaneView*)tFrame->getView();
if (tpview)
tview = (XFE_ThreadView*)tpview->getThreadView();
#else
XFE_ThreadView *tview =
(XFE_ThreadView *) tFrame->getView();
#endif
if (tview)
tview->processCmdQueue();
}/* if tFrame */
m_updateThread = False;
}/* if */
}
void
XFE_MsgView::loadMessage(MSG_FolderInfo *info,
MessageKey key)
{
MSG_FolderLine folderLine;
m_folderInfo = info;
m_messageKey = key;
MSG_GetFolderLineById(XFE_MNView::getMaster(), m_folderInfo, &folderLine);
if (folderLine.flags & MSG_FOLDER_FLAG_NEWSGROUP
|| folderLine.flags & MSG_FOLDER_FLAG_CATEGORY)
m_displayingNewsgroup = TRUE;
else
m_displayingNewsgroup = FALSE;
MSG_LoadMessage(m_pane, info, MSG_MESSAGEKEYNONE);
// set up attachment notify callback
static MSG_MessagePaneCallbacks attachmentCb = {
XFE_MsgView::AttachmentCountCb,
XFE_MsgView::ToggleAttachmentPanelCb
};
MSG_SetMessagePaneCallbacks(m_pane,&attachmentCb,(void*)this);
// remove previous message's attachments before displaying next message
if (m_attachPanel) {
m_attachPanel->removeAllAttachments();
m_attachPanel->setPaneHeight(1);
}
// reset panel height memory for next message
m_attachApplHeight=0;
m_attachUserHeight=0;
MSG_LoadMessage(m_pane, info, key);
}
// called as each attachment is processed
void
XFE_MsgView::AttachmentCountCb(MSG_Pane*,void *closure,int32 count,XP_Bool done)
{
if (closure) {
XFE_MsgView *m=(XFE_MsgView*)closure;
m->attachmentCountCb(count,done);
}
}
// show panel as soon as we detect attachments, display attachment icons when
// all attachments have been loaded.
void
XFE_MsgView::attachmentCountCb(int32 count,XP_Bool done)
{
if (count>0) {
// Prepare to display attachment panel if there is at least 1 attachment
// The panel will be shown as soon as we detect attachments, but will fill
// up only when all attachments are loaded. Gives user early-warning of
// attachments. If we held off managing panel until all attachments
// are loaded, it will cause unexpected relayout after user has started
// reading body of message.
// erase previous message attachments
m_attachPanel->removeAllAttachments();
// add icons only when all attachments have been loaded
if (done) {
MSG_AttachmentData* data;
done = FALSE;
MSG_GetViewedAttachments(m_pane, &data, &done);
XP_ASSERT(done);
if (data) {
m_attachPanel->addAttachments(m_pane,data);
m_attachPanel->updateDisplay();
}
// if user has tried to resize panel blindly, then
// expand it to the preferred height. This ignores
// their guess, but they were probably wrong anyway,
// and should have been more patient. Yeah.
m_attachApplHeight=0;
m_attachUserHeight=0;
if (m_attachPanel->getPaneHeight()<10) {
// panel effectively closed. make it completely closed for neatness.
m_attachPanel->setPaneHeight(1);
}
else {
// panel is open, reset height to ideal
setAttachPrefHeight();
}
}
// manage attachment panel
m_attachPanel->show();
}
else {
// count==0 - either load is in-progress, or there are no attachments
if (done) {
// definitely no attachments - hide attachment panel and
// remove old attachment data
if (m_attachPanel) {
m_attachPanel->hide();
m_attachPanel->removeAllAttachments();
}
}
}
}
// called when user clicks attachment icon in message header
void
XFE_MsgView::ToggleAttachmentPanelCb(MSG_Pane*,void *closure)
{
if (closure) {
XFE_MsgView *m=(XFE_MsgView*)closure;
m->toggleAttachmentPanelCb();
}
}
void
XFE_MsgView::toggleAttachmentPanelCb()
{
if (!m_attachPanel)
return;
int currentHeight=m_attachPanel->getPaneHeight();
if (currentHeight<10) {
// expand attachment panel
// if user hasn't set size, choose size to show all attachments
if (!m_attachUserHeight)
setAttachPrefHeight();
else
m_attachPanel->setPaneHeight(m_attachUserHeight);
}
else {
// contract attachment panel
// if user changed pane size, remember it
if (!m_attachApplHeight || currentHeight!=m_attachApplHeight)
m_attachUserHeight=currentHeight;
m_attachPanel->setPaneHeight(1);
}
}
void
XFE_MsgView::setAttachPrefHeight()
{
if (!m_attachPanel || !getBaseWidget())
return;
// pick a default height for the attachment panel.
// Make large enough to view all attachments without
// scrolling, up to a maximum of 70% of the message
// pane height - don't want to obscure the attachment
// show/hide link in the message header.
Dimension parentHeight;
XtVaGetValues(getBaseWidget(),XmNheight,&parentHeight,NULL);
int prefHeight=m_attachPanel->getPreferredHeight();
if (prefHeight > (7*parentHeight/10))
prefHeight=(7*parentHeight/10);
m_attachApplHeight=prefHeight;
m_attachPanel->setPaneHeight(m_attachApplHeight);
}
MSG_FolderInfo *
XFE_MsgView::getFolderInfo()
{
return m_folderInfo;
}
MessageKey
XFE_MsgView::getMessageKey()
{
return m_messageKey;
}
void
XFE_MsgView::paneChanged(XP_Bool asynchronous,
MSG_PANE_CHANGED_NOTIFY_CODE code,
int32 value)
{
switch (code)
{
case MSG_PaneNotifyFolderDeleted:
{
#ifndef USE_3PANE
/* test frame type
*/
XFE_Frame *frame = (XFE_Frame*)m_toplevel;
if (frame &&
FRAME_MAILNEWS_MSG == frame->getType()) {
/* standalone frame
*/
if (!m_frameDeleted) {
frame->delete_response();
m_frameDeleted = True;
}/* if */
}/* if */
#endif
}
/* shall we update banner or simply return? NO
*/
return;
case MSG_PaneNotifyMessageLoaded:
notifyInterested(messageHasChanged, (void*)value);
{
MSG_FolderInfo *folderInfo = MSG_GetCurFolder(m_pane);
/* We need to update this to reflect what the real folderInfo is
*/
m_folderInfo = folderInfo;
MessageKey key = (MessageKey) value;
if (MSG_GetBacktrackState(m_pane) == MSG_BacktrackIdle)
MSG_AddBacktrackMessage(m_pane, folderInfo, key);
else
MSG_SetBacktrackState(m_pane, MSG_BacktrackIdle);
}
break;
case MSG_PaneNotifyLastMessageDeleted:
notifyInterested(lastMsgDeleted, (void*)value);
break;
default:
break;
}
XFE_MNView::paneChanged(asynchronous, code, value);
}
Boolean
XFE_MsgView::isCommandSelected( CommandType cmd, void *calldata, XFE_CommandInfo*)
{
MSG_CommandType msg_cmd;
XP_Bool selectable = False;;
msg_cmd = commandToMsgCmd(cmd);
if (msg_cmd != (MSG_CommandType)~0)
{
if ( MSG_GetToggleStatus(m_pane, msg_cmd, NULL, 0 ) == MSG_Checked)
selectable = True;
return (Boolean)selectable;
}
return XFE_MNView::isCommandSelected(cmd, calldata);
}
Boolean
XFE_MsgView::isCommandEnabled(CommandType cmd, void *calldata, XFE_CommandInfo*)
{
#define IS_CMD(command) cmd == (command)
XP_Bool selectable = FALSE;
// DeleteMessage stands for CancelMessage in the ThreadView,
// so intercept it early:
if ( (IS_CMD(xfeCmdDeleteMessage) || IS_CMD(xfeCmdCancelMessages))
&& isDisplayingNews() )
{
MSG_CommandStatus(m_pane, MSG_CancelMessage,
NULL, 0,
&selectable, NULL, NULL, NULL);
return selectable;
}
#if defined(USE_ABCOM)
if (IS_CMD(xfeCmdAddSenderToAddressBook)||
IS_CMD(xfeCmdAddAllToAddressBook)) {
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),
NULL,
0,
&selectable, NULL, NULL, NULL,
destAB);
error = AB_ReleaseContainersList(abList);
return selectable;
}/* if */
#endif /* USE_ABCOM */
MSG_MotionType nav_cmd;
MSG_CommandType msg_cmd;
nav_cmd = commandToMsgNav(cmd);
if (IS_CMD(xfeCmdSetPriorityHighest)
|| IS_CMD(xfeCmdSetPriorityHigh)
|| IS_CMD(xfeCmdSetPriorityNormal)
|| IS_CMD(xfeCmdSetPriorityLow)
|| IS_CMD(xfeCmdSetPriorityLowest)
|| IS_CMD(xfeCmdSetPriorityNone)
|| IS_CMD(xfeCmdPrint)
|| IS_CMD(xfeCmdCopyMessage)
|| IS_CMD(xfeCmdMoveMessage)
|| IS_CMD(xfeCmdIgnoreThread)
|| IS_CMD(xfeCmdWatchThread)
|| IS_CMD(xfeCmdMarkMessageByDate))
{
MSG_ViewIndex index;
MessageKey key;
MSG_FolderInfo *info;
MSG_GetCurMessage(m_pane, &info, &key, &index);
return (key != MSG_MESSAGEKEYNONE);
}
else if (IS_CMD(xfeCmdMommy)
|| IS_CMD(xfeCmdNewFolder)
|| IS_CMD(xfeCmdRenameFolder)
|| IS_CMD(xfeCmdEmptyTrash)
|| IS_CMD(xfeCmdAddNewsgroup)
|| IS_CMD(xfeCmdUpdateMessageCount)
|| IS_CMD(xfeCmdPrintSetup)
|| IS_CMD(xfeCmdPrintPreview))
{
return True;
}
else if (IS_CMD(xfeCmdEditPreferences) ||
IS_CMD(xfeCmdWrapLongLines) )
{
return True;
}
else if ( IS_CMD(xfeCmdEditConfiguration) )
{
MSG_ViewIndex index ;
MessageKey key;
MSG_FolderInfo *info;
XP_Bool selectable = FALSE;
MSG_CommandType msg_cmd = commandToMsgCmd(cmd);
MSG_GetCurMessage(m_pane, &info, &key, &index);
MSG_CommandStatus(m_pane, msg_cmd,
&index, 1,
&selectable, NULL, NULL, NULL);
return (selectable && !(isDisplayingNews()) );
}
else if ( IS_CMD(xfeCmdModerateDiscussion) )
{
MSG_ViewIndex index ;
MessageKey key;
MSG_FolderInfo *info;
XP_Bool selectable = FALSE;
MSG_CommandType msg_cmd = commandToMsgCmd(cmd);
MSG_GetCurMessage(m_pane, &info, &key, &index);
MSG_CommandStatus(m_pane, msg_cmd,
&index, 1,
&selectable, NULL, NULL, NULL);
return (selectable && (isDisplayingNews()) );
}
else if (IS_CMD(xfeCmdGetNextNNewMsgs))
{
return m_displayingNewsgroup;
}
#ifdef DEBUG_akkana
else if (IS_CMD(xfeCmdEditMessage))
{
return !m_displayingNewsgroup;
}
#endif
else if (nav_cmd != (MSG_MotionType)~0)
{
MSG_ViewIndex index;
MessageKey key;
MSG_FolderInfo *info;
MSG_GetCurMessage(m_pane, &info, &key, &index);
if (MSG_NavigateStatus(m_pane, nav_cmd, index, &selectable, NULL) < 0)
selectable = FALSE;
return selectable;
}
else
{
msg_cmd = commandToMsgCmd(cmd);
if (msg_cmd != (MSG_CommandType)~0)
{
if (IS_CMD(xfeCmdGetNewMessages)) {
int num_inboxes = MSG_GetFoldersWithFlag(XFE_MNView::getMaster(),
MSG_FOLDER_FLAG_INBOX,
NULL, 0);
if ((num_inboxes > 0) ||
(MSG_CommandStatus(m_pane,
msg_cmd, NULL, 0,
&selectable, NULL, NULL, NULL) < 0)) {
selectable = FALSE;
}/* if */
}/* else */
else if (MSG_CommandStatus(m_pane, msg_cmd, NULL, 0, &selectable, NULL, NULL, NULL) < 0)
selectable = FALSE;
return selectable;
}
}
return XFE_MNView::isCommandEnabled(cmd, calldata);
#undef IS_CMD
}
void
XFE_MsgView::doCommand(CommandType cmd,
void *calldata, XFE_CommandInfo* info)
{
#define IS_CMD(command) cmd == (command)
if (IS_CMD(xfeCmdMommy))
{
fe_showMessages(XtParent(getToplevel()->getBaseWidget()),
/* Tao: we might need to check if this returns a
* non-NULL frame
*/
ViewGlue_getFrame(m_contextData),
NULL,
m_folderInfo,
fe_globalPrefs.reuse_thread_window,
False, MSG_MESSAGEKEYNONE);
}
#if defined(USE_ABCOM)
else if (IS_CMD(xfeCmdAddSenderToAddressBook)||
IS_CMD(xfeCmdAddAllToAddressBook)) {
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),
NULL,
0,
destAB);
error = AB_ReleaseContainersList(abList);
}/* if */
}/* if */
#endif /* USE_ABCOM */
else if (IS_CMD(xfeCmdGetNewMessages))
{
getNewMail();
}
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(xfeCmdPrint))
{
fe_print_cb (CONTEXT_WIDGET (m_contextData),
(XtPointer) m_contextData, NULL);
getToplevel()->notifyInterested(XFE_View::chromeNeedsUpdating);
}
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
// Grabbed this from ThreadView.cpp -slamm 2/19/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(xfeCmdSetPriorityHighest)
|| IS_CMD(xfeCmdSetPriorityHigh)
|| IS_CMD(xfeCmdSetPriorityNormal)
|| IS_CMD(xfeCmdSetPriorityLow)
|| IS_CMD(xfeCmdSetPriorityLowest)
|| IS_CMD(xfeCmdSetPriorityNone))
{
MSG_PRIORITY priority = commandToPriority(cmd);
MSG_SetPriority(m_pane, m_messageKey, priority);
}
else if (IS_CMD(xfeCmdGetNewMessages))
{
getNewMail();
}
else if ( IS_CMD(xfeCmdEditConfiguration) ||
IS_CMD(xfeCmdModerateDiscussion) )
{
MSG_ViewIndex index ;
MessageKey key;
MSG_FolderInfo *info;
MSG_CommandType msg_cmd = commandToMsgCmd(cmd);
MSG_GetCurMessage(m_pane, &info, &key, &index);
MSG_Command(m_pane, msg_cmd, &index, 1);
}
else if (isDisplayingNews()
&& (IS_CMD(xfeCmdDeleteMessage) || IS_CMD(xfeCmdCancelMessages)))
{
// If this is a news article, then Delete Message
// is really Cancel Message:
MSG_Command(m_pane, MSG_CancelMessage, NULL, 0);
m_updateThread = True;
}
else if (IS_CMD(xfeCmdMoveMessage))
{
MSG_FolderInfo *info = (MSG_FolderInfo*)calldata;
MSG_ViewIndex index;
MSG_FolderInfo *curFolderInfo;
MessageKey key;
MSG_GetCurMessage(m_pane, &curFolderInfo, &key, &index);
if (index && info) {
MSG_MoveMessagesIntoFolder(m_pane, &index, 1, info);
m_updateThread = True;
}/* if */
}
else if (cmd == xfeCmdChangeDocumentEncoding)
{
int/*16*/ new_doc_csid = (int/*16*/)calldata;
INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(m_contextData);
if (new_doc_csid != m_contextData->fe.data->xfe_doc_csid)
{
/*
* Somebody is setting the doc_csid to a non-zero
* value, thereby screwing up our GetDefaultDocCSID
* routine. Make sure it gets set to zero here
* in the mail and news cases. Don't want to set
* it to zero in the Browser case, since it is
* legitimate there when the HTTP charset has been
* set. We override the charset in the mail and
* news cases.
*/
INTL_SetCSIDocCSID(c, new_doc_csid);
m_contextData->fe.data->xfe_doc_csid = new_doc_csid;
INTL_SetCSIWinCSID(c,
INTL_DocToWinCharSetID(new_doc_csid));
// now let our observers know that the encoding
// for this window needs to be changed.
getToplevel()->notifyInterested(XFE_Frame::encodingChanged, calldata);
MSG_SetFolderCSID(m_folderInfo, m_contextData->fe.data->xfe_doc_csid);
}
}
else if (cmd == xfeCmdSetDefaultDocumentEncoding)
{
}
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_MNView::doCommand(cmd, calldata, info);
}
else
{
if (msg_cmd == MSG_DeleteMessage)
/* stop loading since we are deleting this message:
* shall we check if it is stopable?
*/
XP_InterruptContext(m_contextData);
MSG_Command(m_pane, msg_cmd, NULL, 0);
if (msg_cmd == MSG_DeleteMessage ||
msg_cmd == MSG_CancelMessage) {
m_updateThread = True;
}/* if */
/* stand alone msgpane
*/
if (IS_CMD(xfeCmdUndo)
|| IS_CMD(xfeCmdRedo)) {
MessageKey key = MSG_MESSAGEKEYNONE;
MSG_FolderInfo *folder = NULL;
if ( UndoComplete == MSG_GetUndoStatus(m_pane) ) {
if (MSG_GetUndoMessageKey(m_pane, &folder, &key) && folder)
loadMessage(folder, key);
}/* if */
}/* if */
XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating, getFolderInfo());
}
}
else
{
MSG_ViewIndex index, threadIndex;
MessageKey key;
MessageKey resultId;
MSG_FolderInfo *info;
MSG_GetCurMessage(m_pane, &info, &key, &index);
// MsgView might be invoked from Search Dialog
// In this circumstances, m_folderInfo was
// not initialized. Therefore, we will see a crash when one
// tries to do Next Msg.
// We try to initialize m_folderInfo here base on current msg
// msg folder info.
// The above comment is not valid if we set m_folderInfo when MessageLoad
// notification arrives
//
if (!m_folderInfo)
m_folderInfo = info;
MSG_FolderInfo *curInfo = info;
MSG_ViewNavigate(m_pane, nav_cmd, index,
&resultId, &index, &threadIndex,
&info);
// ViewNavigate gives a NULL folderinfo if the folder
// info won't be changing.
if (!info) {
int idx = (int) index;
if (idx >= 0) {
info = m_folderInfo;
loadMessage(info, resultId);
}/* if */
}/* if */
else if (curInfo != info) {
/* folder changed
*/
/* get parent view
*/
XFE_ThreadView *threadView = (XFE_ThreadView *)getParent();
/* load new folder
*/
if (threadView) {
/* in thread win
*/
threadView->loadFolder(info);
threadView->setPendingCmdSelByKey(selectByKey, resultId);
}/* if */
else {
/* in message win
*/
MWContext *thrContext = fe_showMessages(XtParent(getToplevel()->getBaseWidget()),
/* Tao: we might need to check if this returns a
* non-NULL frame
*/
ViewGlue_getFrame(m_contextData),
NULL,
info,
fe_globalPrefs.reuse_thread_window,
False, resultId);
if (thrContext) {
XFE_ThreadFrame *tFrame = (XFE_ThreadFrame *) ViewGlue_getFrame(thrContext);
XP_ASSERT(tFrame);
threadView = (XFE_ThreadView *) tFrame->getView();
if (threadView) {
switch (nav_cmd) {
case MSG_NextMessage:
threadView->setPendingCmdSelByKey(selectFirstUnread, resultId);
}/* switch */
}/* if */
}/* if */
/* load myself
*/
}/* else */
}/* else if */
}
}
#undef IS_CMD
}
Boolean
XFE_MsgView::handlesCommand(CommandType cmd, void *calldata, XFE_CommandInfo*)
{
#define IS_CMD(command) cmd == (command)
if ( IS_CMD(xfeCmdSaveAs)
|| IS_CMD(xfeCmdSaveMessagesAs)
|| IS_CMD(xfeCmdSaveAsTemplate)
|| IS_CMD(xfeCmdAddSenderToAddressBook)
|| IS_CMD(xfeCmdAddAllToAddressBook)
|| IS_CMD(xfeCmdGetNewMessages)
|| IS_CMD(xfeCmdGetNextNNewMsgs)
|| IS_CMD(xfeCmdPrint)
|| IS_CMD(xfeCmdSendMessagesInOutbox)
|| IS_CMD(xfeCmdNextUnreadMessage)
|| IS_CMD(xfeCmdPreviousUnreadMessage)
|| IS_CMD(xfeCmdNextMessage)
|| IS_CMD(xfeCmdPreviousMessage)
|| IS_CMD(xfeCmdNextUnreadThread)
|| IS_CMD(xfeCmdNextCollection)
|| IS_CMD(xfeCmdNextUnreadCollection)
|| IS_CMD(xfeCmdFirstUnreadMessage)
|| IS_CMD(xfeCmdFirstFlaggedMessage)
|| IS_CMD(xfeCmdPreviousFlaggedMessage)
|| IS_CMD(xfeCmdNextFlaggedMessage)
|| IS_CMD(xfeCmdUndo)
|| IS_CMD(xfeCmdRedo)
|| IS_CMD(xfeCmdSearch)
|| IS_CMD(xfeCmdDeleteMessage)
|| IS_CMD(xfeCmdEditPreferences)
|| IS_CMD(xfeCmdMarkMessageRead)
|| IS_CMD(xfeCmdMarkMessageUnread)
|| IS_CMD(xfeCmdMarkMessageByDate)
|| IS_CMD(xfeCmdMarkAllMessagesRead)
|| IS_CMD(xfeCmdMarkThreadRead)
|| IS_CMD(xfeCmdMarkMessageForLater)
|| IS_CMD(xfeCmdMarkMessage)
|| IS_CMD(xfeCmdReplyToSender)
|| IS_CMD(xfeCmdReplyToAll)
|| IS_CMD(xfeCmdReplyToNewsgroup)
|| IS_CMD(xfeCmdReplyToSenderAndNewsgroup)
|| IS_CMD(xfeCmdForwardMessage)
|| IS_CMD(xfeCmdForwardMessageQuoted)
|| IS_CMD(xfeCmdForwardMessageInLine)
|| IS_CMD(xfeCmdShowAllHeaders)
|| IS_CMD(xfeCmdShowNormalHeaders)
|| IS_CMD(xfeCmdShowBriefHeaders)
|| IS_CMD(xfeCmdViewAttachmentsInline)
|| IS_CMD(xfeCmdViewAttachmentsAsLinks)
|| IS_CMD(xfeCmdRot13Message)
|| IS_CMD(xfeCmdMoveMessage)
|| IS_CMD(xfeCmdCopyMessage)
|| IS_CMD(xfeCmdNewFolder)
|| IS_CMD(xfeCmdRenameFolder)
|| IS_CMD(xfeCmdEmptyTrash)
|| IS_CMD(xfeCmdCompressAllFolders)
|| IS_CMD(xfeCmdAddNewsgroup)
|| IS_CMD(xfeCmdUpdateMessageCount)
|| IS_CMD(xfeCmdPrintSetup)
|| IS_CMD(xfeCmdPrintPreview)
|| IS_CMD(xfeCmdEditMessage)
|| IS_CMD(xfeCmdToggleThreadKilled)
|| IS_CMD(xfeCmdToggleThreadWatched)
/* priorities. */
|| IS_CMD(xfeCmdSetPriorityHighest)
|| IS_CMD(xfeCmdSetPriorityHigh)
|| IS_CMD(xfeCmdSetPriorityNormal)
|| IS_CMD(xfeCmdSetPriorityLow)
|| IS_CMD(xfeCmdSetPriorityLowest)
|| IS_CMD(xfeCmdSetPriorityNone)
|| IS_CMD(xfeCmdIgnoreThread)
|| IS_CMD(xfeCmdWatchThread)
|| IS_CMD(xfeCmdModerateDiscussion)
|| IS_CMD(xfeCmdWrapLongLines)
|| IS_CMD(xfeCmdMommy))
{
return True;
}
else
{
return XFE_MNView::handlesCommand(cmd, calldata);
}
#undef IS_CMD
}
char*
XFE_MsgView::commandToString(CommandType cmd, void * calldata, XFE_CommandInfo* info)
{
#define IS_CMD(command) cmd == (command)
if ( (IS_CMD(xfeCmdDeleteMessage) || IS_CMD(xfeCmdCancelMessages))
&& isDisplayingNews() )
return XP_GetString(MK_MSG_CANCEL_MESSAGE);
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;
}
MSG_CommandType msg_cmd = commandToMsgCmd(cmd);
MSG_MotionType msg_nav = commandToMsgNav(cmd);
const char *display_string = NULL;
if (msg_cmd != (MSG_CommandType)~0)
{
if (IS_CMD(xfeCmdGetNewMessages)) {
int num_inboxes = MSG_GetFoldersWithFlag(XFE_MNView::getMaster(),
MSG_FOLDER_FLAG_INBOX,
NULL, 0);
if ((num_inboxes >0) ||
(MSG_CommandStatus(m_pane, msg_cmd,
NULL, 0, NULL, NULL,
(const char **)&display_string, NULL) < 0)) {
return NULL;
}/* if */
return (char*)display_string;
}/* if */
else if (MSG_CommandStatus(m_pane, msg_cmd,
NULL, 0, NULL, NULL,
(const char **)&display_string, NULL) < 0)
return NULL;
else
{
if ( (cmd == xfeCmdComposeMessageHTML ) ||
( cmd == xfeCmdComposeMessagePlain) ||
( cmd == xfeCmdComposeArticleHTML) ||
( cmd == xfeCmdComposeArticlePlain) )
{
return NULL;
}
else
return (char*)display_string;
}
}
else if (msg_cmd != (MSG_MotionType)~0)
{
MessageKey key;
MSG_ViewIndex index;
MSG_FolderInfo *info;
MSG_GetCurMessage(m_pane, &info, &key, &index);
if (index == MSG_VIEWINDEXNONE
|| MSG_NavigateStatus(m_pane, msg_nav,
(MSG_ViewIndex)index,
NULL, (const char **)&display_string) < 0)
return NULL;
else
{
if ( (cmd == xfeCmdComposeMessageHTML ) ||
( cmd == xfeCmdComposeMessagePlain) ||
( cmd == xfeCmdComposeArticleHTML) ||
( cmd == xfeCmdComposeArticlePlain) )
{
return NULL;
}
else
return (char*)display_string;
}
}
else if (IS_CMD(xfeCmdFindInObject))
{
/* short circuit HTMLView's "Find in Page/Frame" and keep
our "Find in Message." */
return NULL;
}
else
return XFE_MNView::commandToString(cmd, calldata, info);
#undef IS_CMD
}
XFE_CALLBACK_DEFN(XFE_MsgView, showPopup)(XFE_NotificationCenter *,
void *, void *calldata)
{
D(printf("XFE_MsgView::showPopup()\n");)
XEvent *event = (XEvent *)calldata;
URL_Struct *url_under_mouse = m_htmlView->URLUnderMouse();
URL_Struct *image_under_mouse = m_htmlView->ImageUnderMouse();
URL_Struct *background_under_mouse = m_htmlView->BackgroundUnderMouse();
XP_Bool isBrowserLink = FALSE;
XP_Bool isAttachmentLink = FALSE;
XP_Bool isLink = url_under_mouse != NULL;
XP_Bool isImage = image_under_mouse != NULL;
XP_Bool needSeparator = FALSE;
XP_Bool haveAddedItems = FALSE;
if (m_popup)
delete m_popup;
/* Need to switch focus for the popup menu so that menu items can be enabled in
the three pane world */
XFE_ThreadView *threadView = (XFE_ThreadView *)getParent(); /* returns the thread view */
if (threadView)
getToplevel()->notifyInterested(XFE_MNListView::changeFocus, (void*) threadView);
m_popup = new XFE_PopupMenu("popup",(XFE_Frame*)m_toplevel,
XfeAncestorFindApplicationShell(m_widget));
if (url_under_mouse != NULL
&& XP_STRNCMP ("mailto:", url_under_mouse->address, 7) != 0
&& XP_STRNCMP ("telnet:", url_under_mouse->address, 7) != 0
&& XP_STRNCMP ("tn3270:", url_under_mouse->address, 7) != 0
&& XP_STRNCMP ("rlogin:", url_under_mouse->address, 7) != 0
&& XP_STRNCMP ("addbook:", url_under_mouse->address, 8) != 0)
{
isBrowserLink = TRUE;
}
if (url_under_mouse != NULL
&& XP_STRNCASECMP ("mailbox:", url_under_mouse->address, 8) != 0
&& XP_STRSTR(url_under_mouse->address, "part?"))
{
isAttachmentLink = TRUE;
}
/* turn off everything if the user right clicks on the paperclip icon */
if (url_under_mouse != NULL
&& XP_STRCMP ("mailbox:displayattachments", url_under_mouse->address) == 0)
{
isBrowserLink = FALSE;
isAttachmentLink = FALSE;
isImage = FALSE;
}
#define ADD_MENU_SEPARATOR { \
if (haveAddedItems) { \
needSeparator = TRUE; \
haveAddedItems = FALSE; \
} \
}
#define ADD_SPEC(theSpec) { \
if (needSeparator) \
m_popup->addMenuSpec(separator_spec); \
m_popup->addMenuSpec(theSpec); \
needSeparator = FALSE; \
haveAddedItems = TRUE; \
}
if (isBrowserLink) ADD_SPEC ( openLinkNew_spec );
#ifdef EDITOR
if (isBrowserLink) ADD_SPEC ( openLinkEdit_spec );
#endif
ADD_MENU_SEPARATOR;
ADD_SPEC ( repl_spec );
ADD_MENU_SEPARATOR;
ADD_SPEC ( addr_spec );
ADD_MENU_SEPARATOR;
ADD_SPEC ( filemsg_spec );
if (isCommandEnabled(xfeCmdStopLoading)) ADD_SPEC ( stopLoading_spec );
ADD_MENU_SEPARATOR;
if (isImage) ADD_SPEC ( openImage_spec );
ADD_MENU_SEPARATOR;
if (isBrowserLink) ADD_SPEC ( saveLink_spec );
if (isImage) ADD_SPEC ( saveImage_spec );
ADD_MENU_SEPARATOR;
if (isCommandEnabled(xfeCmdCopy)) ADD_SPEC ( copy_spec );
if (isLink) ADD_SPEC ( copyLink_spec );
if (isImage) ADD_SPEC ( copyImage_spec );
// Finish up the popup
m_popup->position (event);
m_popup->show();
}
XFE_CALLBACK_DEFN(XFE_MsgView, spaceAtMsgEnd)(XFE_NotificationCenter *,
void *, void */*callData*/)
{
notifyInterested(spacebarAtMsgBottom);
}
XFE_CALLBACK_DEFN(XFE_MsgView, refresh)(XFE_NotificationCenter *,
void *, void */*callData*/)
{
m_htmlView->doCommand(xfeCmdRefresh);
}