home *** CD-ROM | disk | FTP | other *** search
Wrap
/* -*- 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" //#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 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, NULL, "reply-to-sender" }, { xfeCmdReplyToAll, PUSHBUTTON, NULL, NULL, NULL, "reply-to-all" }, { xfeCmdReplyToNewsgroup, PUSHBUTTON, NULL, NULL, NULL, "reply-to-newsgroup" }, { xfeCmdReplyToSenderAndNewsgroup, PUSHBUTTON, NULL, NULL, NULL, "reply-to-sender-and-newsgroup" }, { xfeCmdForwardMessage, PUSHBUTTON }, { xfeCmdForwardMessageQuoted, 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, NULL, "reply-to-sender" }, { xfeCmdReplyToAll, PUSHBUTTON, NULL, NULL, NULL, "reply-to-all" }, { xfeCmdForwardMessage, PUSHBUTTON }, { xfeCmdForwardMessageQuoted, 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 } }; 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; #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; 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 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 || 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 (!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 (!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 */) { int listChangeDepth = m_outliner->getListChangeDepth()-1; #if defined(DEBUG_tao) 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 */ } #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 defined(DEL_5_0) 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; 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 */ else XP_ASSERT(0); }/* 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; processCmdQueue(); }/* if */ else XP_ASSERT(0); }/* 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 */ else XP_ASSERT(0); #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; }/* notify == MSG_NotifyInsertOrDelete */ #if defined(DEBUG_tao) printf("\n<<XFE_ThreadView::listChangeFinished, m_lastLoadedInd=%d", m_lastLoadedInd); #endif #else if (notify == MSG_NotifyChanged) { m_lineChanged = where; return; }/* if */ else if (notify == MSG_NotifyInsertOrDelete && num <= 0) { if (num == 0) { /* SPECIAL case: the header got deleted */ /* we do not care deletion on non-focusing line */ if (m_lastLoadedInd != where) return; /* deleted */ if (m_deletedCount && m_deleted) m_deleted = (int *) XP_REALLOC(m_deleted, (m_deletedCount+1)*sizeof(int)); else m_deleted = (int *) XP_CALLOC(1, sizeof(int)); m_deleted[m_deletedCount++] = where; #if defined(DEBUG_tao) printf("\n**>SPECIAL case:listChangeFinished=%d, m_deletedCount=%d\n", where, m_deletedCount); #endif }/* if */ else 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 */ if (!m_deletedCount && !m_deleted) { m_deleted = (int *) XP_CALLOC(1, sizeof(int)); m_deleted[m_deletedCount++] = where-1; processCmdQueue(); }/* if */ }/* if */ }/* if */ else if (num == -1){ /* we do not care deletion on non-focusing line */ if (m_lastLoadedInd != where) return; /* deleted */ if (m_deletedCount && m_deleted) m_deleted = (int *) XP_REALLOC(m_deleted, (m_deletedCount+1)*sizeof(int)); else m_deleted = (int *) XP_CALLOC(1, sizeof(int)); m_deleted[m_deletedCount++] = where; #if defined(DEBUG_tao) printf("\n-->listChangeFinished=%d, m_deletedCount=%d\n", where, m_deletedCount); #endif }/* else if num == -1 */ }/* else if notify == MSG_NotifyInsertOrDelete && num < 0*/ #endif /* DEL_5_0 */ 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; 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 */ #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 MessageKey id = (MessageKey) value; MSG_ViewIndex index = MSG_GetMessageIndexForKey(m_pane, id, False); #if defined(DEBUG_tao) 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; } /* 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; // only need to do everything below here if the folder being // loaded is different than what's currently displayed. if (m_folderInfo != folderInfo) { // must be valid. XP_ASSERT(folderInfo); // clear the currently display message, since we're in a different folder now. showMessage(-1); 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 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 (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 (m_msgExpanded) { m_msgview->loadMessage(m_folderInfo, (row == -1 ? MSG_MESSAGEKEYNONE : MSG_GetMessageKey(m_pane, row))); } 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(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(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); // DeleteMessage stands for CancelMessage in the ThreadView, // so intercept it early: if ( (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(xfeCmdNextMessage) || IS_CMD(xfeCmdNextUnreadMessage) || IS_CMD(xfeCmdPreviousMessage) || IS_CMD(xfeCmdPreviousUnreadMessage) || 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); } else if (IS_CMD(xfeCmdMommy)) { fe_showFoldersWithSelected(XtParent(getToplevel()->getBaseWidget()), 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; 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(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))) { // 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)) { 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); } else if (IS_CMD(xfeCmdSearchAddress)) { fe_showLdapSearch(XfeAncestorFindApplicationShell(getToplevel()->getBaseWidget()), 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()), 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()), 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 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 == 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()), 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 { // 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); } 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 (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); m_outliner->makeVisible(index); 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); }