home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / src / ThreadView.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  99.1 KB  |  3,582 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /* 
  19.    ThreadView.cpp -- presents view of mail threads.
  20.    Created: Chris Toshok <toshok@netscape.com>, 7-Aug-96.
  21.    */
  22.  
  23.  
  24.  
  25. #include "MozillaApp.h"
  26. #include "ThreadView.h"
  27. #include "MsgFrame.h"
  28. #include "FolderFrame.h"
  29. #include "FolderMenu.h"
  30. #include "ViewGlue.h"
  31.  
  32. #if defined(USE_MOTIF_DND)
  33. #include "OutlinerDrop.h"
  34. #endif /* USE_MOTIF_DND */
  35.  
  36. #include "xpassert.h"
  37. #include "xfe.h"
  38. #include "icondata.h"
  39. #include "msgcom.h"
  40. //#include "allxpstr.h"
  41. #include "felocale.h" /* for fe_ConvertToLocalEncoding */
  42. #include "xp_mem.h"
  43. #include "Xfe/Xfe.h"
  44.  
  45. #include <Xm/ArrowB.h>
  46. #include <Xm/Form.h>
  47. #include <Xm/Label.h>
  48. #include <Xm/PanedW.h>
  49.  
  50. #include "MNSearchFrame.h"
  51. #include "MailFilterDlg.h"
  52. #include "LdapSearchFrame.h"
  53. #include "prefs.h"
  54.  
  55. #include "prefapi.h"
  56.  
  57. #ifdef DEBUG_toshok
  58. #define D(x) x
  59. #else
  60. #define D(x)
  61. #endif
  62.  
  63. #ifdef DEBUG_dora
  64. #define DD(x) x
  65. #else
  66. #define DD(x)
  67. #endif
  68.  
  69. #define OUTLINER_GEOMETRY_PREF "mail.threadpane.outliner_geometry"
  70. #define MESSAGEPANE_HEIGHT_PREF "mail.threadpane.messagepane_height"
  71.  
  72. #include "xpgetstr.h"
  73.  
  74. extern int XFE_RE;
  75. extern int XFE_WINDOW_TITLE_NEWSGROUP;
  76. extern int XFE_WINDOW_TITLE_FOLDER;
  77. extern int XFE_SIZE_IN_LINES;
  78. extern int XFE_SIZE_IN_BYTES;
  79. extern int XFE_THREAD_OUTLINER_COLUMN_SUBJECT;
  80. extern int XFE_THREAD_OUTLINER_COLUMN_DATE;
  81. extern int XFE_THREAD_OUTLINER_COLUMN_PRIORITY;
  82. extern int XFE_THREAD_OUTLINER_COLUMN_STATUS;
  83. extern int XFE_THREAD_OUTLINER_COLUMN_SENDER;
  84. extern int XFE_THREAD_OUTLINER_COLUMN_RECIPIENT;
  85.  
  86. extern int XP_STATUS_NEW;
  87. extern int XP_STATUS_REPLIED_AND_FORWARDED;
  88. extern int XP_STATUS_FORWARDED;
  89. extern int XP_STATUS_REPLIED;
  90.  
  91. extern int MK_MSG_CANCEL_MESSAGE;
  92. extern int MK_MSG_DELETE_SEL_MSGS;
  93.  
  94. extern int XFE_DND_MESSAGE_ERROR;
  95.  
  96. const int XFE_ThreadView::OUTLINER_COLUMN_SUBJECT = 0;
  97. const int XFE_ThreadView::OUTLINER_COLUMN_SENDERRECIPIENT = 1;
  98. const int XFE_ThreadView::OUTLINER_COLUMN_UNREADMSG = 2;
  99. const int XFE_ThreadView::OUTLINER_COLUMN_DATE = 3;
  100. const int XFE_ThreadView::OUTLINER_COLUMN_PRIORITY = 4;
  101. const int XFE_ThreadView::OUTLINER_COLUMN_FLAG = 5;
  102. const int XFE_ThreadView::OUTLINER_COLUMN_STATUS = 6;
  103. const int XFE_ThreadView::OUTLINER_COLUMN_SIZE = 7;
  104.  
  105. // Minimum and maximum sizes for the paned window panes:
  106. #define PANE_MIN 50
  107. #define PANE_MAX 6000
  108.  
  109. fe_icon XFE_ThreadView::threadonIcon = { 0 };
  110. fe_icon XFE_ThreadView::threadoffIcon = { 0 };
  111.  
  112. MenuSpec XFE_ThreadView::priority_popup_submenu[] = {
  113.   { xfeCmdSetPriorityHighest,    PUSHBUTTON },
  114.   { xfeCmdSetPriorityHigh,    PUSHBUTTON },
  115.   { xfeCmdSetPriorityNormal,    PUSHBUTTON },
  116.   { xfeCmdSetPriorityLow,    PUSHBUTTON },
  117.   { xfeCmdSetPriorityLowest,    PUSHBUTTON },
  118.   { NULL }
  119. };
  120.  
  121. MenuSpec XFE_ThreadView::news_popup_spec[] = {
  122.   { xfeCmdOpenSelected,     PUSHBUTTON },
  123. // open in new window
  124.   MENU_SEPARATOR,
  125.   // Setting the call data to non-null is a signal to commandToString
  126.   // not to reset the menu string
  127.   { xfeCmdReplyToSender,    PUSHBUTTON, NULL, NULL, NULL, "reply-to-sender" },
  128.   { xfeCmdReplyToAll,    PUSHBUTTON, NULL, NULL, NULL, "reply-to-all" },
  129.   { xfeCmdReplyToNewsgroup,    PUSHBUTTON, NULL, NULL, NULL, "reply-to-newsgroup" },
  130.   { xfeCmdReplyToSenderAndNewsgroup,    PUSHBUTTON, NULL, NULL, NULL, "reply-to-sender-and-newsgroup" },
  131.   { xfeCmdForwardMessage,        PUSHBUTTON },
  132.   { xfeCmdForwardMessageQuoted,    PUSHBUTTON },
  133.   MENU_SEPARATOR,
  134.   { "addToABSubmenu",   CASCADEBUTTON,
  135.     (MenuSpec *) &addrbk_submenu_spec },
  136.   MENU_SEPARATOR,
  137.   { xfeCmdIgnoreThread,        PUSHBUTTON },
  138.   { xfeCmdWatchThread,        PUSHBUTTON },
  139.   MENU_SEPARATOR,
  140.   { "fileSubmenu",              DYNA_CASCADEBUTTON, NULL, NULL, False, (void*)xfeCmdMoveMessage, XFE_FolderMenu::generate },
  141.   { xfeCmdDeleteMessage,    PUSHBUTTON },
  142.   { xfeCmdSaveMessagesAs,    PUSHBUTTON },
  143.   { xfeCmdPrint,        PUSHBUTTON },
  144.   { NULL }
  145.  
  146. };
  147.  
  148. MenuSpec XFE_ThreadView::mail_popup_spec[] = {
  149.   { xfeCmdOpenSelected,     PUSHBUTTON },
  150.   MENU_SEPARATOR,
  151.   // Setting the call data to non-null is a signal to commandToString
  152.   // not to reset the menu string
  153.   { xfeCmdReplyToSender,    PUSHBUTTON, NULL, NULL, NULL, "reply-to-sender" },
  154.   { xfeCmdReplyToAll,        PUSHBUTTON, NULL, NULL, NULL, "reply-to-all" },
  155.   { xfeCmdForwardMessage,    PUSHBUTTON },
  156.   { xfeCmdForwardMessageQuoted,    PUSHBUTTON },
  157.   MENU_SEPARATOR,
  158.   { "addToABSubmenu",   CASCADEBUTTON,
  159.     (MenuSpec *) &addrbk_submenu_spec },
  160.   MENU_SEPARATOR,
  161.   { xfeCmdIgnoreThread,        PUSHBUTTON },
  162.   { xfeCmdWatchThread,        PUSHBUTTON },
  163.   MENU_SEPARATOR,
  164.   { "changePriority",        CASCADEBUTTON, priority_popup_submenu },
  165.   MENU_SEPARATOR,
  166.   { "fileSubmenu",              DYNA_CASCADEBUTTON, NULL, NULL, False, (void*)xfeCmdMoveMessage, XFE_FolderMenu::generate },
  167.   { xfeCmdDeleteMessage,    PUSHBUTTON },
  168.   { xfeCmdSaveMessagesAs,    PUSHBUTTON },
  169.   { xfeCmdPrint,        PUSHBUTTON },
  170.   { NULL }
  171. };
  172.  
  173. MenuSpec XFE_ThreadView::addrbk_submenu_spec[] = {
  174.     { xfeCmdAddSenderToAddressBook,    PUSHBUTTON },
  175.     { xfeCmdAddAllToAddressBook,        PUSHBUTTON },
  176.     //  { xfeCmdAddCardToAddressBook,        PUSHBUTTON } ?
  177.     { NULL }
  178. };
  179.  
  180. XFE_ThreadView::XFE_ThreadView(XFE_Component *toplevel_component,
  181.                    Widget parent,
  182.                    XFE_View *parent_view, MWContext *context,
  183.                    MSG_Pane *p) 
  184.   : XFE_MNListView(toplevel_component, parent_view, context, p)
  185. {
  186.   /* initialize
  187.    */
  188.   m_nLoadingFolders = 0;
  189.  
  190.   m_frameDeleted = False;
  191.  
  192. #if HANDLE_CMD_QUEUE
  193.  
  194.   m_lastLoadedInd = MSG_VIEWINDEXNONE;
  195.   m_lastLoadedKey = MSG_MESSAGEKEYNONE;
  196.   m_lineChanged = MSG_VIEWINDEXNONE;
  197.  
  198.   m_selected = NULL;
  199.   m_selectedCount = 0;
  200.  
  201.   m_deleted = NULL;
  202.   m_deletedCount = 0;
  203.  
  204.   m_collapsed = NULL;
  205.   m_collapsedCount = 0;
  206.  
  207. #endif /* HANDLE_CMD_QUEUE */
  208.  
  209.   Widget panedw;
  210.   int num_columns = 8;
  211.   XtWidgetGeometry arrow_geo;
  212.   static int default_column_widths[] = {30, 20, 3, 20, 9, 3, 15, 6};
  213.  
  214.   panedw = XtVaCreateWidget("panedw",
  215.                             xmPanedWindowWidgetClass,
  216.                             parent,
  217.                             NULL);
  218.  
  219.  
  220.   // create the outliner message list.
  221.   m_outliner = new XFE_Outliner("messageList",
  222.                                 this,
  223.                                 getToplevel(),
  224.                                 panedw,
  225.                                 FALSE,  // constantSize
  226.                                 TRUE,   // hasHeadings
  227.                                 num_columns, 
  228.                                 5,
  229.                                 default_column_widths,
  230.                                 OUTLINER_GEOMETRY_PREF);
  231.  
  232.   // initialize the icons if they haven't already been
  233.   {
  234.     Pixel bg_pixel;
  235.     
  236.     XtVaGetValues(m_outliner->getBaseWidget(), XmNbackground, &bg_pixel, 0);
  237.  
  238.     initMessageIcons(getToplevel()->getBaseWidget(),
  239.                      getToplevel()->getFGPixel(),
  240.                      bg_pixel);
  241.   }
  242.  
  243.   // now that we've created the icons, we can size the two icon-only columns to be
  244.   // the widths required of the pixmaps.
  245.  
  246.   m_outliner->setColumnWidth ( OUTLINER_COLUMN_UNREADMSG, msgUnreadIcon.width + 2 /* for the outliner's shadow */);
  247.   m_outliner->setColumnWidth ( OUTLINER_COLUMN_FLAG, msgFlagIcon.width + 2 /* for the outliner's shadow */);
  248.  
  249.   m_outliner->setPipeColumn( OUTLINER_COLUMN_SUBJECT );
  250.   m_outliner->setMultiSelectAllowed( True );
  251.  
  252.   m_outliner->setColumnResizable( OUTLINER_COLUMN_UNREADMSG, False );
  253.   m_outliner->setColumnResizable( OUTLINER_COLUMN_FLAG, False );
  254.  
  255.   m_outliner->setHideColumnsAllowed( True );
  256.  
  257. #if !defined(USE_MOTIF_DND)
  258.   fe_dnd_CreateDrop(m_outliner->getBaseWidget(), drop_func, this);
  259. #endif /* USE_MOTIF_DND */
  260.  
  261.   XtVaSetValues(m_outliner->getBaseWidget(),
  262.                 XmNallowResize, TRUE,
  263.                 XmNpaneMinimum, PANE_MIN, // should this be a resource?
  264.                 XmNpaneMaximum, PANE_MAX, // why is the limit in HPaned 1000???
  265.                 NULL);
  266.  
  267.   m_outliner->show();
  268.  
  269.   // create the arrow button stuff
  270.  
  271.   m_arrowform = XtVaCreateManagedWidget("arrowform",
  272.                                         xmFormWidgetClass,
  273.                                         panedw,
  274.                                         XmNallowResize, FALSE,
  275.                                         XmNskipAdjust, TRUE,
  276.                                         NULL);
  277.  
  278.   m_arrowb = XtVaCreateManagedWidget("arrowb",
  279.                      xmArrowButtonWidgetClass,
  280.                      m_arrowform,
  281.                      XmNleftAttachment, XmATTACH_FORM,
  282.                      XmNtopAttachment, XmATTACH_FORM,
  283.                      XmNbottomAttachment, XmATTACH_FORM,
  284.                      XmNrightAttachment, XmATTACH_NONE,
  285.                      XmNarrowDirection, XmARROW_DOWN,
  286.                      XmNshadowThickness, 0,
  287.                      NULL);
  288.  
  289.   XtAddCallback(m_arrowb, XmNactivateCallback, toggleMsgExpansionCallback, this);
  290.  
  291.   // Arrow label should be blank initially.
  292.   XmString tempString = XmStringCreateSimple(" ");
  293.   m_arrowlabel = XtVaCreateManagedWidget("arrowlabel",
  294.                      xmLabelWidgetClass,
  295.                      m_arrowform,
  296.                      XmNleftAttachment, XmATTACH_WIDGET,
  297.                      XmNleftWidget, m_arrowb,
  298.                      XmNtopAttachment, XmATTACH_FORM,
  299.                      XmNbottomAttachment, XmATTACH_FORM,
  300.                      XmNrightAttachment, XmATTACH_FORM,
  301.                      XmNalignment, XmALIGNMENT_BEGINNING,
  302.                      XmNlabelString, tempString,
  303.                      NULL);
  304.   XmStringFree(tempString);
  305.  
  306.   arrow_geo.request_mode = CWHeight;
  307.   XtQueryGeometry(m_arrowform, NULL, &arrow_geo);
  308.  
  309.   XtVaSetValues(m_arrowform,
  310.         XmNpaneMaximum, arrow_geo.height,
  311.         XmNpaneMinimum, arrow_geo.height,
  312.         NULL);
  313.  
  314.   // create the message viewing area.
  315.   m_msgview = new XFE_MsgView(toplevel_component, panedw, this, m_contextData);
  316.   addView(m_msgview);
  317.  
  318.   XtVaSetValues(m_msgview->getBaseWidget(),
  319.                 XmNallowResize, TRUE,
  320.                 XmNpaneMinimum, PANE_MIN, // should this be a resource?
  321.                 XmNpaneMaximum, PANE_MAX, // why is the limit in PanedW 1000???
  322.                 NULL);
  323.  
  324.   m_msgview->registerInterest(XFE_MsgView::spacebarAtMsgBottom,
  325.                   this,
  326.                   (XFE_FunctionNotification)spaceAtMsgEnd_cb);
  327.  
  328.   m_msgview->registerInterest(XFE_MsgView::messageHasChanged,
  329.                               this,
  330.                               (XFE_FunctionNotification)newMessageLoading_cb);
  331.  
  332.   getToplevel()->registerInterest(XFE_Frame::allConnectionsCompleteCallback,
  333.                                   this,
  334.                                   (XFE_FunctionNotification)allConnectionsComplete_cb);
  335.  
  336.   if (!p)
  337.     setPane(MSG_CreateThreadPane(m_contextData,
  338.                  XFE_MNView::m_master));
  339.  
  340.  
  341.   m_msgExpanded = TRUE;
  342.  
  343.   {
  344.       Widget scrolled = XtNameToWidget (m_msgview->getBaseWidget(), "*scroller");
  345.       int32 message_pane_desired_height;
  346.       PREF_GetIntPref(MESSAGEPANE_HEIGHT_PREF, &message_pane_desired_height);
  347.  
  348.       XtVaSetValues(scrolled,
  349.                     XmNheight, message_pane_desired_height,
  350.                     NULL);
  351.       
  352.       m_msgview->show();
  353.   }
  354.  
  355.   /* safe default, for now.  It'll be overriden (if need be), when
  356.      a folder is loaded. */
  357.  
  358.   m_displayingDraft = FALSE;
  359.  
  360.   m_commandPending = noPendingCommand;
  361.   m_getNewMsg = False;
  362.  
  363.   m_selectionAfterDeleting = MSG_VIEWINDEXNONE;
  364.   m_popup = NULL;
  365.   m_folderInfo = NULL;
  366.  
  367.   setBaseWidget(panedw);
  368. }
  369.  
  370. XFE_ThreadView::~XFE_ThreadView()
  371. {
  372. D(printf ("In XFE_ThreadView::~XFE_ThreadView()\n");)
  373.  
  374.  
  375.     /* save off the height of the message pane. */
  376.     {
  377.         Dimension message_pane_height;
  378.         Widget scrolled = XtNameToWidget (m_msgview->getBaseWidget(), "*scroller");
  379.         
  380.         XtVaGetValues(scrolled,
  381.                       XmNheight, &message_pane_height,
  382.                       NULL);
  383.         
  384.         PREF_SetIntPref(MESSAGEPANE_HEIGHT_PREF, (int32)message_pane_height);
  385.     }        
  386.  
  387.   delete m_outliner;
  388.  
  389.   destroyPane();
  390.  
  391.   if (m_popup)
  392.     delete m_popup;
  393.  
  394.   // XFE_View destroys m_msgview for us.
  395. }
  396.  
  397. void XFE_ThreadView::setGetNewMsg(XP_Bool b)
  398. {
  399.     m_getNewMsg = b;
  400. }
  401.  
  402. fe_icon*
  403. XFE_ThreadView::flagToIcon(int folder_flags, int message_flags)
  404. {
  405.     if (folder_flags & MSG_FOLDER_FLAG_NEWSGROUP)
  406.         return (message_flags & MSG_FLAG_READ ? &newsPostIcon : &newsNewIcon);
  407.     else if (folder_flags & MSG_FOLDER_FLAG_DRAFTS)
  408.         return &draftIcon;
  409.     else if (message_flags & MSG_FLAG_IMAP_DELETED
  410.              || message_flags & MSG_FLAG_EXPUNGED)
  411.         return &deletedIcon;
  412.     else
  413.         return (message_flags & MSG_FLAG_READ ? &mailMessageReadIcon : &mailMessageUnreadIcon);
  414. }
  415.  
  416. #if defined(USE_MOTIF_DND)
  417. fe_icon_data*
  418. XFE_ThreadView::flagToIconData(int folder_flags, int message_flags)
  419. {
  420.   if (folder_flags & MSG_FOLDER_FLAG_NEWSGROUP)
  421.     return (message_flags & MSG_FLAG_READ ? &MN_Newspost : &MN_NewsNew);
  422.   else if (folder_flags & MSG_FOLDER_FLAG_DRAFTS)
  423.     return &MN_Draftfile;
  424.   else if (message_flags & MSG_FLAG_IMAP_DELETED
  425.            || message_flags & MSG_FLAG_EXPUNGED)
  426.     return &MN_Delete;
  427.   else
  428.     return (message_flags & MSG_FLAG_READ ? &MN_MailRead : &MN_MailUnread);
  429. }
  430. #endif /* USE_MOTIF_DND */
  431.  
  432. void
  433. XFE_ThreadView::initMessageIcons(Widget widget,
  434.                                  Pixel bg_pixel,
  435.                                  Pixel fg_pixel)
  436. {
  437.     static Boolean init_icons_done = False;
  438.  
  439.     if (init_icons_done)
  440.         return;
  441.  
  442.     init_icons_done = True;
  443.  
  444.     if (!mailMessageReadIcon.pixmap)
  445.         fe_NewMakeIcon(widget,
  446.                        fg_pixel,
  447.                        bg_pixel,
  448.                        &mailMessageReadIcon,
  449.                        NULL, 
  450.                        MN_MailRead.width, MN_MailRead.height,
  451.                        MN_MailRead.mono_bits, MN_MailRead.color_bits, MN_MailRead.mask_bits, FALSE); 
  452.  
  453.     if (!mailMessageUnreadIcon.pixmap)
  454.         fe_NewMakeIcon(widget,
  455.                        fg_pixel,
  456.                        bg_pixel,
  457.                        &mailMessageUnreadIcon,
  458.                        NULL, 
  459.                        MN_MailUnread.width, MN_MailUnread.height,
  460.                        MN_MailUnread.mono_bits, MN_MailUnread.color_bits, MN_MailUnread.mask_bits, FALSE);
  461.  
  462.     if (!draftIcon.pixmap)
  463.         fe_NewMakeIcon(widget,
  464.                        fg_pixel,
  465.                        bg_pixel,
  466.                        &draftIcon,
  467.                        NULL, 
  468.                        MN_Draftfile.width, MN_Draftfile.height,
  469.                        MN_Draftfile.mono_bits, MN_Draftfile.color_bits, MN_Draftfile.mask_bits, FALSE);
  470.     
  471.     if (!newsPostIcon.pixmap)
  472.         fe_NewMakeIcon(widget,
  473.                        fg_pixel,
  474.                        bg_pixel,
  475.                        &newsPostIcon,
  476.                        NULL, 
  477.                        MN_Newspost.width, MN_Newspost.height,
  478.                        MN_Newspost.mono_bits, MN_Newspost.color_bits, MN_Newspost.mask_bits, FALSE);
  479.  
  480.     if (!newsNewIcon.pixmap)
  481.         fe_NewMakeIcon(widget,
  482.                        fg_pixel,
  483.                        bg_pixel,
  484.                        &newsNewIcon,
  485.                        NULL, 
  486.                        MN_NewsNew.width, MN_NewsNew.height,
  487.                        MN_NewsNew.mono_bits, MN_NewsNew.color_bits, MN_NewsNew.mask_bits, FALSE);
  488.     
  489.     if (!msgReadIcon.pixmap)
  490.         fe_NewMakeIcon(widget,
  491.                        fg_pixel,
  492.                        bg_pixel,
  493.                        &msgReadIcon,
  494.                        NULL, 
  495.                        MN_DotRead.width, MN_DotRead.height,
  496.                        MN_DotRead.mono_bits, MN_DotRead.color_bits, MN_DotRead.mask_bits, FALSE);
  497.     
  498.     if (!msgUnreadIcon.pixmap)
  499.         fe_NewMakeIcon(widget,
  500.                        fg_pixel,
  501.                        bg_pixel,
  502.                        &msgUnreadIcon,
  503.                        NULL, 
  504.                        MN_Unread.width, MN_Unread.height,
  505.                        MN_Unread.mono_bits, MN_Unread.color_bits, MN_Unread.mask_bits, FALSE);
  506.  
  507.     if (!msgFlagIcon.pixmap)
  508.         fe_NewMakeIcon(widget,
  509.                        fg_pixel,
  510.                        bg_pixel,
  511.                        &msgFlagIcon,
  512.                        NULL, 
  513.                        MN_Flag.width, MN_Flag.height,
  514.                        MN_Flag.mono_bits, MN_Flag.color_bits, MN_Flag.mask_bits, FALSE);
  515.     
  516.     if (!threadonIcon.pixmap)
  517.         fe_NewMakeIcon(widget,
  518.                        fg_pixel,
  519.                        bg_pixel,
  520.                        &threadonIcon,
  521.                        NULL, 
  522.                        threadon.width, threadon.height,
  523.                        threadon.mono_bits, threadon.color_bits, 
  524.                        threadon.mask_bits, FALSE);
  525.     
  526.     if (!threadoffIcon.pixmap)
  527.         fe_NewMakeIcon(widget,
  528.                        fg_pixel,
  529.                        bg_pixel,
  530.                        &threadoffIcon,
  531.                        NULL, 
  532.                        threadoff.width, threadoff.height,
  533.                        threadoff.mono_bits, threadoff.color_bits, 
  534.                        threadoff.mask_bits, FALSE);
  535.  
  536.     if (!openSpoolIgnoredIcon.pixmap)
  537.         fe_NewMakeIcon(widget,
  538.                        fg_pixel,
  539.                        bg_pixel,
  540.                        &openSpoolIgnoredIcon,
  541.                        NULL,
  542.                        MN_ThreadIgnoreO.width, MN_ThreadIgnoreO.height,
  543.                        MN_ThreadIgnoreO.mono_bits, MN_ThreadIgnoreO.color_bits,
  544.                        MN_ThreadIgnoreO.mask_bits, FALSE);
  545.  
  546.     if (!closedSpoolIgnoredIcon.pixmap)
  547.         fe_NewMakeIcon(widget,
  548.                        fg_pixel,
  549.                        bg_pixel,
  550.                        &closedSpoolIgnoredIcon,
  551.                        NULL,
  552.                        MN_ThreadIgnore.width, MN_ThreadIgnore.height,
  553.                        MN_ThreadIgnore.mono_bits, MN_ThreadIgnore.color_bits,
  554.                        MN_ThreadIgnore.mask_bits, FALSE);
  555.  
  556.     if (!openSpoolWatchedIcon.pixmap)
  557.         fe_NewMakeIcon(widget,
  558.                        fg_pixel,
  559.                        bg_pixel,
  560.                        &openSpoolWatchedIcon,
  561.                        NULL,
  562.                        MN_ThreadWatchO.width, MN_ThreadWatchO.height,
  563.                        MN_ThreadWatchO.mono_bits, MN_ThreadWatchO.color_bits,
  564.                        MN_ThreadWatchO.mask_bits, FALSE);
  565.  
  566.     if (!closedSpoolWatchedIcon.pixmap)
  567.         fe_NewMakeIcon(widget,
  568.                        fg_pixel,
  569.                        bg_pixel,
  570.                        &closedSpoolWatchedIcon,
  571.                        NULL,
  572.                        MN_ThreadWatch.width, MN_ThreadWatch.height,
  573.                        MN_ThreadWatch.mono_bits, MN_ThreadWatch.color_bits,
  574.                        MN_ThreadWatch.mask_bits, FALSE);
  575.  
  576.     if (!openSpoolNewIcon.pixmap)
  577.         fe_NewMakeIcon(widget,
  578.                        fg_pixel,
  579.                        bg_pixel,
  580.                        &openSpoolNewIcon,
  581.                        NULL,
  582.                        MN_ThreadNew/*O*/.width, MN_ThreadNew/*O*/.height,
  583.                        MN_ThreadNew/*O*/.mono_bits, MN_ThreadNew/*O*/.color_bits,
  584.                        MN_ThreadNew/*O*/.mask_bits, FALSE);
  585.  
  586.     if (!closedSpoolNewIcon.pixmap)
  587.         fe_NewMakeIcon(widget,
  588.                        fg_pixel,
  589.                        bg_pixel,
  590.                        &closedSpoolNewIcon,
  591.                        NULL,
  592.                        MN_ThreadNew.width, MN_ThreadNew.height,
  593.                        MN_ThreadNew.mono_bits, MN_ThreadNew.color_bits,
  594.                        MN_ThreadNew.mask_bits, FALSE);
  595.  
  596.     if (!openSpoolIcon.pixmap)
  597.         fe_NewMakeIcon(widget,
  598.                        fg_pixel,
  599.                        bg_pixel,
  600.                        &openSpoolIcon,
  601.                        NULL,
  602.                        MN_ThreadO.width, MN_ThreadO.height,
  603.                        MN_ThreadO.mono_bits, MN_ThreadO.color_bits,
  604.                        MN_ThreadO.mask_bits, FALSE);
  605.  
  606.     if (!closedSpoolIcon.pixmap)
  607.         fe_NewMakeIcon(widget,
  608.                        fg_pixel,
  609.                        bg_pixel,
  610.                        &closedSpoolIcon,
  611.                        NULL,
  612.                        MN_Thread.width, MN_Thread.height,
  613.                        MN_Thread.mono_bits, MN_Thread.color_bits,
  614.                        MN_Thread.mask_bits, FALSE);
  615.  
  616.     if (!deletedIcon.pixmap)
  617.         fe_NewMakeIcon(widget,
  618.                        fg_pixel,
  619.                        bg_pixel,
  620.                        &deletedIcon,
  621.                        NULL,
  622.                        MN_Delete.width, MN_Delete.height,
  623.                        MN_Delete.mono_bits, MN_Delete.color_bits,
  624.                        MN_Delete.mask_bits, FALSE);
  625. }
  626.  
  627. #if HANDLE_CMD_QUEUE
  628.  
  629. /* It looks like a selectInvalid here
  630.  */
  631. void XFE_ThreadView::processCmdQueue()
  632. {
  633.     int count =0;
  634.     int *Arr = NULL;
  635.  
  636.     if (m_deletedCount && m_deleted) {
  637.         count = m_deletedCount;
  638.         Arr = m_deleted;
  639.     }/* else if */
  640.  
  641. #if defined(DEBUG_tao)
  642.     printf("\n->XFE_ThreadView::processCmdQueue, count=%d", count);
  643.     if (count > 1)
  644.         XP_ASSERT(0);
  645. #endif
  646.  
  647.     int lastInd = count?Arr[count-1]:-1;
  648.     for (int i=count-2; i >= 0; i--)
  649.         if (Arr[i] < lastInd)
  650.             lastInd--;
  651.  
  652.     int nLines = MSG_GetNumLines(m_pane);
  653.     if (lastInd >= nLines)
  654.         /* the worst case is -1 ;
  655.          * which we do deal with it in paneChanged already!
  656.          */
  657.         lastInd = nLines-1;
  658.  
  659.     if (lastInd >= 0 && 
  660.         m_lastLoadedInd != MSG_VIEWINDEXNONE)
  661.         showMessage(lastInd);
  662. #if defined(DEBUG_tao)
  663.     else
  664.         printf("\n->XFE_ThreadView::processCmdQueue,m_lastLoadedInd=%d,",
  665.                m_lastLoadedInd);    
  666. #endif
  667.  
  668.     /* final step
  669.      */
  670.  
  671.     /* reset 
  672.      */
  673.     XP_FREEIF(m_selected);
  674.     m_selectedCount = 0;
  675.     XP_FREEIF(m_deleted);
  676.     m_deletedCount = 0;
  677.     XP_FREEIF(m_collapsed);
  678.     m_collapsedCount = 0;
  679. }
  680.  
  681. #endif /* HANDLE_CMD_QUEUE */
  682.  
  683. #if defined(DEL_5_0)
  684. void
  685. XFE_ThreadView::listChangeStarting(XP_Bool /* asynchronous */, 
  686.                                    MSG_NOTIFY_CODE notify, 
  687.                                    MSG_ViewIndex /* where */, 
  688.                                    int32 /* num */)
  689. {
  690.     int listChangeDepth = m_outliner->getListChangeDepth()-1;
  691. #if defined(DEBUG_tao)
  692.     printf("\n>>XFE_ThreadView::listChangeStarting, depth=%d, m_lastLoadedInd=%d", 
  693.            listChangeDepth, m_lastLoadedInd);
  694. #endif
  695.  
  696.     if (notify == MSG_NotifyScramble ||
  697.         notify == MSG_NotifyAll) {
  698.         m_lastLoadedInd = MSG_VIEWINDEXNONE;
  699.     }/* if */
  700. }
  701. #endif /* DEL_5_0 */
  702.  
  703. void
  704. XFE_ThreadView::listChangeFinished(XP_Bool /* asynchronous */, 
  705.                                    MSG_NOTIFY_CODE notify, 
  706.                                    MSG_ViewIndex where, 
  707.                                    int32 num)
  708. {
  709.     int listChangeDepth = m_outliner->getListChangeDepth()-1;
  710. #if defined(DEBUG_tao)
  711.     printf("\n>>XFE_ThreadView::listChangeFinished, depth=%d, m_lastLoadedInd=%d", 
  712.            listChangeDepth, m_lastLoadedInd);
  713. #endif
  714.  
  715. #if defined(DEL_5_0)
  716.     if (notify == MSG_NotifyScramble ||
  717.         notify == MSG_NotifyAll) {
  718.         m_lastLoadedInd = MSG_GetMessageIndexForKey(m_pane, 
  719.                                                     m_lastLoadedKey,
  720.                                                     False);
  721.     }/* if */
  722.     else if (notify == MSG_NotifyChanged) {
  723.         m_lineChanged = where;
  724.         return;
  725.     }/* if */
  726.     else if (notify == MSG_NotifyInsertOrDelete &&
  727.              m_lastLoadedInd != MSG_VIEWINDEXNONE) {
  728.         /* there was a msg loaded
  729.          */
  730.         if (num < 0) {
  731.             /* 1. collapsing ??
  732.              */
  733.             if ((m_lineChanged != MSG_VIEWINDEXNONE) &&
  734.                 (m_lineChanged == (where -1)) && /* essential */
  735.                 (listChangeDepth == 0)) { /* must be collapsing */
  736.                 /* collapsed
  737.                  */
  738.                 if ((m_lastLoadedInd >= where) && 
  739.                     (m_lastLoadedInd < (where-num))) { 
  740.                     /* one of the "reply" is being hidden
  741.                      * selection would go to thread leader; 
  742.                      * thus needs reload right away
  743.                      */
  744.                     /* load the thread leader: where -1*/
  745.                     if (!m_deletedCount && !m_deleted) {
  746.                         m_deleted = (int *) XP_CALLOC(1, sizeof(int));
  747.                         m_deleted[m_deletedCount++] = where-1;        
  748.                         processCmdQueue();
  749.                     }/* if */
  750.                     else
  751.                         XP_ASSERT(0);
  752.                 }/* if collapsed */
  753.                 else {
  754. #if defined(DEBUG_tao)
  755.                     printf("\n***XFE_ThreadView::listChangeFinished, collapsing not selected\n");
  756. #endif /* DEBUG_tao */
  757.                     m_lastLoadedInd += num; /* re-adjust */
  758.                 }/* else */
  759.             }/* collapsed */
  760.             else if (where == m_lastLoadedInd) {
  761.                 /* the selected one is gone
  762.                  */
  763.                 if (!m_deletedCount && !m_deleted) {
  764.                     m_deleted = (int *) XP_CALLOC(1, sizeof(int));
  765.                     m_deleted[m_deletedCount++] = where;        
  766.                     processCmdQueue();
  767.                 }/* if */
  768.                 else
  769.                     XP_ASSERT(0);
  770.             }/* where == m_lastLoadedInd */
  771.             else if (where <= m_lastLoadedInd)
  772.                 m_lastLoadedInd += num; /* re-adjust */
  773.         }/* num < 0 */
  774.         else if (num == 0) {
  775.             /* SPECIAL case: the header got deleted
  776.              */
  777.  
  778.             /* we do not care deletion on non-focusing line
  779.              */
  780.             if (m_lastLoadedInd == where) {
  781.                 /* deleted
  782.                  */
  783.                 if (!m_deletedCount && !m_deleted) {
  784.                     m_deleted = (int *) XP_CALLOC(1, sizeof(int));
  785.                     m_deleted[m_deletedCount++] = where;        
  786.                     processCmdQueue();
  787.                 }/* if */
  788.                 else
  789.                     XP_ASSERT(0);
  790.  
  791. #if defined(DEBUG_tao)
  792.                 printf("\n**>SPECIAL case:listChangeFinished=%d, m_deletedCount=%d\n", 
  793.                        where, m_deletedCount);
  794. #endif        
  795.             }/* m_lastLoadedInd == where */
  796.         }/* if num == 0 */
  797.         else if (num > 0 && where <= m_lastLoadedInd)
  798.             m_lastLoadedInd += num;
  799.  
  800.     }/* notify == MSG_NotifyInsertOrDelete */
  801. #if defined(DEBUG_tao)
  802.     printf("\n<<XFE_ThreadView::listChangeFinished, m_lastLoadedInd=%d", 
  803.            m_lastLoadedInd);
  804. #endif
  805.  
  806.  
  807. #else
  808.     if (notify == MSG_NotifyChanged) {
  809.         m_lineChanged = where;
  810.         return;
  811.     }/* if */
  812.     else if (notify == MSG_NotifyInsertOrDelete && 
  813.              num <= 0) {
  814.  
  815.         if (num == 0) {
  816.             /* SPECIAL case: the header got deleted
  817.              */
  818.  
  819.             /* we do not care deletion on non-focusing line
  820.              */
  821.             if (m_lastLoadedInd != where)
  822.                 return;
  823.  
  824.             /* deleted
  825.              */
  826.             if (m_deletedCount && m_deleted)
  827.                 m_deleted = (int *) XP_REALLOC(m_deleted, 
  828.                                                (m_deletedCount+1)*sizeof(int));
  829.             else
  830.                 m_deleted = (int *) XP_CALLOC(1, sizeof(int));
  831.             m_deleted[m_deletedCount++] = where;        
  832. #if defined(DEBUG_tao)
  833.             printf("\n**>SPECIAL case:listChangeFinished=%d, m_deletedCount=%d\n", 
  834.                    where, m_deletedCount);
  835. #endif        
  836.             
  837.         }/* if */
  838.         else if ((m_lineChanged != MSG_VIEWINDEXNONE) &&
  839.             (m_lineChanged == (where -1)) && /* essential */
  840.             (listChangeDepth == 0)) { /* must be collapsing */
  841.             /* collapsed
  842.              */
  843.             if ((m_lastLoadedInd >= where) && 
  844.                 (m_lastLoadedInd < (where-num))) { 
  845.                 /* one of the "reply" is being hidden
  846.                  * selection would go to thread leader; 
  847.                  * thus needs reload right away
  848.                  */
  849.                 if (!m_deletedCount && !m_deleted) {
  850.                     m_deleted = (int *) XP_CALLOC(1, sizeof(int));
  851.                     m_deleted[m_deletedCount++] = where-1;        
  852.                     processCmdQueue();
  853.                 }/* if */
  854.             }/* if */
  855.         }/* if */
  856.         else if (num == -1){
  857.             /* we do not care deletion on non-focusing line
  858.              */
  859.             if (m_lastLoadedInd != where)
  860.                 return;
  861.  
  862.             /* deleted
  863.              */
  864.             if (m_deletedCount && m_deleted)
  865.                 m_deleted = (int *) XP_REALLOC(m_deleted, 
  866.                                                (m_deletedCount+1)*sizeof(int));
  867.             else
  868.                 m_deleted = (int *) XP_CALLOC(1, sizeof(int));
  869.             m_deleted[m_deletedCount++] = where;        
  870. #if defined(DEBUG_tao)
  871.             printf("\n-->listChangeFinished=%d, m_deletedCount=%d\n", 
  872.                    where, m_deletedCount);
  873. #endif        
  874.         }/* else if num == -1 */
  875.     }/* else if notify == MSG_NotifyInsertOrDelete && num < 0*/
  876. #endif /* DEL_5_0 */
  877.  
  878.     m_lineChanged = MSG_VIEWINDEXNONE;
  879. }/* XFE_ThreadView::listChangeFinished() */
  880.  
  881. void
  882. XFE_ThreadView::paneChanged(XP_Bool asynchronous,
  883.                             MSG_PANE_CHANGED_NOTIFY_CODE code,
  884.                             int32 value)
  885. {
  886. #if defined(DEBUG_tao)
  887.     printf("\n  XFE_ThreadView::paneChanged, pane=0x%x, asynchronous=%d, code=%d, value=%d",
  888.            m_pane, asynchronous, code, value);
  889. #endif
  890.  
  891.   switch (code)
  892.     {
  893.     case MSG_PaneNotifyFolderDeleted:
  894.         {
  895.             /* bug 95564: check folderInfo before closing
  896.              */
  897.             MSG_FolderInfo *deleted = (MSG_FolderInfo *) value;
  898.             if (m_folderInfo == deleted) {
  899.                 /* test frame type
  900.                  */
  901.                 XFE_Frame *frame = (XFE_Frame*)m_toplevel;
  902.                 if (frame &&
  903.                     FRAME_MAILNEWS_THREAD == frame->getType()) {
  904.                     /* standalone frame
  905.                      */    
  906.                     if (!m_frameDeleted) {
  907.                         frame->delete_response();
  908.                         m_frameDeleted = True;
  909.                     }/* if */
  910.                 }/* if */
  911.             }/* if m_folderInfo == deleted */
  912. #if defined(DEBUG_tao)
  913.             else
  914.                 printf("\n---Wrong folder IGNORing MSG_PaneNotifyFolderDeleted\n");
  915. #endif
  916.         }
  917.         /* shall we update banner or simply return?
  918.          */
  919.         return;
  920.  
  921.     case MSG_PaneNotifyCopyFinished:
  922. #if defined(DEBUG_tao)
  923.         printf("\n++XFE_ThreadView, MSG_PaneNotifyCopyFinished++\n");
  924.         /* It happens in loading mails.
  925.          * XP_ASSERT(0);
  926.          */ 
  927. #endif
  928.         break;
  929.  
  930.     case MSG_PaneNotifyMessageLoaded:
  931. #if defined(DEBUG_tao)
  932.         printf("\n++XFE_ThreadView, MSG_PaneNotifyMessageLoaded++\n");
  933.         XP_ASSERT(0);
  934. #endif
  935.         break;
  936.  
  937.     case MSG_PaneNotifyLastMessageDeleted:
  938.         /* clear msgPane
  939.          */
  940.         showMessage(-1);
  941.         break;
  942.  
  943.     case MSG_PaneNotifyMessageDeleted:
  944.         {
  945.         // If we delete a message from the threadview, and
  946.         // there's currently a message view showing that message,
  947.         // we need to tell the msg view so it can pop down:
  948.         XFE_MozillaApp::theApp()->notifyInterested(msgWasDeleted, (void*)value);
  949.  
  950. #if HANDLE_CMD_QUEUE
  951.  
  952.         MessageKey id = (MessageKey) value;
  953.         MSG_ViewIndex index = MSG_GetMessageIndexForKey(m_pane, 
  954.                                                         id,
  955.                                                         False);
  956. #if defined(DEBUG_tao)
  957.         printf("\n MSG_PaneNotifyMessageDeleted,index=%d", index);
  958. #endif
  959. #endif /* HANDLE_CMD_QUEUE */
  960.  
  961.         }
  962.         break;
  963.  
  964.     case MSG_PaneNotifyFolderLoadedSync:
  965.     case MSG_PaneNotifyFolderLoaded:
  966.     {
  967.         D(printf ("Inside pane changed -- folder loaded\n");)
  968. #if defined(DEBUG_tao)
  969.         if (code == MSG_PaneNotifyFolderLoadedSync)
  970.             printf("\n**XFE_ThreadView::paneChanged: code == MSG_PaneNotifyFolderLoadedSync \n");
  971. #endif
  972.         if (m_nLoadingFolders > 0) {
  973.             /* release the block
  974.              */
  975.             m_outliner->setBlockSel(False);
  976.  
  977.             m_nLoadingFolders--;
  978.         }/* if */
  979.         
  980.         /* Call this after folder is loaded
  981.          */
  982.         if ((code == MSG_PaneNotifyFolderLoaded) &&
  983.             m_getNewMsg) {
  984.  
  985.             /* Do it for movemail/pop3 only
  986.              */ 
  987.             if (fe_globalPrefs.mail_server_type != MAIL_SERVER_IMAP)
  988.                 getNewMail();
  989.  
  990.             /* reset
  991.              */
  992.             m_getNewMsg = False;
  993.         }/* if */
  994.  
  995.         /* select first msg
  996.          */
  997.         if (m_commandPending == noPendingCommand
  998.             && m_outliner->getTotalLines() > 0)
  999.             {
  1000.                 m_commandPending = selectByIndex;
  1001.                 m_pendingSelectionIndex = 0;
  1002.             }
  1003.  
  1004.         /* we only actually handle the command here 
  1005.          * if the folder was loaded synchronously. 
  1006.          */
  1007.         if (code == MSG_PaneNotifyFolderLoadedSync)
  1008.             handlePendingCommand();
  1009.  
  1010.         XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::MNChromeNeedsUpdating);
  1011.  
  1012.         notifyInterested(XFE_MNView::bannerNeedsUpdating, (void*)code);
  1013.  
  1014.         XP_Bool invalidate_needed = False;
  1015.         if (MSG_GetToggleStatus(m_pane, MSG_SortByThread, NULL, 0) == MSG_Checked)
  1016.             {
  1017.                 invalidate_needed = m_outliner->getDescendantSelectAllowed() == False;
  1018.                 m_outliner->setDescendantSelectAllowed( True );
  1019.                 m_outliner->setSortColumn(-1, OUTLINER_SortAscending);
  1020.             }
  1021.         else
  1022.             {
  1023.                 invalidate_needed = m_outliner->getDescendantSelectAllowed() == True;
  1024.                 m_outliner->setDescendantSelectAllowed( False );
  1025.             }
  1026.  
  1027.         if (invalidate_needed)
  1028.             m_outliner->invalidate();
  1029.     }
  1030.         break;
  1031.  
  1032.     default:
  1033.         break;
  1034.     }
  1035.  
  1036.     // This can result in flickering of the banner, but if we don't call it,
  1037.     // the number of unread and total messages isn't updated correctly
  1038.     XFE_MNListView::paneChanged(asynchronous, code, value);
  1039. }
  1040.  
  1041. void
  1042. XFE_ThreadView::loadFolder(MSG_FolderInfo *folderInfo)
  1043. {
  1044.   MSG_FolderLine folderLine;
  1045.   char *newsgroup_format = XP_GetString(XFE_WINDOW_TITLE_NEWSGROUP);
  1046.   char *folder_format = XP_GetString(XFE_WINDOW_TITLE_FOLDER);
  1047.   char *window_title;
  1048.   int window_title_length;
  1049.  
  1050.   // only need to do everything below here if the folder being
  1051.   // loaded is different than what's currently displayed.
  1052.   if (m_folderInfo != folderInfo) {
  1053.       
  1054.       // must be valid.
  1055.       XP_ASSERT(folderInfo);
  1056.       
  1057.       // clear the currently display message, since we're in a different folder now.
  1058.       showMessage(-1);
  1059.       updateExpandoFlippyText(-1);
  1060.  
  1061.       m_outliner->deselectAllItems();
  1062.       
  1063.       MSG_GetFolderLineById(XFE_MNView::getMaster(), folderInfo, &folderLine);
  1064.  
  1065. #if defined(USE_MOTIF_DND)
  1066.       m_outliner->enableDragDrop(this,
  1067.                                  NULL, /* no dropping -- of anything but outliner columns. */
  1068.                                  XFE_ThreadView::getDragTargets,
  1069.                                  XFE_ThreadView::getDragIconData,
  1070.                                  XFE_ThreadView::dragConvert);
  1071. #endif /* USE_MOTIF_DND */
  1072.       
  1073.       if (folderLine.flags & MSG_FOLDER_FLAG_NEWSGROUP)
  1074.           {
  1075.               // it's a newsgroup
  1076.               window_title_length = strlen(newsgroup_format) - 2 /* %s */ + strlen(folderLine.name) + 1;
  1077.               
  1078.               window_title = (char*)XP_CALLOC(sizeof(char), window_title_length);
  1079.               
  1080.               sprintf (window_title, newsgroup_format, folderLine.name);
  1081.               
  1082.               m_displayingNewsgroup = TRUE;
  1083.               m_displayingDraft = FALSE;
  1084.               
  1085. #if !defined(USE_MOTIF_DND)
  1086.               m_outliner->setDragType( FE_DND_NEWS_MESSAGE, &newsPostIcon,
  1087.                                        this, (fe_dnd_SourceDropFunc)&XFE_ThreadView::source_drop_func);
  1088. #endif /* USE_MOTIF_DND */
  1089.               
  1090.           }
  1091.       else 
  1092.           {
  1093.               window_title_length = strlen(folder_format) - 2 /* %s */ + strlen(folderLine.name) + 1;
  1094.               
  1095.               window_title = (char*)XP_CALLOC(sizeof(char), window_title_length);
  1096.               
  1097.               sprintf (window_title, folder_format, folderLine.name);
  1098.                       
  1099.  
  1100.               if (folderLine.flags & MSG_FOLDER_FLAG_DRAFTS)
  1101.                   {
  1102.                       // it's the draft folder
  1103.                       m_displayingDraft = TRUE;
  1104.                       m_displayingNewsgroup = FALSE;
  1105. #if !defined(USE_MOTIF_DND)
  1106.  
  1107.                       m_outliner->setDragType(FE_DND_MAIL_MESSAGE, &mailMessageUnreadIcon,
  1108.                                               this, 
  1109.                                               (fe_dnd_SourceDropFunc)&XFE_ThreadView::source_drop_func);
  1110. #endif /* USE_MOTIF_DND */
  1111.                   }
  1112.               else
  1113.                   {
  1114.                       // it's a normal mail folder
  1115.                       m_displayingNewsgroup = FALSE;
  1116.                       m_displayingDraft = FALSE;
  1117.                       
  1118. #if !defined(USE_MOTIF_DND)
  1119.                       m_outliner->setDragType(FE_DND_MAIL_MESSAGE, &mailMessageUnreadIcon, 
  1120.                                               this,
  1121.                                               (fe_dnd_SourceDropFunc)&XFE_ThreadView::source_drop_func);
  1122. #endif /* USE_MOTIF_DND */
  1123.                   }
  1124.           }
  1125.       
  1126.       //  getContainer()->setTitle(window_title);
  1127.       
  1128.       XP_FREE(window_title);
  1129.       
  1130.       D(printf("Loading folder into ThreadView\n");)
  1131.           
  1132.       /* if it doesn't have categories, we can load it directly
  1133.          into the threadview's pane. */
  1134.       m_folderInfo = folderInfo;
  1135.               
  1136.       /* keep track of on loading folders
  1137.        */
  1138.       if (m_nLoadingFolders == 0) {
  1139.           m_nLoadingFolders++; // FYI
  1140.  
  1141.           /* block selection
  1142.            */
  1143.           m_outliner->setBlockSel(True);
  1144.       }/* if */ 
  1145.       else
  1146.           XP_ASSERT(0);
  1147.  
  1148.       MSG_LoadFolder(m_pane, m_folderInfo);
  1149.  
  1150.  
  1151.       XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::MNChromeNeedsUpdating);
  1152.       /* either open or close the message view, depending on the folder prefs */
  1153.       {
  1154.           int32 new_folder_prefs = MSG_GetFolderPrefFlags(m_folderInfo);
  1155.           
  1156.           if (new_folder_prefs & MSG_FOLDER_PREF_FEVALID)
  1157.               {
  1158.                   if (new_folder_prefs & MSG_FOLDER_PREF_ONEPANE)
  1159.                       {
  1160.                           if (m_msgview->isShown())
  1161.                               {
  1162.                                   toggleMsgExpansion();
  1163.                               }
  1164.                       }
  1165.                   else
  1166.                       {
  1167.                           if (!m_msgview->isShown())
  1168.                               {
  1169.                                   toggleMsgExpansion();
  1170.                               }
  1171.                       }
  1172.               }
  1173.       }
  1174.   }/* if  diff folder */
  1175.   else  /* if  the same loaded folder, we need to invoke handlePendingCommand */
  1176.     handlePendingCommand();
  1177. }
  1178.  
  1179. MSG_FolderInfo *
  1180. XFE_ThreadView::getFolderInfo()
  1181. {
  1182.   return m_folderInfo;
  1183. }
  1184.  
  1185. void
  1186. XFE_ThreadView::updateExpandoFlippyText(int row)
  1187. {
  1188.     char *subjectStr;
  1189.     XmString subject;
  1190.     XmString oldsubject = 0;
  1191.     char *oldsubjectStr = NULL;
  1192.     XP_Bool needsChange = TRUE;
  1193.  
  1194. #if defined(DEBUG_tao)
  1195.     printf("\nXFE_ThreadView::updateExpandoFlippyText(row=%d)\n",row);
  1196. #endif
  1197.     if (row == -1)
  1198.         {
  1199.             subjectStr = "";
  1200.         }
  1201.     else
  1202.         {
  1203.             acquireLineData(row);
  1204.             
  1205.             subjectStr = getColumnText(OUTLINER_COLUMN_SUBJECT);
  1206.         }      
  1207.     
  1208.     XtVaGetValues (m_arrowlabel, 
  1209.                    XmNlabelString, &oldsubject,
  1210.                    NULL);
  1211.     
  1212.     if (XmStringGetLtoR(oldsubject, XmFONTLIST_DEFAULT_TAG, &oldsubjectStr))
  1213.         if (oldsubjectStr && !strcmp(oldsubjectStr, subjectStr)) 
  1214.             {
  1215.                 needsChange = FALSE;
  1216.                 if (oldsubjectStr) XtFree(oldsubjectStr);
  1217.             }
  1218.     
  1219.     if (needsChange) 
  1220.         {
  1221.             subject = XmStringCreate (subjectStr, XmFONTLIST_DEFAULT_TAG);
  1222.             
  1223.             XtVaSetValues (m_arrowlabel, 
  1224.                            XmNlabelString, subject, 
  1225.                            NULL);
  1226.             
  1227.             XmStringFree (subject);
  1228.         }
  1229.     
  1230.     XmStringFree (oldsubject);
  1231.     XFlush(XtDisplay(m_arrowlabel));
  1232. }
  1233.  
  1234. //
  1235. // show a message at a particular row in the thread's outliner.
  1236. // sending -1 to this function will clear the label and the message
  1237. // area.
  1238. //
  1239. void
  1240. XFE_ThreadView::showMessage(int row)
  1241. {
  1242.     /* sometimes this can get called before we've loaded a folder. */
  1243.     if (!m_folderInfo)
  1244.         return;
  1245.  
  1246.     /*
  1247.     ** if the message area is expanded we just load the message, since
  1248.     ** we will turn around and call the makeVisible/selectItemExclusive/etc
  1249.     ** in our newMessageLoading method.
  1250.     ** If the message area isn't expanded, we handle it here.
  1251.     */
  1252.     if (row > -1) {
  1253.         m_lastLoadedInd = (MSG_ViewIndex) row;
  1254.         m_lastLoadedKey = MSG_GetMessageKey(m_pane, row);
  1255. #if defined(DEBUG_tao)
  1256.         printf("\nXFE_ThreadView::showMessage m_lastLoadedInd=%d\n", 
  1257.                m_lastLoadedInd);
  1258. #endif        
  1259.     }/* if */
  1260.  
  1261.     if (m_msgExpanded)
  1262.         {
  1263.             m_msgview->loadMessage(m_folderInfo,
  1264.                                    (row == -1 ? MSG_MESSAGEKEYNONE : MSG_GetMessageKey(m_pane, row)));
  1265.         }
  1266.     else
  1267.         {
  1268.             if (row != -1)
  1269.                 {
  1270.                     m_outliner->makeVisible(row);
  1271.                     m_outliner->selectItemExclusive(row);
  1272.                 }
  1273.         }
  1274.     updateExpandoFlippyText(row);
  1275. }
  1276.  
  1277. char *
  1278. XFE_ThreadView::commandToString(CommandType cmd, void * calldata, XFE_CommandInfo* info)
  1279. {
  1280. #define IS_CMD(command) cmd == (command)  
  1281.     if (IS_CMD(xfeCmdToggleMessageExpansion))
  1282.         {
  1283.             if (m_msgview->isShown())
  1284.                 return stringFromResource("hideMsgAreaCmdString");
  1285.             else
  1286.                 return stringFromResource("showMsgAreaCmdString");
  1287.         }
  1288.     else if (IS_CMD(xfeCmdDeleteMessage) || IS_CMD(xfeCmdCancelMessages)) {
  1289.         if (isDisplayingNews())
  1290.             return XP_GetString(MK_MSG_CANCEL_MESSAGE);
  1291.         else
  1292.             return XP_GetString(MK_MSG_DELETE_SEL_MSGS);            
  1293.     }
  1294.     else if ( calldata &&
  1295.               (IS_CMD(xfeCmdReplyToSender)
  1296.                || IS_CMD(xfeCmdReplyToAll)
  1297.                || IS_CMD(xfeCmdReplyToNewsgroup)
  1298.                || IS_CMD(xfeCmdReplyToSenderAndNewsgroup) ) )
  1299.     {
  1300.         // if calldata is non-null for a Reply button,
  1301.         // that's a signal not to change the
  1302.         // widget name in the resources file:
  1303.         return 0;
  1304.     }
  1305.  
  1306.     else
  1307.         return XFE_MNListView::commandToString(cmd, calldata, info);
  1308.   
  1309. #undef IS_CMD
  1310. }
  1311.  
  1312. Boolean
  1313. XFE_ThreadView::isCommandSelected(CommandType cmd, void *calldata, XFE_CommandInfo*)
  1314. {
  1315. #define IS_CMD(command) cmd == (command)
  1316.   if (IS_CMD(xfeCmdShowAllHeaders)
  1317.        || IS_CMD(xfeCmdShowNormalHeaders)
  1318.        || IS_CMD(xfeCmdShowBriefHeaders)
  1319.        || IS_CMD(xfeCmdWrapLongLines)
  1320.        || IS_CMD(xfeCmdViewAttachmentsInline)
  1321.        || IS_CMD(xfeCmdEditMessage)
  1322.        || IS_CMD(xfeCmdOpenSelected)
  1323.        || IS_CMD(xfeCmdUpdateMessageCount)
  1324.        || IS_CMD(xfeCmdViewAttachmentsAsLinks))
  1325.     {
  1326.       return m_msgExpanded && m_msgview->isCommandSelected(cmd);
  1327.     }
  1328.   else if (IS_CMD(xfeCmdPrintSetup)
  1329.            || IS_CMD(xfeCmdPrintPreview))
  1330.       return True;
  1331.   else if (IS_CMD(xfeCmdSortAscending))
  1332.   {
  1333.       return ( MSG_GetToggleStatus( m_pane, MSG_SortBackward, NULL, 0 )
  1334.                != MSG_Checked );
  1335.   }
  1336.   else if (IS_CMD(xfeCmdSortDescending))
  1337.   {
  1338.       return ( MSG_GetToggleStatus( m_pane, MSG_SortBackward, NULL, 0 )
  1339.                == MSG_Checked );
  1340.   }
  1341.   else
  1342.     return XFE_MNListView::isCommandSelected(cmd, calldata);
  1343. #undef IS_CMD
  1344. }
  1345.  
  1346. Boolean
  1347. XFE_ThreadView::isCommandEnabled(CommandType cmd, void *calldata, XFE_CommandInfo* info)
  1348. {
  1349. #define IS_CMD(command) cmd == (command)
  1350.  
  1351.     if (IS_CMD(xfeCmdDeleteMessage)) {
  1352.         /* Given a flag or set of flags, returns the number of folders that have
  1353.          *  that flag set.  If the result pointer is not NULL, fills it in with the
  1354.          *  list of folders (providing up to resultsize entries).  
  1355.          */
  1356.         int32 resultsize = MSG_GetFoldersWithFlag(XFE_MNView::getMaster(),
  1357.                                                   MSG_FOLDER_FLAG_TRASH,
  1358.                                                   NULL,
  1359.                                                   0);
  1360.         if (resultsize == 0)
  1361.             return False;
  1362.     }/* IS_CMD(xfeCmdDeleteMessage */
  1363.  
  1364.     const int *selected;
  1365.     int count;
  1366.     m_outliner->getSelection(&selected, &count);
  1367.  
  1368.     // DeleteMessage stands for CancelMessage in the ThreadView,
  1369.     // so intercept it early:
  1370.     if ( (IS_CMD(xfeCmdDeleteMessage) || IS_CMD(xfeCmdCancelMessages))
  1371.               && isDisplayingNews() )
  1372.     {
  1373.       XP_Bool selectable = False;
  1374.       MSG_CommandStatus(m_pane, MSG_CancelMessage,
  1375.                         /* just need some integer pointer here...*/
  1376.                         (MSG_ViewIndex*)selected, count,
  1377.                         &selectable, NULL, NULL, NULL);
  1378.       return selectable;
  1379.     }
  1380.  
  1381.     // Check if selectThread should be enabled or not...
  1382.     if ( IS_CMD(xfeCmdSelectThread))
  1383.     {
  1384.         Boolean status =
  1385.                 MSG_GetToggleStatus(m_pane, MSG_SortByThread, NULL, 0)==MSG_Checked;
  1386.         return ((count > 0) && status);
  1387.     }
  1388.     if ( !m_displayingNewsgroup && IS_CMD(xfeCmdEditConfiguration) )
  1389.     {
  1390.         // Manage Mail Account
  1391.         return True;
  1392.     }
  1393.     if ( m_displayingNewsgroup && IS_CMD(xfeCmdModerateDiscussion) )
  1394.     {
  1395.         // Moderate Newsgroup Discussion
  1396.         return True;
  1397.     }
  1398.      if (IS_CMD(xfeCmdUndo)
  1399.          || IS_CMD(xfeCmdRedo)) {
  1400.          XP_Bool selectable = False;
  1401.          MSG_CommandType msg_cmd = commandToMsgCmd(cmd);
  1402.          MSG_CommandStatus(m_pane, msg_cmd,
  1403.                            /* just need some integer pointer here...*/
  1404.                            (MSG_ViewIndex*)selected, count,
  1405.                            &selectable, NULL, NULL, NULL);
  1406.  
  1407. #if defined(DEBUG_tao)
  1408.          if (IS_CMD(xfeCmdUndo))
  1409.              printf("\n XFE_ThreadView, MSG_CommandStatus:: m_pane=%x, xfeCmdUndo=%d", m_pane, selectable);
  1410.          else if (IS_CMD(xfeCmdRedo))
  1411.              printf("\n XFE_ThreadView, MSG_CommandStatus:: m_pane=%x, xfeCmdRedo=%d", m_pane, selectable);
  1412. #endif
  1413.        return selectable;
  1414.      }
  1415.  
  1416.  
  1417.   MSG_MotionType nav_cmd;
  1418.  
  1419.   nav_cmd = commandToMsgNav(cmd);
  1420.  
  1421.   if ((nav_cmd != (MSG_MotionType)~0)&&
  1422.       (!(IS_CMD(xfeCmdBack)||IS_CMD(xfeCmdForward))))
  1423.     {
  1424.       XP_Bool selectable = FALSE;
  1425.       if (count == 1)
  1426.           MSG_NavigateStatus(m_pane, nav_cmd, selected[0],
  1427.                              &selectable, NULL);
  1428.  
  1429.       return selectable;
  1430.     }
  1431.  
  1432.   else if (IS_CMD(xfeCmdToggleMessageExpansion))
  1433.       {
  1434.           return True;
  1435.       }
  1436.   else if (IS_CMD(xfeCmdGetNextNNewMsgs))
  1437.       {
  1438.           return m_displayingNewsgroup;
  1439.       }
  1440.   else if (IS_CMD(xfeCmdEditPreferences))
  1441.     {
  1442.       return True;
  1443.     }
  1444.   //  Always available even if nothing is selected:
  1445.   else if (IS_CMD(xfeCmdComposeArticle)
  1446.            || IS_CMD(xfeCmdComposeArticleHTML)
  1447.            || IS_CMD(xfeCmdComposeArticlePlain)
  1448.            || IS_CMD(xfeCmdPrintSetup)
  1449.            || IS_CMD(xfeCmdPrintPreview)
  1450.            || IS_CMD(xfeCmdUpdateMessageCount))
  1451.     {
  1452.       return True;
  1453.     }
  1454.  
  1455.   // the move and copy commands are available if there are messages selected.
  1456.   else if (IS_CMD(xfeCmdMoveMessage)
  1457.        || IS_CMD(xfeCmdCopyMessage)
  1458.        || IS_CMD(xfeCmdSetPriorityHighest)
  1459.        || IS_CMD(xfeCmdSetPriorityHigh)
  1460.        || IS_CMD(xfeCmdSetPriorityNormal)
  1461.        || IS_CMD(xfeCmdSetPriorityLow)
  1462.        || IS_CMD(xfeCmdSetPriorityLowest)
  1463.        || IS_CMD(xfeCmdSetPriorityNone)
  1464.        || IS_CMD(xfeCmdEditMessage)
  1465.        || IS_CMD(xfeCmdOpenSelected))
  1466.     {
  1467.       return (count > 0);
  1468.     }
  1469.   // the sort commands are always available, if there are messages
  1470.   else if (IS_CMD(xfeCmdSortBySender)
  1471.            || IS_CMD(xfeCmdSortByDate)
  1472.            || IS_CMD(xfeCmdSortBySubject)
  1473.            || IS_CMD(xfeCmdSortByPriority)
  1474.            || IS_CMD(xfeCmdSortByThread)
  1475.            || IS_CMD(xfeCmdSortByMessageNumber)
  1476.            || IS_CMD(xfeCmdSortBySize)
  1477.            || IS_CMD(xfeCmdSortByFlag)
  1478.            || IS_CMD(xfeCmdSortByStatus)
  1479.            || IS_CMD(xfeCmdSortByUnread)
  1480.            || IS_CMD(xfeCmdSortAscending)
  1481.            || IS_CMD(xfeCmdSortDescending)
  1482.            || IS_CMD(xfeCmdMarkMessageByDate))
  1483.     {
  1484.       return MSG_GetNumLines(m_pane) > 0;
  1485.     }
  1486.   // commands that work on the msgview.
  1487.   else if (IS_CMD(xfeCmdShowAllHeaders)
  1488.            || IS_CMD(xfeCmdPrint)
  1489.            || IS_CMD(xfeCmdShowNormalHeaders)
  1490.            || IS_CMD(xfeCmdShowBriefHeaders)
  1491.            || IS_CMD(xfeCmdWrapLongLines)
  1492.            || IS_CMD(xfeCmdViewAttachmentsInline)
  1493.            || IS_CMD(xfeCmdViewAttachmentsAsLinks)
  1494.            || IS_CMD(xfeCmdViewPageSource)
  1495.            || IS_CMD(xfeCmdFindInObject)
  1496.            || IS_CMD(xfeCmdFindAgain))
  1497.     {
  1498.       return m_msgExpanded && m_msgview->isCommandEnabled(cmd);
  1499.     }
  1500.  
  1501.   else if (IS_CMD(xfeCmdSearch))
  1502.       {
  1503.           return !XP_IsContextBusy(m_contextData);
  1504.       }
  1505.   else if (IS_CMD(xfeCmdExpand)
  1506.            || IS_CMD(xfeCmdExpandAll)
  1507.            || IS_CMD(xfeCmdCollapse)
  1508.            || IS_CMD(xfeCmdCollapseAll))
  1509.       return True;
  1510.   else
  1511.     {
  1512.       return XFE_MNListView::isCommandEnabled(cmd, calldata, info);
  1513.     }
  1514. #undef IS_CMD
  1515. }
  1516.  
  1517. Boolean
  1518. XFE_ThreadView::handlesCommand(CommandType cmd, void *calldata, XFE_CommandInfo*)
  1519. {
  1520. #define IS_CMD(command) cmd == (command)
  1521.   if (IS_CMD(xfeCmdToggleMessageExpansion)
  1522.       || IS_CMD(xfeCmdGetNewMessages)
  1523.       || IS_CMD(xfeCmdGetNextNNewMsgs)
  1524.       || IS_CMD(xfeCmdAddSenderToAddressBook)
  1525.       || IS_CMD(xfeCmdAddAllToAddressBook)
  1526.       || IS_CMD(xfeCmdEditMessage)
  1527.       || IS_CMD(xfeCmdSendMessagesInOutbox)
  1528.       || IS_CMD(xfeCmdPrint)
  1529.       || IS_CMD(xfeCmdSaveAs)
  1530.       || IS_CMD(xfeCmdReplyToSender)
  1531.       || IS_CMD(xfeCmdReplyToSenderAndNewsgroup)
  1532.       || IS_CMD(xfeCmdReplyToAll)
  1533.       || IS_CMD(xfeCmdForwardMessage)
  1534.       || IS_CMD(xfeCmdForwardMessageQuoted)
  1535.       || IS_CMD(xfeCmdNextMessage)
  1536.       || IS_CMD(xfeCmdNextUnreadMessage)
  1537.       || IS_CMD(xfeCmdPreviousMessage)
  1538.       || IS_CMD(xfeCmdPreviousUnreadMessage)
  1539.       || IS_CMD(xfeCmdDeleteMessage)
  1540.       || IS_CMD(xfeCmdSortBySender)
  1541.       || IS_CMD(xfeCmdSortByDate)
  1542.       || IS_CMD(xfeCmdSortBySubject)
  1543.       || IS_CMD(xfeCmdSortByPriority)
  1544.       || IS_CMD(xfeCmdSortByThread)
  1545.       || IS_CMD(xfeCmdSortByMessageNumber)
  1546.       || IS_CMD(xfeCmdSortBySize)
  1547.       || IS_CMD(xfeCmdSortByFlag)
  1548.       || IS_CMD(xfeCmdSortByStatus)
  1549.       || IS_CMD(xfeCmdSortByUnread)
  1550.       || IS_CMD(xfeCmdSortAscending)
  1551.       || IS_CMD(xfeCmdSortDescending)
  1552.       || IS_CMD(xfeCmdViewNew)
  1553.       || IS_CMD(xfeCmdViewAllThreads)
  1554.       || IS_CMD(xfeCmdViewThreadsWithNew)
  1555.       || IS_CMD(xfeCmdViewWatchedThreadsWithNew)
  1556.       || IS_CMD(xfeCmdShowAllHeaders)
  1557.       || IS_CMD(xfeCmdShowNormalHeaders)
  1558.       || IS_CMD(xfeCmdShowBriefHeaders)
  1559.       || IS_CMD(xfeCmdViewAttachmentsInline)
  1560.       || IS_CMD(xfeCmdViewAttachmentsAsLinks)
  1561.       || IS_CMD(xfeCmdRot13Message)
  1562.       || IS_CMD(xfeCmdMarkMessageRead)
  1563.       || IS_CMD(xfeCmdMarkMessageUnread)
  1564.       || IS_CMD(xfeCmdMarkMessageByDate)
  1565.       || IS_CMD(xfeCmdMarkThreadRead)
  1566.       || IS_CMD(xfeCmdMarkAllMessagesRead)
  1567.       || IS_CMD(xfeCmdMarkMessage)
  1568.       || IS_CMD(xfeCmdUnmarkMessage)
  1569.       || IS_CMD(xfeCmdToggleThreadKilled)
  1570.       || IS_CMD(xfeCmdToggleThreadWatched)
  1571.       || IS_CMD(xfeCmdRenameFolder)
  1572.       || IS_CMD(xfeCmdSearch)
  1573.       || IS_CMD(xfeCmdSearchAddress)
  1574.       || IS_CMD(xfeCmdEditPreferences)
  1575.       || IS_CMD(xfeCmdWrapLongLines)
  1576.  
  1577.       /* priorities. */
  1578.       || IS_CMD(xfeCmdSetPriorityHighest)
  1579.       || IS_CMD(xfeCmdSetPriorityHigh)
  1580.       || IS_CMD(xfeCmdSetPriorityNormal)
  1581.       || IS_CMD(xfeCmdSetPriorityLow)
  1582.       || IS_CMD(xfeCmdSetPriorityLowest)
  1583.       || IS_CMD(xfeCmdSetPriorityNone)
  1584.  
  1585.       /* we handle these command to place more constraints on it being sensitive. */
  1586.       || IS_CMD(xfeCmdViewPageSource)
  1587.       || IS_CMD(xfeCmdFindInObject)
  1588.       || IS_CMD(xfeCmdFindAgain)
  1589.  
  1590.       || IS_CMD(xfeCmdShowPopup)
  1591.       || IS_CMD(xfeCmdModerateDiscussion)
  1592.  
  1593.       || IS_CMD(xfeCmdEditMessage)
  1594.       || IS_CMD(xfeCmdOpenSelected)
  1595.       || IS_CMD(xfeCmdUpdateMessageCount)
  1596.       || IS_CMD(xfeCmdNewFolder)
  1597.       || IS_CMD(xfeCmdCompressAllFolders)
  1598.       || IS_CMD(xfeCmdCompressFolders)
  1599.       || IS_CMD(xfeCmdAddNewsgroup)
  1600.       || IS_CMD(xfeCmdPrintSetup)
  1601.       || IS_CMD(xfeCmdPrintPreview)
  1602.       || IS_CMD(xfeCmdExpand)
  1603.       || IS_CMD(xfeCmdExpandAll)
  1604.       || IS_CMD(xfeCmdCollapse)
  1605.       || IS_CMD(xfeCmdCollapseAll)
  1606.       || IS_CMD(xfeCmdToggleKilledThreads)
  1607.       || IS_CMD(xfeCmdSelectThread)
  1608.       || IS_CMD(xfeCmdEditConfiguration)
  1609.       || IS_CMD(xfeCmdModerateDiscussion)
  1610.       || IS_CMD(xfeCmdMommy))
  1611.     {
  1612.       return TRUE;
  1613.     }
  1614.   else
  1615.     {
  1616.       return XFE_MNListView::handlesCommand(cmd, calldata);
  1617.     }
  1618. #undef IS_CMD
  1619. }
  1620.  
  1621. void
  1622. XFE_ThreadView::addCollapsed(int where)
  1623. {
  1624.  
  1625.     if (m_collapsedCount && m_collapsed)
  1626.         m_collapsed = (int *) XP_REALLOC(m_collapsed, 
  1627.                                        (m_collapsedCount+1)*sizeof(int));
  1628.     else
  1629.         m_collapsed = (int *) XP_CALLOC(1, sizeof(int));
  1630.     m_collapsed[m_collapsedCount++] = where+1;
  1631. #if defined(DEBUG_tao)
  1632.     printf("\n-->addCollapsed=%d, m_collapsedCount=%d\n", 
  1633.            where+1, m_collapsedCount);
  1634. #endif        
  1635. }
  1636.  
  1637. XP_Bool
  1638. XFE_ThreadView::isCollapsed(int where)
  1639. {
  1640.     if (!m_collapsedCount || !m_collapsed)
  1641.         return False;
  1642.  
  1643.     for (int i=0; i < m_collapsedCount; i++)
  1644.         if (m_collapsed[i] == where) {
  1645.             /* clear it
  1646.              * thread children's pos > 0
  1647.              */
  1648.             m_collapsed[i] = 0-where;
  1649.             return True;
  1650.         }/* for i */
  1651.     return False;
  1652. }
  1653.  
  1654. void
  1655. XFE_ThreadView::doCommand(CommandType cmd,
  1656.                           void *calldata, XFE_CommandInfo* info)
  1657. {
  1658. #define IS_CMD(command) cmd == (command)
  1659.   const int *selected;
  1660.   int count;
  1661.   
  1662.   m_outliner->getSelection(&selected, &count);
  1663.  
  1664.   if (IS_CMD(xfeCmdToggleMessageExpansion))
  1665.       {
  1666.           toggleMsgExpansion();
  1667.           getToplevel()->notifyInterested(XFE_View::chromeNeedsUpdating);
  1668.       }
  1669.   else if (IS_CMD(xfeCmdMommy))
  1670.       {
  1671.           fe_showFoldersWithSelected(XtParent(getToplevel()->getBaseWidget()),
  1672.                                      ViewGlue_getFrame(m_contextData),
  1673.                                      NULL,
  1674.                                      m_folderInfo);
  1675.       }
  1676.   else if (IS_CMD(xfeCmdShowPopup))
  1677.     {
  1678.         XEvent *event = info->event;
  1679.         int x, y, clickrow;
  1680.         Widget w = XtWindowToWidget(event->xany.display, event->xany.window);
  1681.         
  1682.         if (m_popup)
  1683.             delete m_popup;
  1684.  
  1685.         if (w == NULL) w = m_widget;
  1686.         
  1687.         m_popup = new XFE_PopupMenu("popup",(XFE_Frame*)m_toplevel, // XXXXXXX
  1688.                         XfeAncestorFindApplicationShell(w));
  1689.         
  1690.         if (m_displayingNewsgroup)
  1691.             m_popup->addMenuSpec(news_popup_spec);
  1692.         else
  1693.             m_popup->addMenuSpec(mail_popup_spec);
  1694.  
  1695.         m_outliner->translateFromRootCoords(event->xbutton.x_root,
  1696.                                             event->xbutton.y_root,
  1697.                                             &x, &y);
  1698.       
  1699.         clickrow = m_outliner->XYToRow(x, y);
  1700.         
  1701.         if (clickrow != -1) /* if it was actually in the outliner's content rows. */
  1702.             {
  1703.                 if (! m_outliner->isSelected(clickrow))
  1704.                 {
  1705.                     m_outliner->selectItemExclusive(clickrow);
  1706.                     showMessage(clickrow);                
  1707.                 }
  1708.             }
  1709.  
  1710.         m_popup->position(event);
  1711.         
  1712.         m_popup->show();
  1713.     }
  1714.   else if (IS_CMD(xfeCmdGetNewMessages))
  1715.       {
  1716.           getNewMail();
  1717.       }
  1718.   else if (IS_CMD(xfeCmdGetNextNNewMsgs))
  1719.       {
  1720.           getNewNews();
  1721.       }
  1722.   else if (IS_CMD(xfeCmdMarkMessageByDate))
  1723.       {
  1724.           markReadByDate();
  1725.       }
  1726.   else if (IS_CMD(xfeCmdEditPreferences))
  1727.       {
  1728.           fe_showMailNewsPreferences(getToplevel(), m_contextData);
  1729.       }
  1730.   else if (IS_CMD(xfeCmdShowAllHeaders)
  1731.            || IS_CMD(xfeCmdPrint)
  1732.            || IS_CMD(xfeCmdShowNormalHeaders)
  1733.            || IS_CMD(xfeCmdShowBriefHeaders)
  1734.            || IS_CMD(xfeCmdWrapLongLines)
  1735.            || IS_CMD(xfeCmdViewAttachmentsInline)
  1736.            || IS_CMD(xfeCmdViewAttachmentsAsLinks)
  1737.            /* pass to msgview
  1738.             */
  1739.            || IS_CMD(xfeCmdBack)
  1740.            || IS_CMD(xfeCmdForward))
  1741.       {
  1742.           m_msgview->doCommand(cmd);
  1743.       }
  1744.   else if (IS_CMD(xfeCmdSetPriorityHighest)
  1745.            || IS_CMD(xfeCmdSetPriorityHigh)
  1746.            || IS_CMD(xfeCmdSetPriorityNormal)
  1747.            || IS_CMD(xfeCmdSetPriorityLow)
  1748.            || IS_CMD(xfeCmdSetPriorityLowest)
  1749.            || IS_CMD(xfeCmdSetPriorityNone))
  1750.       {
  1751.           MSG_PRIORITY priority = commandToPriority(cmd);
  1752.           MessageKey key;
  1753.           int i;
  1754.           
  1755.           for (i = 0; i < count; i ++)
  1756.               {
  1757.                   key = MSG_GetMessageKey(m_pane, (MSG_ViewIndex)selected[i]);
  1758.                   
  1759.                   MSG_SetPriority(m_pane, key, priority);
  1760.               }
  1761.       }
  1762.   else if (IS_CMD(xfeCmdMoveMessage))
  1763.       {
  1764.           MSG_FolderInfo *info = (MSG_FolderInfo*)calldata;
  1765.           
  1766.           if (info)
  1767.           {
  1768.             MSG_FolderLine folderLine;
  1769.               MSG_GetFolderLineById(XFE_MNView::getMaster(), info, &folderLine);
  1770.  
  1771.             if ( folderLine.flags & MSG_FOLDER_FLAG_NEWSGROUP)
  1772.             {
  1773.                MSG_CopyMessagesIntoFolder(m_pane, (MSG_ViewIndex*)selected, count, info);
  1774.             }
  1775.             else
  1776.             {
  1777.                 MSG_MoveMessagesIntoFolder(m_pane, (MSG_ViewIndex*)selected, count, info);
  1778.             }
  1779.           }
  1780.       }
  1781.   else if (IS_CMD(xfeCmdCopyMessage))
  1782.     {
  1783.       MSG_FolderInfo *info = (MSG_FolderInfo*)calldata;
  1784.  
  1785.       if (info)
  1786.     MSG_CopyMessagesIntoFolder(m_pane, (MSG_ViewIndex*)selected, count, info);
  1787.     }
  1788.   else if (isDisplayingNews()
  1789.       && (IS_CMD(xfeCmdDeleteMessage) || IS_CMD(xfeCmdCancelMessages)))
  1790.     {
  1791.         // If this is a news article, then Delete Message
  1792.         // is really Cancel Message:
  1793.         MSG_Command(m_pane, MSG_CancelMessage,
  1794.                     (MSG_ViewIndex*)selected, count);
  1795.     }
  1796.   else if (IS_CMD(xfeCmdExpand))
  1797.     { 
  1798.         MSG_MessageLine mline;
  1799.         MSG_GetThreadLineByIndex(m_pane, (MSG_ViewIndex)selected[0], 1,
  1800.                                  &mline);
  1801.         if ((mline.numChildren > (uint16)0)
  1802.             && ((mline.flags & MSG_FLAG_ELIDED) != (uint32)0))
  1803.             MSG_ToggleExpansion(m_pane, (MSG_ViewIndex)selected[0], NULL);
  1804.     }
  1805.   else if (IS_CMD(xfeCmdCollapse))
  1806.     {
  1807.         MSG_MessageLine mline;
  1808.         MSG_GetThreadLineByIndex(m_pane, (MSG_ViewIndex)selected[0], 1,
  1809.                                  &mline);
  1810.         if ((mline.numChildren > (uint16)0)
  1811.             && ((mline.flags & MSG_FLAG_ELIDED) == (uint32)0)) {
  1812.             if (mline.numChildren == 1)
  1813.                 addCollapsed(selected[0]);
  1814.             MSG_ToggleExpansion(m_pane, (MSG_ViewIndex)selected[0], NULL);
  1815.         }/* if */
  1816.     }
  1817.   else if (IS_CMD(xfeCmdExpandAll))
  1818.     {
  1819.         // Note that in the following loop, getTotalLines()
  1820.         // may grow each time we expand, but that's okay.
  1821.         int i;
  1822.         for (i=0; i < getOutliner()->getTotalLines(); ++i)
  1823.         {
  1824.             MSG_MessageLine mline;
  1825.             MSG_GetThreadLineByIndex(m_pane, i, 1, &mline);
  1826.             if ((mline.numChildren != (uint16)0)
  1827.                 && ((mline.flags & MSG_FLAG_ELIDED) != (uint32)0))
  1828.                 MSG_ToggleExpansion(m_pane, (MSG_ViewIndex)i, NULL);
  1829.         }
  1830.     }
  1831.   else if (IS_CMD(xfeCmdCollapseAll))
  1832.     {
  1833.         // Note that in the following loop, getTotalLines()
  1834.         // may shrink each time we collapse, but that's okay.
  1835.         int i;
  1836.         for (i=0; i < getOutliner()->getTotalLines(); ++i)
  1837.         {
  1838.             MSG_MessageLine mline;
  1839.             MSG_GetThreadLineByIndex(m_pane, i, 1, &mline);
  1840.             if (mline.numChildren != (uint16)0)
  1841.             {
  1842.                 // Now collapse the parent:
  1843.                 if ((mline.flags & MSG_FLAG_ELIDED) == (uint32)0) {
  1844.                     if (mline.numChildren == 1)
  1845.                         addCollapsed(i);
  1846.                     MSG_ToggleExpansion(m_pane, (MSG_ViewIndex)i, NULL);
  1847.                 }/* if */
  1848.             }
  1849.         }
  1850.     }
  1851.   else if (IS_CMD(xfeCmdDeleteMessage))
  1852.       {
  1853.           if (count == 1)
  1854.               /* stop loading since we are deleting this message:
  1855.                * shall we check if it is stopable?
  1856.                */
  1857.               XP_InterruptContext(m_contextData);
  1858.  
  1859.               {
  1860.                   MSG_Command(m_pane, MSG_DeleteMessage, (MSG_ViewIndex*)selected, count);
  1861.               }
  1862.  
  1863.           XFE_MozillaApp::theApp()->
  1864.               notifyInterested(XFE_MNView::folderChromeNeedsUpdating, 
  1865.                                getFolderInfo());
  1866.       }
  1867.   else if (IS_CMD(xfeCmdEditMailFilterRules))
  1868.       {
  1869.           fe_showMailFilterDlg(getToplevel()->getBaseWidget(), 
  1870.                                m_contextData);
  1871.       }
  1872.   else if (IS_CMD(xfeCmdSearchAddress))
  1873.       {
  1874.           fe_showLdapSearch(XfeAncestorFindApplicationShell(getToplevel()->getBaseWidget()),
  1875.                             ViewGlue_getFrame(m_contextData),
  1876.                             (Chrome*)NULL);
  1877.     
  1878.       }
  1879.   else if (IS_CMD(xfeCmdSelectThread))
  1880.   {
  1881.         // Call Select Thread
  1882.         selectThread();
  1883.   }
  1884.   else if (IS_CMD(xfeCmdViewNew)
  1885.            || IS_CMD(xfeCmdViewThreadsWithNew)
  1886.            || IS_CMD(xfeCmdViewWatchedThreadsWithNew)
  1887.            || IS_CMD(xfeCmdViewAllThreads)
  1888.            || IS_CMD(xfeCmdToggleKilledThreads)
  1889.            || IS_CMD(xfeCmdSortBySender)
  1890.            || IS_CMD(xfeCmdSortByDate)
  1891.            || IS_CMD(xfeCmdSortBySubject)
  1892.            || IS_CMD(xfeCmdSortByPriority)
  1893.            || IS_CMD(xfeCmdSortByThread)
  1894.            || IS_CMD(xfeCmdSortByMessageNumber)
  1895.            || IS_CMD(xfeCmdSortBySize)
  1896.            || IS_CMD(xfeCmdSortByFlag)
  1897.            || IS_CMD(xfeCmdSortByStatus)
  1898.            || IS_CMD(xfeCmdSortByUnread))
  1899.       {
  1900.           D(printf ("Changing view.\n");)
  1901.           MSG_CommandType msg_cmd = commandToMsgCmd(cmd);
  1902.  
  1903.           if (msg_cmd != (MSG_CommandType)~0)
  1904.               {
  1905.                   MSG_Command(m_pane, msg_cmd, (MSG_ViewIndex*)selected, count);
  1906.                   
  1907.                   /* make sure one of the selected items is still visible. */
  1908.                   m_outliner->getSelection(&selected, &count);
  1909.                   if (count > 0)
  1910.                       m_outliner->makeVisible(selected[0]);
  1911.                   if (IS_CMD(xfeCmdSortByMessageNumber))
  1912.                       m_outliner->setSortColumn(-1, m_outliner->getSortDirection());
  1913.               }
  1914.       }
  1915.   else if (IS_CMD(xfeCmdOpenSelected))
  1916.       {
  1917.           int i;
  1918.           MessageKey key;
  1919.  
  1920.           for (i = 0; i < count; i ++)
  1921.               {
  1922.                   key = MSG_GetMessageKey(m_pane, (MSG_ViewIndex)selected[i]);
  1923.                   
  1924.                   fe_showMsg(XtParent(getToplevel()->getBaseWidget()),
  1925.                              ViewGlue_getFrame(m_contextData),
  1926.                              NULL, m_folderInfo, key, FALSE);
  1927.               }
  1928.       }
  1929.   else if (IS_CMD(xfeCmdSearch))
  1930.       {
  1931.           // We don't need to call XtParent on the base widget because
  1932.           // the base widget is the real toplevel widget already...dora 12/31/96
  1933.           fe_showMNSearch(XfeAncestorFindApplicationShell(getToplevel()->getBaseWidget()),
  1934.                           ViewGlue_getFrame(m_contextData),
  1935.                           NULL, this, m_folderInfo);
  1936.       }
  1937.   else if (IS_CMD(xfeCmdSortDescending))
  1938.       {
  1939.           if ( MSG_GetToggleStatus( m_pane, MSG_SortBackward, NULL, 0  )
  1940.                != MSG_Checked )
  1941.               {
  1942.                   MSG_Command(m_pane, MSG_SortBackward, NULL, 0);
  1943.  
  1944.                   /* make sure one of the selected items is still visible. */
  1945.                   m_outliner->getSelection(&selected, &count);
  1946.                   if (count > 0)
  1947.                       m_outliner->makeVisible(selected[0]);
  1948.               }
  1949.       }
  1950.   else if (IS_CMD(xfeCmdSortAscending))
  1951.       {
  1952.           if ( MSG_GetToggleStatus( m_pane, MSG_SortBackward, NULL, 0 )
  1953.                == MSG_Checked )
  1954.               {
  1955.                   MSG_Command(m_pane, MSG_SortBackward, NULL, 0);
  1956.                   
  1957.                   /* make sure one of the selected items is still visible. */
  1958.                   m_outliner->getSelection(&selected, &count);
  1959.                   if (count > 0)
  1960.                       m_outliner->makeVisible(selected[0]);
  1961.               }
  1962.       }
  1963.   else 
  1964.       {
  1965.           MSG_CommandType msg_cmd = commandToMsgCmd(cmd);
  1966.           MSG_MotionType nav_cmd = commandToMsgNav(cmd);
  1967.           
  1968.           if (info) {
  1969.               CONTEXT_DATA(m_contextData)->stealth_cmd =
  1970.                   ((info->event->type == ButtonRelease) &&
  1971.                    (info->event->xkey.state & ShiftMask));
  1972.           }
  1973.  
  1974.           if (nav_cmd == (MSG_MotionType)~0)
  1975.               {
  1976.                   if ((msg_cmd == (MSG_CommandType)~0) ||
  1977.                       (msg_cmd == MSG_MailNew) ||
  1978.                       (msg_cmd == MSG_PostNew) )
  1979.                       {
  1980.                           XFE_MNListView::doCommand(cmd, calldata, info);
  1981.                       }
  1982.                   else {
  1983.                       MSG_Command(m_pane, msg_cmd, (MSG_ViewIndex*)selected, count);
  1984.  
  1985.                       /* single pane; count ==1
  1986.                        */
  1987.                       if (IS_CMD(xfeCmdUndo) 
  1988.                           || IS_CMD(xfeCmdRedo)) {
  1989.                           MessageKey key = MSG_MESSAGEKEYNONE;
  1990.                           MSG_FolderInfo *folder = NULL;
  1991.                            
  1992.                           if (!m_pane || !m_outliner) 
  1993.                               return;
  1994.                                
  1995.                           UndoStatus undoStatus = 
  1996.                               MSG_GetUndoStatus(m_pane); 
  1997.                           
  1998.                           if ( UndoComplete == undoStatus ) {
  1999.                               if (MSG_GetUndoMessageKey(m_pane, 
  2000.                                                         &folder, &key) 
  2001.                                   && folder) {
  2002.                                   if (m_folderInfo == folder) {
  2003.                                        /* same folder
  2004.                                         * select the message right away!
  2005.                                         */
  2006.                                        MSG_ViewIndex index = 
  2007.                                            MSG_GetMessageIndexForKey(m_pane, 
  2008.                                                                      key, 
  2009.                                                                      TRUE);
  2010.                                        if (index != MSG_VIEWINDEXNONE) {
  2011.                                            showMessage(index);
  2012.                                       }
  2013.                                       
  2014.                                    }/* if */
  2015.                                    else {
  2016. #if HANDLE_CMD_QUEUE
  2017.                                        /* need to load new folder 
  2018.                                         */
  2019.                                       /* XFE: let handlePendingCmd() deal with 
  2020.                                        * this part
  2021.                                        */
  2022.                                       m_commandPending = selectByKey;
  2023.                                       m_pendingSelectionKey = key;
  2024.                                       loadFolder(folder);
  2025. #endif /* HANDLE_CMD_QUEUE */
  2026.                                    }/* if */
  2027.                                }/* if */
  2028.                            }/* if UndoComplete == undoStatus */
  2029.                        }/* if */
  2030.                    }/* else */
  2031.                   
  2032.               }
  2033.           else
  2034.               {
  2035.                   MSG_ViewIndex index, threadIndex;
  2036.                   MessageKey resultId;
  2037.                   MSG_FolderInfo *new_finfo;
  2038.  
  2039.                   if (count == 1)
  2040.                       {
  2041.                           m_outliner->setBlockSel(True);
  2042.                           MSG_ViewNavigate(m_pane, nav_cmd, selected[0], 
  2043.                                            &resultId, &index, &threadIndex, 
  2044.                                            &new_finfo);
  2045.                           m_outliner->setBlockSel(False);
  2046.                           
  2047.                           // ViewNavigate gives a NULL folderinfo if the folder
  2048.                           // info won't be changing.
  2049.                           if (new_finfo &&
  2050.                               new_finfo != m_folderInfo)
  2051.                               {
  2052.                                   /* insert here any navigational commands that can span folders, and
  2053.                                      add corresponding entry in pendingCommand */
  2054.                                   switch (nav_cmd)
  2055.                                       {
  2056.                                       case MSG_NextUnreadMessage:
  2057.                                           m_commandPending = selectFirstUnread;
  2058.                                           break;
  2059.                                       case MSG_PreviousUnreadMessage:
  2060.                                           m_commandPending = selectLastUnread;
  2061.                                           break;
  2062.                                       default:
  2063.                                           XP_ASSERT(0);
  2064.                                           break;
  2065.                                       }
  2066.                                   loadFolder(new_finfo);
  2067.                               }
  2068.                           else
  2069.                               {
  2070.                                   
  2071.                                   int numLines = MSG_GetNumLines(m_pane),
  2072.                                       idx = (int) index;
  2073.                                   if (idx >=0 && idx < numLines)
  2074.                                       showMessage(idx);
  2075.                               }
  2076.                       }
  2077.               }
  2078.  
  2079.           XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating, 
  2080.                                                      getFolderInfo());
  2081.       }
  2082. #undef IS_CMD
  2083. }
  2084.  
  2085. char *XFE_ThreadView::getColumnTextByMsgLine(MSG_MessageLine *msgLine, int column)
  2086. {
  2087.   static char buf[1024];     /* ## Sigh... */
  2088.   static char from_buf[1024];     /* ## Sigh... */
  2089.   static char size_buf[100]; /* ## Sigh... */
  2090.   char *tmp = NULL;
  2091.   
  2092.   switch (column)
  2093.     {
  2094.     case OUTLINER_COLUMN_SUBJECT:
  2095.       {
  2096.         tmp = IntlDecodeMimePartIIStr(msgLine->subject, fe_LocaleCharSetID, 
  2097.                                       FALSE);
  2098.  
  2099.         if (msgLine->flags & MSG_FLAG_HAS_RE) 
  2100.           {
  2101.             XP_SAFE_SPRINTF(buf, sizeof(buf), 
  2102.                             "%s", XP_GetString( XFE_RE ) ); 
  2103.             XP_STRNCAT_SAFE(buf,
  2104.                             (tmp ? tmp : msgLine->subject),
  2105.                             sizeof(buf) - XP_STRLEN(buf));
  2106.             
  2107.             if (tmp) XP_FREE(tmp);
  2108.             
  2109.             return buf;
  2110.           } 
  2111.         else 
  2112.           {
  2113.             if (tmp) 
  2114.               {
  2115.                 XP_STRNCPY_SAFE(buf, tmp, sizeof(buf));
  2116.                 XP_FREE(tmp);
  2117.                 return buf;
  2118.               } 
  2119.             else 
  2120.               {
  2121.                 XP_STRNCPY_SAFE(buf, msgLine->subject, sizeof(buf));
  2122.                 return buf;
  2123.               }
  2124.           }
  2125.       }
  2126.     case OUTLINER_COLUMN_SENDERRECIPIENT:
  2127.       {
  2128.     tmp = IntlDecodeMimePartIIStr(msgLine->author, fe_LocaleCharSetID, FALSE);
  2129.     if (tmp) 
  2130.       {
  2131.         XP_STRNCPY_SAFE(from_buf, tmp, sizeof(from_buf));
  2132.         XP_FREE(tmp);
  2133.         return from_buf;
  2134.       } 
  2135.     else 
  2136.       {
  2137.         XP_STRNCPY_SAFE(from_buf, msgLine->author, sizeof(from_buf));
  2138.         return from_buf;
  2139.       }
  2140.       }
  2141.     case OUTLINER_COLUMN_DATE:
  2142.       {
  2143.     if (msgLine->date == 0) 
  2144.       {
  2145.         return "";
  2146.       } 
  2147.     else 
  2148.       {
  2149.         return (char*)MSG_FormatDate(m_pane, msgLine->date);
  2150.       }
  2151.       }
  2152.     case OUTLINER_COLUMN_PRIORITY:
  2153.       {
  2154.     return priorityToString(msgLine->priority);
  2155.       }
  2156.     case OUTLINER_COLUMN_SIZE:
  2157.       {
  2158.           XP_SAFE_SPRINTF(size_buf, sizeof(size_buf),
  2159.                           "%ld", msgLine->messageLines);
  2160.     return size_buf;
  2161.       }
  2162.     case OUTLINER_COLUMN_STATUS:
  2163.       {
  2164.           if (msgLine->flags & MSG_FLAG_NEW)
  2165.               return XP_GetString(XP_STATUS_NEW);
  2166.           else if ((msgLine->flags & MSG_FLAG_REPLIED)&&
  2167.                    (msgLine->flags & MSG_FLAG_FORWARDED))
  2168.               return XP_GetString(XP_STATUS_REPLIED_AND_FORWARDED);
  2169.           else if (msgLine->flags & MSG_FLAG_FORWARDED)
  2170.               return XP_GetString(XP_STATUS_FORWARDED);
  2171.           else if (msgLine->flags & MSG_FLAG_REPLIED)
  2172.               return XP_GetString(XP_STATUS_REPLIED);
  2173.  
  2174.           return NULL; /* ### */
  2175.       }
  2176.     case OUTLINER_COLUMN_UNREADMSG:
  2177.       {
  2178.     return NULL; // we don't have a string in this column -- only an icon.
  2179.       }
  2180.     case OUTLINER_COLUMN_FLAG:
  2181.       {
  2182.     return NULL; // we don't have a string in this column -- only an icon.
  2183.       }
  2184.     default:
  2185.       XP_ASSERT(0);
  2186.       return NULL;
  2187.     }
  2188.  
  2189. }
  2190. /* Outlinable interface methods */
  2191. char *XFE_ThreadView::getCellTipString(int row, int column)
  2192. {
  2193.     /* returned string will be duplicated by outliner
  2194.      */
  2195.     char *tmp = 0;
  2196.     if (row < 0) {
  2197.         /* header
  2198.          */
  2199.         tmp = getColumnHeaderText(column);
  2200.     }/* if */
  2201.     else {
  2202.         /* content 
  2203.          */
  2204.         MSG_MessageLine* msgLine = 
  2205.             (MSG_MessageLine *) XP_CALLOC(1, 
  2206.                                           sizeof(MSG_MessageLine));
  2207.         if (!MSG_GetThreadLineByIndex(m_pane, row, 1, msgLine))
  2208.             return NULL;
  2209.  
  2210.         /* static array; do not free
  2211.          */
  2212.         tmp = getColumnTextByMsgLine(msgLine, column);
  2213.         XP_FREEIF(msgLine);
  2214.     }/* else */
  2215.     if (tmp && 
  2216.         (!m_outliner->isColTextFit(tmp, row, column)))
  2217.         return tmp;
  2218.  
  2219.     return NULL;
  2220. }
  2221.  
  2222. char *XFE_ThreadView::getCellDocString(int /* row */, int /* column */)
  2223. {
  2224.     return NULL;
  2225. }
  2226.  
  2227. void *
  2228. XFE_ThreadView::ConvFromIndex(int index)
  2229. {
  2230.   MessageKey id = MSG_GetMessageKey(m_pane, index);
  2231.  
  2232.   return (void*)id;
  2233. }
  2234.  
  2235. int
  2236. XFE_ThreadView::ConvToIndex(void *item)
  2237. {
  2238.   MessageKey id = (MessageKey)item;
  2239.   MSG_ViewIndex index;
  2240.  
  2241.   index = MSG_GetMessageIndexForKey(m_pane, id, False);
  2242.  
  2243.   if (index == MSG_VIEWINDEXNONE)
  2244.       {
  2245.           MSG_MessageLine line;
  2246.  
  2247.           if (!MSG_GetThreadLineById(m_pane, id, &line))
  2248.               {
  2249.                   /* error while looking up line for this message.
  2250.                      punt */
  2251.                   return -1;
  2252.               }
  2253.           else
  2254.               {
  2255.                   MSG_ViewIndex thread_index =
  2256.                       MSG_GetMessageIndexForKey(m_pane, line.threadId, False);
  2257.                   
  2258.                   if (MSG_ExpansionDelta(m_pane, thread_index) > 0)
  2259.                       {
  2260.                           MSG_ToggleExpansion(m_pane, thread_index, NULL);
  2261.                           index = MSG_GetMessageIndexForKey(m_pane, 
  2262.                                                             id, False);
  2263.                       }
  2264.                   
  2265.                   return index;
  2266.               }
  2267.       }
  2268.   else
  2269.       {
  2270.           return index;
  2271.       }
  2272. }
  2273.  
  2274. void *
  2275. XFE_ThreadView::acquireLineData(int line)
  2276. {
  2277.   m_ancestorInfo = NULL;
  2278.  
  2279.   if (!MSG_GetThreadLineByIndex(m_pane, line, 1, &m_messageLine))
  2280.     return NULL;
  2281.  
  2282.   m_ancestorInfo = new OutlinerAncestorInfo[ m_messageLine.level + 1 ];
  2283.  
  2284.   int i = m_messageLine.level;
  2285.   int idx = line + 1;
  2286.   while ( i > 0 ) {
  2287.     if ( idx < m_outliner->getTotalLines()) {
  2288.       int level = MSG_GetThreadLevelByIndex( m_pane, idx );
  2289.       if ( level == i ) {
  2290.     m_ancestorInfo[i].has_prev = TRUE;
  2291.     m_ancestorInfo[i].has_next = TRUE;
  2292.     i--;
  2293.     idx++;
  2294.       } else if ( level < i ) {
  2295.     m_ancestorInfo[i].has_prev = FALSE;
  2296.     m_ancestorInfo[i].has_next = FALSE;
  2297.     i--;
  2298.       } else {
  2299.     idx++;
  2300.       }
  2301.     } else {
  2302.       m_ancestorInfo[i].has_prev = FALSE;
  2303.       m_ancestorInfo[i].has_next = FALSE;
  2304.       i--;
  2305.     }
  2306.   }
  2307.   m_ancestorInfo[0].has_prev = FALSE;
  2308.   m_ancestorInfo[0].has_next = FALSE;
  2309.   
  2310.   return &m_messageLine;
  2311. }
  2312.  
  2313. void
  2314. XFE_ThreadView::getTreeInfo(Boolean *expandable,
  2315.                   Boolean *is_expanded,
  2316.                   int *depth,
  2317.                   OutlinerAncestorInfo **ancestor)
  2318. {
  2319.   XP_Bool is_line_expandable;
  2320.   XP_Bool is_line_expanded;
  2321.  
  2322.   is_line_expandable = (m_messageLine.numChildren > 0);
  2323.  
  2324.   if (is_line_expandable)
  2325.     {
  2326.       is_line_expanded = (m_messageLine.flags & MSG_FLAG_ELIDED) == 0;
  2327.     }
  2328.   else
  2329.     {
  2330.       is_line_expanded = FALSE;
  2331.     }
  2332.  
  2333.   if ( ancestor )
  2334.     *ancestor = m_ancestorInfo;
  2335.  
  2336.   if (depth)
  2337.     *depth = m_messageLine.level;
  2338.  
  2339.   if (expandable)
  2340.       *expandable = is_line_expandable;
  2341.  
  2342.   if (is_expanded)
  2343.     *is_expanded = is_line_expanded;
  2344. }
  2345.  
  2346. EOutlinerTextStyle
  2347. XFE_ThreadView::getColumnStyle(int /*column*/)
  2348. {
  2349.   if (m_messageLine.flags & MSG_FLAG_EXPIRED)
  2350.     return OUTLINER_Default ; /* Don't boldface dummy messages. */
  2351.   else if ((m_messageLine.flags & MSG_FLAG_ELIDED) && m_messageLine.numNewChildren > 0)
  2352.     return OUTLINER_Bold; /* boldface toplevel thread messages with unread children. */
  2353.   else
  2354.     return (m_messageLine.flags & MSG_FLAG_READ) ? OUTLINER_Default : OUTLINER_Bold;
  2355. }
  2356.  
  2357. char *
  2358. XFE_ThreadView::getColumnText(int column)
  2359.   static char buf_a[1024];     /* ## Sigh... */
  2360.   static char from_buf_a[1024];     /* ## Sigh... */
  2361.   static char size_buf_a[100]; /* ## Sigh... */
  2362.   char *tmp = NULL;
  2363.   
  2364.   switch (column)
  2365.     {
  2366.     case OUTLINER_COLUMN_SUBJECT:
  2367.       {
  2368.     tmp = IntlDecodeMimePartIIStr(m_messageLine.subject, fe_LocaleCharSetID, FALSE);
  2369.  
  2370.     if (m_messageLine.flags & MSG_FLAG_HAS_RE) 
  2371.       {
  2372.         XP_STRNCPY_SAFE (buf_a, XP_GetString( XFE_RE ), sizeof(buf_a) ); 
  2373.         XP_STRNCAT_SAFE (buf_a, 
  2374.                          (tmp ? tmp : m_messageLine.subject), 
  2375.                          sizeof(buf_a) - XP_STRLEN(buf_a));
  2376.  
  2377.         if (tmp) XP_FREE(tmp);
  2378.  
  2379.         return buf_a;
  2380.       } 
  2381.     else 
  2382.       {
  2383.         if (tmp) 
  2384.           {
  2385.             XP_STRNCPY_SAFE(buf_a, tmp, sizeof(buf_a));
  2386.             
  2387.             XP_FREE(tmp);
  2388.             return buf_a;
  2389.           } 
  2390.         else 
  2391.           {
  2392.         return m_messageLine.subject;
  2393.           }
  2394.       }
  2395.       }
  2396.     case OUTLINER_COLUMN_SENDERRECIPIENT:
  2397.       {
  2398.     tmp = IntlDecodeMimePartIIStr(m_messageLine.author, fe_LocaleCharSetID, FALSE);
  2399.     if (tmp) 
  2400.       {
  2401.         XP_STRNCPY_SAFE(from_buf_a, tmp, sizeof(from_buf_a));
  2402.         XP_FREE(tmp);
  2403.         return from_buf_a;
  2404.       } 
  2405.     else 
  2406.       {
  2407.         return m_messageLine.author;
  2408.       }
  2409.       }
  2410.     case OUTLINER_COLUMN_DATE:
  2411.       {
  2412.     if (m_messageLine.date == 0) 
  2413.       {
  2414.         return "";
  2415.       } 
  2416.     else 
  2417.       {
  2418.         return (char*)MSG_FormatDate(m_pane, m_messageLine.date);
  2419.       }
  2420.       }
  2421.     case OUTLINER_COLUMN_PRIORITY:
  2422.       {
  2423.     return priorityToString(m_messageLine.priority);
  2424.       }
  2425.     case OUTLINER_COLUMN_SIZE:
  2426.       {
  2427.         XP_SAFE_SPRINTF(size_buf_a, sizeof(size_buf_a),
  2428.                         "%ld", m_messageLine.messageLines);
  2429.     return size_buf_a;
  2430.       }
  2431.     case OUTLINER_COLUMN_STATUS:
  2432.       {
  2433.           if (m_messageLine.flags & MSG_FLAG_NEW)
  2434.               return XP_GetString(XP_STATUS_NEW);
  2435.           else if ((m_messageLine.flags & MSG_FLAG_REPLIED)&&
  2436.                    (m_messageLine.flags & MSG_FLAG_FORWARDED))
  2437.               return XP_GetString(XP_STATUS_REPLIED_AND_FORWARDED);
  2438.           else if (m_messageLine.flags & MSG_FLAG_FORWARDED)
  2439.               return XP_GetString(XP_STATUS_FORWARDED);
  2440.           else if (m_messageLine.flags & MSG_FLAG_REPLIED)
  2441.               return XP_GetString(XP_STATUS_REPLIED);
  2442.  
  2443.           return NULL; /* ### */
  2444.       }
  2445.     case OUTLINER_COLUMN_UNREADMSG:
  2446.       {
  2447.     return NULL; // we don't have a string in this column -- only an icon.
  2448.       }
  2449.     case OUTLINER_COLUMN_FLAG:
  2450.       {
  2451.     return NULL; // we don't have a string in this column -- only an icon.
  2452.       }
  2453.     default:
  2454.       XP_ASSERT(0);
  2455.       return NULL;
  2456.     }
  2457. }
  2458.  
  2459. fe_icon *
  2460. XFE_ThreadView::getColumnIcon(int column)
  2461. {
  2462.   switch (column)
  2463.     {
  2464.     case OUTLINER_COLUMN_SUBJECT:
  2465.         {
  2466.             MSG_FolderLine folderLine;
  2467.             
  2468.             MSG_GetFolderLineById(XFE_MNView::getMaster(), m_folderInfo, &folderLine);
  2469.             
  2470.             return flagToIcon(folderLine.flags, m_messageLine.flags);
  2471.         }
  2472.     case OUTLINER_COLUMN_UNREADMSG:
  2473.         return (m_messageLine.flags & MSG_FLAG_READ ? &msgReadIcon : &msgUnreadIcon);
  2474.     case OUTLINER_COLUMN_FLAG:
  2475.         return (m_messageLine.flags & MSG_FLAG_MARKED ? &msgFlagIcon : &msgReadIcon);
  2476.     case -1: /* OUTLINER_DESCENDANT_SELECT_COLUMN */
  2477.         {
  2478.             if (m_messageLine.flags & MSG_FLAG_IGNORED)
  2479.                 {
  2480.                     return (m_messageLine.flags & MSG_FLAG_ELIDED ? &closedSpoolIgnoredIcon : &openSpoolIgnoredIcon);
  2481.                 }
  2482.             else if (m_messageLine.flags & MSG_FLAG_WATCHED)
  2483.                 {
  2484.                     return (m_messageLine.flags & MSG_FLAG_ELIDED ? &closedSpoolWatchedIcon : &openSpoolWatchedIcon);
  2485.                 }
  2486.             else if (m_messageLine.numChildren > 0)
  2487.                 {
  2488.                     if (m_messageLine.flags & MSG_FLAG_NEW
  2489.                         || m_messageLine.numNewChildren > 0)
  2490.                         return (m_messageLine.flags & MSG_FLAG_ELIDED ? &closedSpoolNewIcon : &openSpoolNewIcon);
  2491.                     else
  2492.                         return (m_messageLine.flags & MSG_FLAG_ELIDED ? &closedSpoolIcon : &openSpoolIcon);
  2493.                 }
  2494.             else
  2495.                 {
  2496.                     return NULL;
  2497.                 }
  2498.         }
  2499.     default:
  2500.         return 0;
  2501.     }
  2502. }
  2503.  
  2504. char *
  2505. XFE_ThreadView::getColumnName(int column)
  2506. {
  2507.   switch (column) 
  2508.     {
  2509.     case OUTLINER_COLUMN_SUBJECT:
  2510.       return "Subject";
  2511.     case OUTLINER_COLUMN_UNREADMSG:
  2512.       return "Unread";
  2513.     case OUTLINER_COLUMN_FLAG:
  2514.       return "Flag";
  2515.     case OUTLINER_COLUMN_DATE:
  2516.       return "Date";
  2517.     case OUTLINER_COLUMN_PRIORITY:
  2518.       return "Priority";
  2519.     case OUTLINER_COLUMN_SIZE:
  2520.       return "Size";
  2521.     case OUTLINER_COLUMN_STATUS:
  2522.       return "Status";
  2523.     case OUTLINER_COLUMN_SENDERRECIPIENT:
  2524.       return "Sender";
  2525.     default:
  2526.       XP_ASSERT(0);
  2527.       return 0;
  2528.     }
  2529. }
  2530.  
  2531. char *
  2532. XFE_ThreadView::getColumnHeaderText(int column)
  2533. {
  2534.     switch (column) 
  2535.         {
  2536.         case OUTLINER_COLUMN_SUBJECT:
  2537.             return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_SUBJECT);
  2538.         case OUTLINER_COLUMN_UNREADMSG:
  2539.             return 0;
  2540.         case OUTLINER_COLUMN_FLAG:
  2541.             return 0;
  2542.         case OUTLINER_COLUMN_DATE:
  2543.             return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_DATE);
  2544.         case OUTLINER_COLUMN_PRIORITY:
  2545.             return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_PRIORITY);
  2546.         case OUTLINER_COLUMN_SIZE:
  2547.             {
  2548.                 if (m_displayingNewsgroup)
  2549.                     return XP_GetString(XFE_SIZE_IN_LINES);
  2550.                 else
  2551.                     return XP_GetString(XFE_SIZE_IN_BYTES);
  2552.             }
  2553.         case OUTLINER_COLUMN_STATUS:
  2554.             return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_STATUS);
  2555.         case OUTLINER_COLUMN_SENDERRECIPIENT:
  2556.             if (MSG_DisplayingRecipients(m_pane))
  2557.                 return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_RECIPIENT);
  2558.             else
  2559.                 return XP_GetString(XFE_THREAD_OUTLINER_COLUMN_SENDER);
  2560.         default:
  2561.             // XP_ASSERT(0);
  2562.             return 0;
  2563.         }
  2564. }
  2565.  
  2566. fe_icon *
  2567. XFE_ThreadView::getColumnHeaderIcon(int column)
  2568. {
  2569.   switch (column)
  2570.     {
  2571.     case OUTLINER_COLUMN_UNREADMSG:
  2572.       return &msgUnreadIcon;
  2573.     case OUTLINER_COLUMN_FLAG:
  2574.       return &msgFlagIcon;
  2575.     case OUTLINER_COLUMN_SUBJECT:
  2576.       if (MSG_GetToggleStatus(m_pane, MSG_SortByThread, NULL, 0) == MSG_Checked)
  2577.           return &threadonIcon;
  2578.       else
  2579.           return &threadoffIcon;
  2580.     default:
  2581.       return 0;
  2582.     }
  2583. }
  2584.  
  2585. EOutlinerTextStyle
  2586. XFE_ThreadView::getColumnHeaderStyle(int column)
  2587. {
  2588.   MSG_CommandType sort_type = (MSG_CommandType)~0;
  2589.  
  2590.   switch (column)
  2591.     {
  2592.     case OUTLINER_COLUMN_SENDERRECIPIENT:
  2593.       sort_type = MSG_SortBySender;
  2594.       break;
  2595.     case OUTLINER_COLUMN_DATE:
  2596.       sort_type = MSG_SortByDate;
  2597.       break;
  2598.     case OUTLINER_COLUMN_SUBJECT:
  2599.       sort_type = MSG_SortBySubject;
  2600.       break;
  2601.     case OUTLINER_COLUMN_PRIORITY:
  2602.       sort_type = MSG_SortByPriority;
  2603.       break;
  2604.     case OUTLINER_COLUMN_SIZE:
  2605.         sort_type = MSG_SortBySize;
  2606.         break;
  2607.     case OUTLINER_COLUMN_STATUS:
  2608.         sort_type = MSG_SortByStatus;
  2609.         break;
  2610.     case OUTLINER_COLUMN_UNREADMSG:
  2611.         sort_type = MSG_SortByUnread;
  2612.         break;
  2613.     case OUTLINER_COLUMN_FLAG:
  2614.         sort_type = MSG_SortByFlagged;
  2615.         break;
  2616.     }
  2617.   
  2618.   if (sort_type == (MSG_CommandType)~0)
  2619.     {
  2620.       return OUTLINER_Default;
  2621.     }
  2622.   else
  2623.     {
  2624.         XP_Bool checked = MSG_GetToggleStatus(m_pane, sort_type, NULL, 0) == MSG_Checked;
  2625.         XP_Bool backward = MSG_GetToggleStatus(m_pane, MSG_SortBackward, NULL, 0) == MSG_Checked;
  2626.  
  2627.         if (checked)
  2628.             {
  2629.                 m_outliner->setSortColumn(column,
  2630.                                           backward ? OUTLINER_SortDescending : OUTLINER_SortAscending);
  2631.                 return OUTLINER_Bold;
  2632.             }
  2633.         else
  2634.             {
  2635.                 return OUTLINER_Default;
  2636.             }
  2637.     }
  2638. }
  2639.  
  2640. void
  2641. XFE_ThreadView::releaseLineData()
  2642. {
  2643.   delete [] m_ancestorInfo;
  2644.   m_ancestorInfo = NULL;
  2645. }
  2646.  
  2647. XFE_CALLBACK_DEFN(XFE_ThreadView, allConnectionsComplete)(XFE_NotificationCenter *,
  2648.                                                           void *,
  2649.                                                           void *)
  2650. {
  2651.     D(printf ("in all connections complete.\n");)
  2652.  
  2653. #if HANDLE_CMD_QUEUE
  2654.  
  2655. #if defined(DEBUG_tao)
  2656.     printf("\n XFE_ThreadView::allConnectionsComplete\n");
  2657. #endif
  2658.  
  2659.     processCmdQueue();
  2660. #endif /* HANDLE_CMD_QUEUE */
  2661.  
  2662.     handlePendingCommand();
  2663.  
  2664. }
  2665.  
  2666. void
  2667. XFE_ThreadView::setPendingCmdSelByKey(PendingCommand cmd, MessageKey key)
  2668. {
  2669.     m_commandPending = cmd;
  2670.     m_pendingSelectionKey = key;
  2671. }
  2672.  
  2673. void
  2674. XFE_ThreadView::handlePendingCommand()
  2675. {
  2676.     switch (m_commandPending)
  2677.         {
  2678.         case invalidateThreadAndSelection:
  2679.             /* for this case, we loop backward to the message with level 1 -- the toplevel
  2680.                message in this thread, find it's num_children, and invalidate all those
  2681.                lines.  This fixes pipe updates and lots of other things. */
  2682.             {
  2683.                 D(printf("handlePendingCommand(invalidateThreadAndSelection)\n");)
  2684.                 /* tao: Obselete deletion code; assert!
  2685.                  */
  2686.                 XP_ASSERT(0);
  2687.                 break;
  2688.             }
  2689.         case getNewMessages:
  2690.             {
  2691.                 D(printf("handlePendingCommand(getNewMessages)\n");)
  2692.                 m_commandPending = noPendingCommand;
  2693.                 doCommand(xfeCmdGetNewMessages);
  2694.                 break;
  2695.             }
  2696.         case selectByIndex:
  2697.             {
  2698.                 D(printf("handlePendingCommand(selectByIndex)\n");)
  2699.                 D(printf("  pending selection index is %d\n", m_pendingSelectionIndex);)
  2700.                 m_commandPending = noPendingCommand;
  2701.                 if (m_pendingSelectionIndex != MSG_VIEWINDEXNONE)
  2702.                     showMessage(m_pendingSelectionIndex);
  2703.                 break;
  2704.             }
  2705.         case selectByKey:
  2706.             {
  2707.                 D(printf("handlePendingCommand(selectByKey,%d)\n", m_pendingSelectionKey);)
  2708.  
  2709.                 m_commandPending = noPendingCommand;
  2710.  
  2711.                 if (m_pendingSelectionKey != MSG_MESSAGEKEYNONE)
  2712.                     {
  2713.                         /* 87274: Caldera: "Go to Message Folder" fails when 
  2714.                          * messages are threaded.
  2715.                          *
  2716.                          * Fix: call MSG_xxxForKey() to expand the thread 
  2717.                          * when needed.
  2718.                          */
  2719.                         MSG_ViewIndex index = 
  2720.                             MSG_GetMessageIndexForKey(m_pane, 
  2721.                                                       m_pendingSelectionKey,
  2722.                                                       True);
  2723.                         D(printf ("  pending selection index is %d\n", index);)
  2724.                         if (index != MSG_VIEWINDEXNONE)
  2725.                             showMessage(index);
  2726.                     }
  2727.                 break;
  2728.             }
  2729.         case selectFirstUnread:
  2730.             {
  2731.                 D(printf("handlePendingCommand(selectFirstUnread)\n");)
  2732.                 MSG_ViewIndex index, threadIndex;
  2733.                 MessageKey resultId;
  2734.  
  2735.                 m_commandPending = noPendingCommand;
  2736.  
  2737.                 m_outliner->setBlockSel(True);
  2738.                 MSG_ViewNavigate(m_pane, MSG_FirstUnreadMessage, MSG_VIEWINDEXNONE/* ??? */,
  2739.                                  &resultId, &index, &threadIndex, NULL);
  2740.                 m_outliner->setBlockSel(False);
  2741.  
  2742.                 showMessage(index);
  2743.                 break;
  2744.             }
  2745.         case selectLastUnread:
  2746.             {
  2747.                 D(printf("handlePendingCommand(selectLastUnread)\n");)
  2748.                 MSG_ViewIndex index, threadIndex;
  2749.                 MessageKey resultId;
  2750.  
  2751.                 m_commandPending = noPendingCommand;
  2752.  
  2753.                 MSG_ViewNavigate(m_pane, MSG_LastUnreadMessage, MSG_VIEWINDEXNONE/* ??? */,
  2754.                                  &resultId, &index, &threadIndex, NULL);
  2755.  
  2756.                 showMessage(index);
  2757.                 break;
  2758.             }
  2759.         case scrollToFirstNew:
  2760.             {
  2761.                 D(printf("handlePendingCommand(scrollToFirstNew)\n");)
  2762.                 MessageKey resultId, resultingThread;
  2763.                 MSG_ViewIndex resultIndex = 0;
  2764.  
  2765.                 m_commandPending = noPendingCommand;
  2766.  
  2767.                 /* note:  We don't expand threads here -- we scroll to the message that
  2768.                    starts the thread. */
  2769.  
  2770.                 /* after we do a get new mail, we end up here.  We try to scroll to the
  2771.                    first new one. */
  2772.                 MSG_DataNavigate(m_pane, MSG_FirstNew, MSG_MESSAGEKEYNONE/*???*/,
  2773.                                  &resultId, &resultingThread);
  2774.                 
  2775.                 /* if there wasn't a new message, we scroll to the first unread message */
  2776.                 if (resultId == MSG_MESSAGEKEYNONE
  2777.                     || resultingThread == MSG_MESSAGEKEYNONE)
  2778.                     MSG_DataNavigate(m_pane, MSG_FirstUnreadMessage, MSG_MESSAGEKEYNONE/*???*/,
  2779.                                      &resultId, &resultingThread);
  2780.                 
  2781.                 /* if there wasn't an unread message, we scroll to the last item. */
  2782.                 if (m_outliner->getTotalLines() > 0)
  2783.                     {
  2784.                         if (resultId == MSG_MESSAGEKEYNONE
  2785.                             || resultingThread == MSG_MESSAGEKEYNONE)
  2786.                             {
  2787.                                 resultIndex == m_outliner->getTotalLines() - 1;
  2788.                             }
  2789.                         else
  2790.                             {
  2791.                                 resultIndex = 
  2792.                                     MSG_GetMessageIndexForKey(m_pane, 
  2793.                                                               resultingThread,
  2794.                                                               False);
  2795.                                 if (resultIndex == MSG_VIEWINDEXNONE)
  2796.                                     resultIndex = m_outliner->getTotalLines() - 1;
  2797.                             }
  2798.                         
  2799.                         m_outliner->makeVisible((int)resultIndex);
  2800.                     }
  2801.                 break;
  2802.             }
  2803.         case noPendingCommand: // we should be so lucky
  2804.             D(printf ("no pending command to execute\n");)
  2805.             break;
  2806.         default:
  2807.             XP_ASSERT(0);
  2808.             break;
  2809.         }
  2810. }
  2811.  
  2812. void 
  2813. XFE_ThreadView::Buttonfunc(const OutlineButtonFuncData *data)
  2814. {
  2815.         /* 
  2816.     ** Broadcast the view is currently in focus because 
  2817.     ** of the button clicking
  2818.     */
  2819.         getToplevel()->notifyInterested(XFE_MNListView::changeFocus, (void*) this);
  2820.  
  2821.     if (data->row == -1) // heading row.
  2822.         {
  2823.             const int *selected;
  2824.             int count;
  2825.             
  2826.             m_outliner->setDescendantSelectAllowed(False);
  2827.             
  2828.             switch (data->column)
  2829.                 {
  2830.                 case OUTLINER_COLUMN_SUBJECT:
  2831.                     if (data->x < (threadonIcon.width + /* hack -- shadowthickness */ 4))
  2832.                         {
  2833.                             if (isCommandEnabled(xfeCmdSortByThread))
  2834.                                 {
  2835.                                     m_outliner->setSortColumn(-1,
  2836.                                                               OUTLINER_SortAscending);
  2837.                                     m_outliner->setDescendantSelectAllowed(True);
  2838.                                     doCommand(xfeCmdSortByThread);
  2839.                                 }
  2840.                         }
  2841.                     else
  2842.                         {
  2843.                             if (isCommandEnabled(xfeCmdSortBySubject))
  2844.                                 {
  2845.                                     if (m_outliner->getSortColumn() == data->column)
  2846.                                         m_outliner->toggleSortDirection();
  2847.                                     doCommand(xfeCmdSortBySubject);
  2848.                                 }
  2849.                         }
  2850.                     break;
  2851.                 case OUTLINER_COLUMN_SENDERRECIPIENT:
  2852.                     if (isCommandEnabled(xfeCmdSortBySender))
  2853.                         {
  2854.                             if (m_outliner->getSortColumn() == data->column)
  2855.                                 m_outliner->toggleSortDirection();
  2856.                             doCommand(xfeCmdSortBySender);
  2857.                         }
  2858.                     break;
  2859.                 case OUTLINER_COLUMN_DATE:
  2860.                     if (isCommandEnabled(xfeCmdSortByDate))
  2861.                         {
  2862.                             if (m_outliner->getSortColumn() == data->column)
  2863.                                 m_outliner->toggleSortDirection();
  2864.                             doCommand(xfeCmdSortByDate);
  2865.                         }
  2866.                     break;
  2867.                 case OUTLINER_COLUMN_PRIORITY:
  2868.                     if (isCommandEnabled(xfeCmdSortByPriority))
  2869.                         {
  2870.                             if (m_outliner->getSortColumn() == data->column)
  2871.                                 m_outliner->toggleSortDirection();
  2872.                             doCommand(xfeCmdSortByPriority);
  2873.                         }
  2874.                     break;
  2875.                 case OUTLINER_COLUMN_STATUS:
  2876.                     if (isCommandEnabled(xfeCmdSortByStatus))
  2877.                         {
  2878.                             if (m_outliner->getSortColumn() == data->column)
  2879.                                 m_outliner->toggleSortDirection();
  2880.                             doCommand(xfeCmdSortByStatus);
  2881.                         }
  2882.                     break;
  2883.                 case OUTLINER_COLUMN_SIZE:
  2884.                     if (isCommandEnabled(xfeCmdSortBySize))
  2885.                         {
  2886.                             if (m_outliner->getSortColumn() == data->column)
  2887.                                 m_outliner->toggleSortDirection();
  2888.                             doCommand(xfeCmdSortBySize);
  2889.                         }
  2890.                     break;
  2891.                 case OUTLINER_COLUMN_UNREADMSG:
  2892.                     if (isCommandEnabled(xfeCmdSortByUnread))
  2893.                         {
  2894.                             if (m_outliner->getSortColumn() == data->column)
  2895.                                 m_outliner->toggleSortDirection();
  2896.                             doCommand(xfeCmdSortByUnread);
  2897.                         }
  2898.                     break;
  2899.                 case OUTLINER_COLUMN_FLAG:
  2900.                     if (isCommandEnabled(xfeCmdSortByFlag))
  2901.                         {
  2902.                             if (m_outliner->getSortColumn() == data->column)
  2903.                                 m_outliner->toggleSortDirection();
  2904.                             doCommand(xfeCmdSortByFlag);
  2905.                         }
  2906.                     break;
  2907.                 }
  2908.  
  2909.             m_outliner->getSelection(&selected, &count);
  2910.  
  2911.             if (count >= 1)
  2912.                 {
  2913.                     D(printf ("Making %d visible\n", selected[0]);)
  2914.                     m_outliner->makeVisible(selected[0]);
  2915.                 }
  2916.         }
  2917.     else  // content row.
  2918.         {
  2919.             if (data->clicks == 2)
  2920.                 {
  2921.                     m_outliner->selectItemExclusive(data->row);
  2922.                     
  2923.                     if ( m_displayingDraft )
  2924.                         {
  2925.                             MSG_OpenDraft(m_pane, m_folderInfo,
  2926.                                           MSG_GetMessageKey(m_pane, data->row));
  2927.                         }
  2928.                     else
  2929.                         {
  2930.                             // ok.  we're going to display a message in a message frame.
  2931.                             // what is left to determine is whether or not we will be
  2932.                             // popping up another window or reusing an existing one (if
  2933.                             // there is one.)  This behavior is governed by two things:
  2934.                             // 1.  fe_globalPrefs.reuse_msg_window and,
  2935.                             // 2.  data->alt (whether the alt key was down or not...)
  2936.                             
  2937.                             fe_showMsg(XtParent(getToplevel()->getBaseWidget()),
  2938.                                        ViewGlue_getFrame(m_contextData),
  2939.                                        (Chrome*)NULL,
  2940.                                        m_folderInfo,
  2941.                                        MSG_GetMessageKey(m_pane, data->row),
  2942.                                        
  2943.                                        (( fe_globalPrefs.reuse_msg_window
  2944.                                           && !data->shift)
  2945.                                         || (!fe_globalPrefs.reuse_msg_window
  2946.                                             && data->shift))
  2947.                                        );
  2948.                         }
  2949.                 }
  2950.             else if (data->clicks == 1)
  2951.                 {
  2952.                     const int *selected;
  2953.                     int count;
  2954.                             
  2955.                     m_outliner->getSelection(&selected, &count);
  2956. #if defined(DEBUG_tao)
  2957.                     printf("\n+++ data->clicks count=%d\n", count);
  2958. #endif
  2959.                     if (data->ctrl)
  2960.                         {
  2961.                             m_outliner->toggleSelected(data->row);
  2962.  
  2963.                             m_outliner->getSelection(&selected, &count);
  2964. #if defined(DEBUG_tao)
  2965.                             printf("\n+++ data->clicks count=%d\n", count);
  2966. #endif
  2967.                             if (count == 1)
  2968.                                 showMessage(selected[0]);
  2969.                             else if (count == 0 ||
  2970.                                      count > 1)
  2971.                                 showMessage(-1);
  2972.                                 
  2973.                         }
  2974.                     else if (data->shift)
  2975.                         {
  2976.                             // select the range.
  2977.                             
  2978.                             if (count == 0) /* there wasn't anything selected yet. */
  2979.                                 {
  2980.                                     m_outliner->selectItemExclusive(data->row);
  2981.                                     
  2982.                                     // clear the message area/label
  2983.                                     showMessage(-1);
  2984.                                 }
  2985.                             else if (count == 1) /* there was only one, so we select the range from
  2986.                                                     that item to the new one. */
  2987.                                 {
  2988.                                     m_outliner->selectRangeByIndices(selected[0], data->row);
  2989.                                     
  2990.                                     // clear the message area/label
  2991.                                     showMessage(-1);
  2992.                                 }
  2993.                             else /* we had a range of items selected, so let's do something really
  2994.                                     nice with them. */
  2995.                                 {
  2996.                                     m_outliner->trimOrExpandSelection(data->row);
  2997.                                     
  2998.                                     // clear the message area/label
  2999.                                     showMessage(-1);
  3000.                                 }
  3001.                         }
  3002.                     else
  3003.                         {      
  3004.                             // handle the columns that don't actually move the selection here
  3005.                             if (data->column == OUTLINER_COLUMN_UNREADMSG)
  3006.                                 {
  3007.                                     MSG_Command(m_pane, MSG_ToggleMessageRead, (MSG_ViewIndex*)&data->row, 1);
  3008.                                 }
  3009.                             else if (data->column == OUTLINER_COLUMN_FLAG)
  3010.                                 {
  3011.                                     MSG_MessageLine line;
  3012.                                     
  3013.                                     if (!MSG_GetThreadLineByIndex(m_pane, data->row, 1, &line))
  3014.                                         return;
  3015.                                     
  3016.                                     if (line.flags & MSG_FLAG_MARKED)
  3017.                                         MSG_Command(m_pane, MSG_UnmarkMessages, (MSG_ViewIndex*)&data->row, 1);
  3018.                                     else
  3019.                                         MSG_Command(m_pane, MSG_MarkMessages, (MSG_ViewIndex*)&data->row, 1);
  3020.                                 }
  3021.                             else
  3022.                                 {
  3023.                                     // we've selected a message, update the label and load it into
  3024.                                     // our message view.
  3025.                                     
  3026.                                     showMessage(data->row);
  3027.                                 }
  3028.                         }
  3029.                     
  3030.                     XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating,
  3031.                                                                getFolderInfo());
  3032.                 }
  3033.         }
  3034. }
  3035.  
  3036. void
  3037. XFE_ThreadView::Flippyfunc(const OutlineFlippyFuncData *data)
  3038. {
  3039.     int delta = MSG_ExpansionDelta(m_pane, data->row);
  3040.     XP_Bool need_to_select_top = FALSE;
  3041.  
  3042.     if (data->do_selection) // we do descendant selection
  3043.         {
  3044.             MSG_MessageLine line;
  3045.  
  3046.             if (delta > 0)
  3047.                 MSG_ToggleExpansion(m_pane, data->row, NULL);
  3048.             
  3049.             MSG_GetThreadLineByIndex(m_pane, data->row, 1, &line);
  3050.             
  3051.             m_outliner->deselectAllItems();
  3052.             m_outliner->selectRangeByIndices(data->row, data->row + line.numChildren);
  3053.             showMessage(-1);
  3054.         }
  3055.     else if (delta != 0) // actually to flippy stuff.
  3056.         {
  3057.             if (delta < 0)
  3058.                 {
  3059.                     if (delta == -1)
  3060.                         addCollapsed(data->row);
  3061.  
  3062.                     int i;
  3063.                     delta = -delta;
  3064.  
  3065.                     for (i = data->row + 1; i < data->row + 1 + delta; i ++)
  3066.                         {
  3067.                             if (m_outliner->isSelected(i))
  3068.                                 {
  3069.                                     need_to_select_top = TRUE;
  3070.                                     m_outliner->deselectItem(i);
  3071.                                 }
  3072.                         }
  3073.                 }
  3074.  
  3075.             MSG_ToggleExpansion(m_pane, data->row, NULL);
  3076.  
  3077.             if (need_to_select_top)
  3078.                 m_outliner->selectItem(data->row);
  3079.         }
  3080. }
  3081.  
  3082. XFE_CALLBACK_DEFN(XFE_ThreadView, spaceAtMsgEnd)(XFE_NotificationCenter*,
  3083.                          void *, void *)
  3084. {
  3085.     if (isCommandEnabled(xfeCmdNextUnreadMessage))
  3086.         doCommand(xfeCmdNextUnreadMessage);
  3087.     else if (isCommandEnabled(xfeCmdNextUnreadCollection))
  3088.         doCommand(xfeCmdNextUnreadCollection);
  3089. }
  3090.  
  3091. XFE_CALLBACK_DEFN(XFE_ThreadView, newMessageLoading)(XFE_NotificationCenter*,
  3092.                                                      void *, void*)
  3093. {
  3094.     if (m_commandPending == noPendingCommand)
  3095.         {
  3096.             MSG_FolderInfo *info = m_msgview->getFolderInfo();
  3097.             MessageKey key = m_msgview->getMessageKey();
  3098.             
  3099.             if (info != m_folderInfo)
  3100.                 {
  3101.                     m_commandPending = selectByKey;
  3102.                     m_pendingSelectionKey = key;
  3103.                     loadFolder(info);
  3104.                 }
  3105.             else
  3106.                 {
  3107.                     MSG_ViewIndex index = MSG_GetMessageIndexForKey(m_pane, 
  3108.                                                                     key, 
  3109.                                                                     False);
  3110.                     
  3111.                     int numLines = MSG_GetNumLines(m_pane);
  3112.                     if (m_outliner->getTotalLines() != numLines)
  3113.                         m_outliner->change(0, numLines, numLines);
  3114.  
  3115.                     m_outliner->makeVisible(index);
  3116.                     m_outliner->selectItemExclusive(index);
  3117.                     updateExpandoFlippyText(index);
  3118.                 }
  3119.                   notifyInterested(XFE_View::chromeNeedsUpdating);
  3120.         }
  3121. }
  3122.  
  3123. void
  3124. XFE_ThreadView::toggleMsgExpansion()
  3125. {
  3126.     int32 folder_prefs = 0;
  3127.  
  3128.     if (m_folderInfo)
  3129.         {
  3130.             folder_prefs = MSG_GetFolderPrefFlags(m_folderInfo);
  3131.             folder_prefs |= MSG_FOLDER_PREF_FEVALID;
  3132.         }
  3133.  
  3134.     if (m_msgExpanded)
  3135.         {
  3136.             // we are currently expanded
  3137.             Dimension message_pane_height;
  3138.             
  3139.             XtVaGetValues(m_msgview->getBaseWidget(),
  3140.                           XmNheight, &message_pane_height,
  3141.                           NULL);
  3142.             
  3143.             D(printf ("Saving message pane height as %d\n", message_pane_height);)
  3144.             PREF_SetIntPref(MESSAGEPANE_HEIGHT_PREF, (int32)message_pane_height);
  3145.  
  3146.             
  3147.             m_msgview->hide();
  3148.             
  3149.             m_msgExpanded = FALSE;
  3150.             // Set maximum heights so that the sash will go away:
  3151.             Dimension height;
  3152.             XtVaGetValues(m_arrowform,
  3153.                           XmNheight, &height,
  3154.                           NULL);
  3155.             XtVaSetValues(m_arrowform,
  3156.                           XmNpaneMinimum, height,
  3157.                           XmNpaneMaximum, height,
  3158.                           NULL);
  3159.             
  3160.             XtVaSetValues(m_arrowb, 
  3161.                           XmNarrowDirection, XmARROW_UP,
  3162.                           NULL);
  3163.             
  3164.             folder_prefs |= MSG_FOLDER_PREF_ONEPANE;
  3165.  
  3166.             notifyInterested(XFE_View::chromeNeedsUpdating);
  3167.         }
  3168.     else
  3169.         {
  3170.             const int *selected;
  3171.             int count;
  3172.             int32 message_pane_desired_height;
  3173.             Dimension message_pane_minimum_height;
  3174.             Dimension message_pane_resulting_height;
  3175.             Dimension panedw_spacing;
  3176.             Dimension panedw_marginheight;
  3177.             Dimension panedw_height;
  3178.             Dimension arrow_form_height;
  3179.             Dimension minimum_height_of_outliner;
  3180.             int resulting_height_of_outliner;
  3181.             XP_Bool need_to_resize_frame = False;
  3182.             
  3183.             // we are currently unexpanded
  3184.             XtVaSetValues(m_arrowb, 
  3185.                           XmNarrowDirection, XmARROW_DOWN,
  3186.                           NULL);
  3187.             
  3188.             XtVaGetValues(m_widget,
  3189.                           XmNspacing, &panedw_spacing,
  3190.                           XmNmarginHeight, &panedw_marginheight,
  3191.                           XmNheight, &panedw_height,
  3192.                           NULL);
  3193.             
  3194.             XtVaGetValues(m_arrowform,
  3195.                           XmNheight, &arrow_form_height,
  3196.                           NULL);
  3197.             
  3198.             XtVaGetValues(m_outliner->getBaseWidget(),
  3199.                           XmNpaneMinimum, &minimum_height_of_outliner,
  3200.                           NULL);
  3201.             
  3202.             XtVaGetValues(m_msgview->getBaseWidget(),
  3203.                           XmNpaneMinimum, &message_pane_minimum_height,
  3204.                           NULL);
  3205.             
  3206.             PREF_GetIntPref(MESSAGEPANE_HEIGHT_PREF, &message_pane_desired_height);
  3207.             
  3208.             D(printf ("Message pane wants to be %d high.\n", message_pane_desired_height);)
  3209.             
  3210.             resulting_height_of_outliner = (panedw_height
  3211.                                             - (2 * panedw_spacing) /* space between the outliner and arrow
  3212.                                                                       and between the arrow and message */
  3213.                                             - (2 * panedw_marginheight)
  3214.                                             - arrow_form_height
  3215.                                             - message_pane_desired_height);
  3216.             
  3217.             D(printf ("This will make the outliner %d high.\n", resulting_height_of_outliner);)
  3218.             
  3219.             if (resulting_height_of_outliner < (int)minimum_height_of_outliner)
  3220.                 {
  3221.                     D(printf ("  This is not ok.\n");)
  3222.                     resulting_height_of_outliner = minimum_height_of_outliner;
  3223.                     
  3224.                     message_pane_resulting_height = (message_pane_desired_height
  3225.                                                      - (minimum_height_of_outliner
  3226.                                                         - resulting_height_of_outliner));
  3227.                     
  3228.                     if (message_pane_resulting_height < message_pane_minimum_height)
  3229.                         {
  3230.                             message_pane_resulting_height = message_pane_minimum_height;
  3231.                             need_to_resize_frame = True;
  3232.                         }
  3233.                     
  3234.                     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");)
  3235.                 }
  3236.             
  3237.             if (need_to_resize_frame)
  3238.                 XtVaSetValues(getToplevel()->getBaseWidget(),
  3239.                               XmNallowShellResize, True,
  3240.                               NULL);
  3241.  
  3242.             XtVaSetValues(m_msgview->getBaseWidget(),
  3243.                           XmNskipAdjust, TRUE,
  3244.                           NULL);
  3245.             
  3246.             m_msgview->show();
  3247.  
  3248.             XtVaSetValues(m_msgview->getBaseWidget(),
  3249.                           XmNskipAdjust, FALSE,
  3250.                           XmNpaneMinimum, PANE_MIN,
  3251.                           XmNpaneMaximum, PANE_MAX,
  3252.                           NULL);
  3253.  
  3254.             if (need_to_resize_frame)
  3255.                 XtVaSetValues(getToplevel()->getBaseWidget(),
  3256.                               XmNallowShellResize, False,
  3257.                               NULL);
  3258.             
  3259.             XtVaSetValues(m_outliner->getBaseWidget(),
  3260.                           XmNpaneMinimum, PANE_MIN,
  3261.                           XmNpaneMaximum, PANE_MAX,
  3262.                           NULL);
  3263.  
  3264.             m_msgExpanded = TRUE;
  3265.             
  3266.             folder_prefs &= ~MSG_FOLDER_PREF_ONEPANE;
  3267.  
  3268.             m_outliner->getSelection(&selected, &count);
  3269.             
  3270.             if (count == 1)
  3271.                 showMessage(selected[0]);
  3272.             else
  3273.                 showMessage(-1);
  3274.     
  3275.             XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating, getFolderInfo());
  3276.         }
  3277.  
  3278.     if (m_folderInfo)
  3279.         MSG_SetFolderPrefFlags(m_folderInfo, folder_prefs);
  3280. }
  3281.  
  3282. void
  3283. XFE_ThreadView::toggleMsgExpansionCallback(Widget, XtPointer clientData, XtPointer)
  3284. {
  3285.   XFE_ThreadView *obj = (XFE_ThreadView*)clientData;
  3286.  
  3287.   obj->toggleMsgExpansion();
  3288. }
  3289.  
  3290. #if !defined(USE_MOTIF_DND)
  3291. void
  3292. XFE_ThreadView::sourcedropfunc(fe_dnd_Source */*source*/, fe_dnd_Message msg, void *closure)
  3293. {
  3294.       MSG_FolderInfo *info = (MSG_FolderInfo*)closure;
  3295.  
  3296.       // messages can be copied or moved.  The closure to this function will always
  3297.       // be a MSG_FolderInfo*.
  3298.       
  3299.       // XXX assume that nothing could have changed the selected between the time
  3300.       // we started dragging and now...  don't know how smart this is...
  3301.       
  3302.       const char *name = MSG_GetFolderNameFromID(info);
  3303.       const int *indices;
  3304.       int count;
  3305.       
  3306.       m_outliner->getSelection(&indices, &count);
  3307.       
  3308.       /* New Code to take on the new Drag and Drop APIs with effect for both mail/news. However,
  3309.        the effect checking on news articles are not completed in BE yet.  Coredump will
  3310.      be encountered when filing news articles. */
  3311.  
  3312.       if (msg == FE_DND_MESSAGE_DELETE)
  3313.           {
  3314.               // delete the messages.
  3315.           }
  3316.       else 
  3317.     {
  3318.  
  3319.               MSG_DragEffect requireEffect = MSG_Default_Drag;
  3320.  
  3321.               MSG_DragEffect effect =
  3322.                     MSG_DragMessagesIntoFolderStatus(m_pane, 
  3323.                     (MSG_ViewIndex*)indices, count,
  3324.                     info, requireEffect);
  3325.  
  3326.               if (effect == MSG_Require_Move ) 
  3327.         {
  3328.             if (msg == FE_DND_MESSAGE_COPY )
  3329.             {
  3330.                   DD(printf("### ThreadView::sourcedropfunc(req MOVE): FE_DND_MESSAGE_COPY To \n");)
  3331.                   MSG_CopyMessagesInto(m_pane, (MSG_ViewIndex*)indices, count, name);
  3332.             }
  3333.             else
  3334.                   {
  3335.                   DD(printf("### ThreadView::sourcedropfunc(req MOVE): FE_DND_MESSAGE_MOVE To \n");)
  3336.                   MSG_MoveMessagesInto(m_pane, (MSG_ViewIndex*)indices, count, name);
  3337.                   }
  3338.         }
  3339.         else if ( effect == MSG_Require_Copy )
  3340.         {
  3341.               DD(printf("### ThreadView::sourcedropfunc(req COPY): FE_DND_MESSAGE_COPY To \n");)
  3342.             MSG_CopyMessagesInto(m_pane, (MSG_ViewIndex*)indices, count, name);
  3343.         }
  3344.         else if ( effect == MSG_Drag_Not_Allowed )
  3345.         {
  3346.               DD(printf("### ThreadView::sourcedropfunc: Not Allowed \n");)
  3347.             char tmp[128];
  3348.                         XP_SAFE_SPRINTF(tmp, sizeof(tmp),
  3349.                                         "%s",
  3350.                     XP_GetString(XFE_DND_MESSAGE_ERROR));
  3351.             XFE_Progress (m_contextData, tmp);
  3352.  
  3353.         }
  3354.         else /* should not reach here. the effect status should be with in
  3355.             the defined range. Please double check if you try to refer
  3356.             to any enum outside the effect enum scope */
  3357.             XP_ASSERT(0);
  3358.     }
  3359.  
  3360.   /* now we need to modify the chrome of windows viewing either folder */
  3361.   XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating, m_folderInfo);
  3362.   XFE_MozillaApp::theApp()->notifyInterested(XFE_MNView::folderChromeNeedsUpdating, info);
  3363. }
  3364.  
  3365. void
  3366. XFE_ThreadView::source_drop_func(fe_dnd_Source *src, fe_dnd_Message msg, void *closure)
  3367. {
  3368.   XFE_ThreadView *obj = (XFE_ThreadView*)src->closure;
  3369.  
  3370.   obj->sourcedropfunc(src, msg, closure);
  3371. }
  3372.  
  3373. void
  3374. XFE_ThreadView::dropfunc(Widget /*dropw*/, fe_dnd_Event type,
  3375.              fe_dnd_Source *source, XEvent *event)
  3376. {
  3377.   m_outliner->handleDragEvent(event, type, source);
  3378. }
  3379.  
  3380. void
  3381. XFE_ThreadView::drop_func(Widget dropw, void *closure, fe_dnd_Event type,
  3382.               fe_dnd_Source *source, XEvent* event)
  3383. {
  3384.   XFE_ThreadView *obj = (XFE_ThreadView*)closure;
  3385.  
  3386.   obj->dropfunc(dropw, type, source, event);
  3387. }
  3388. #endif /* USE_MOTIF_DND */
  3389.  
  3390. void
  3391. XFE_ThreadView::openWithKey(MessageKey key )
  3392. {
  3393.   m_commandPending = selectByKey;
  3394.   m_pendingSelectionKey = key;
  3395. }
  3396.  
  3397. #if defined(USE_MOTIF_DND)
  3398. fe_icon_data *
  3399. XFE_ThreadView::GetDragIconData(int row, int /*column*/)
  3400. {
  3401.   D(printf("XFE_ThreadView::GetDragIconData()\n");)
  3402.   
  3403.   if (row == -1) return &MN_MailRead;
  3404.   else
  3405.     {
  3406.       MSG_FolderLine folderLine;
  3407.       int flags = m_messageLine.flags;
  3408.  
  3409.       MSG_GetFolderLineById(XFE_MNView::getMaster(), m_folderInfo, &folderLine);
  3410.  
  3411.       acquireLineData(row);
  3412.       flags = m_messageLine.flags;
  3413.       releaseLineData();
  3414.  
  3415.       return flagToIconData(folderLine.flags, flags);
  3416.     }
  3417. }
  3418.  
  3419. fe_icon_data *
  3420. XFE_ThreadView::getDragIconData(void *this_ptr,
  3421.                                 int row,
  3422.                                 int column)
  3423. {
  3424.   D(printf("XFE_ThreadView::getDragIconData()\n");)
  3425.   XFE_ThreadView *thread_view = (XFE_ThreadView*)this_ptr;
  3426.  
  3427.   return thread_view->GetDragIconData(row, column);
  3428. }
  3429.  
  3430. void
  3431. XFE_ThreadView::GetDragTargets(int row, int column,
  3432.                                Atom **targets,
  3433.                                int *num_targets)
  3434. {
  3435.   D(printf("XFE_ThreadView::GetDragTargets()\n");)
  3436.  
  3437.   int flags;
  3438.  
  3439.   XP_ASSERT(row > -1);
  3440.   if (row == -1)
  3441.     {
  3442.       *targets = NULL;
  3443.       *num_targets = 0;
  3444.     }
  3445.   else
  3446.     {
  3447.       acquireLineData(row);
  3448.       flags = m_messageLine.flags;
  3449.       releaseLineData();
  3450.       
  3451.       *num_targets = 5;
  3452.       *targets = new Atom[ *num_targets ];
  3453.  
  3454.       (*targets)[1] = XFE_DragBase::_XA_NETSCAPE_URL;
  3455.       (*targets)[2] = XA_STRING;
  3456.  
  3457.       if (isDisplayingNews())
  3458.         (*targets)[0] = XFE_OutlinerDrop::_XA_NETSCAPE_NEWS_MESSAGE;
  3459.       else
  3460.         (*targets)[0] = XFE_OutlinerDrop::_XA_NETSCAPE_MAIL_MESSAGE;
  3461.     }
  3462. }
  3463.  
  3464. void
  3465. XFE_ThreadView::getDragTargets(void *this_ptr,
  3466.                                int row,
  3467.                                int column,
  3468.                                Atom **targets,
  3469.                                int *num_targets)
  3470. {
  3471.   D(printf("XFE_ThreadView::getDragTargets()\n");)
  3472.   XFE_ThreadView *thread_view = (XFE_ThreadView*)this_ptr;
  3473.  
  3474.  thread_view->GetDragTargets(row, column, targets, num_targets);
  3475. }
  3476.  
  3477. char *
  3478. XFE_ThreadView::DragConvert(Atom atom)
  3479. {
  3480.   if (atom == XFE_DragBase::_XA_NETSCAPE_URL)
  3481.     {
  3482.       // translate drag data to NetscapeURL format
  3483.       XFE_URLDesktopType urlData;
  3484.       char *result;
  3485.       const int *selection;
  3486.       int count;
  3487.       int i;
  3488.  
  3489.       m_outliner->getSelection(&selection, &count);
  3490.  
  3491.       urlData.createItemList(count);
  3492.  
  3493.       for (i = 0; i < count; i ++)
  3494.         {
  3495.           MessageKey key = MSG_GetMessageKey(m_pane, selection[i]);
  3496.           URL_Struct *url = MSG_ConstructUrlForMessage(m_pane,
  3497.                                                        key);
  3498.           urlData.url(i,url->address);
  3499.  
  3500.           NET_FreeURLStruct(url);
  3501.         }
  3502.  
  3503.       result = XtNewString(urlData.getString());
  3504.       
  3505.       return result;
  3506.     }
  3507.   else if (atom == XFE_OutlinerDrop::_XA_NETSCAPE_MAIL_MESSAGE
  3508.            || atom == XFE_OutlinerDrop::_XA_NETSCAPE_NEWS_MESSAGE)
  3509.     {
  3510.       char result[100];
  3511.       const int *selection;
  3512.       int count;
  3513.  
  3514.       m_outliner->getSelection(&selection, &count);
  3515.  
  3516.       if (count < 1) return XtNewString("0"); /* XXX ? */
  3517.  
  3518.       sprintf (result, "%d", selection[0]);
  3519.       return (char*)XtNewString(result); /* XXX fixme */
  3520.     }
  3521.   else if (atom == XA_STRING)
  3522.     {
  3523. #if notyet
  3524.       char *result;
  3525.       URL_Struct *url = MSG_ConstructUrlForMessage(m_pane,
  3526.                                                    m_dragmessage);
  3527.  
  3528.  
  3529.       result = XtNewString(url->address);
  3530.  
  3531.       NET_FreeURLStruct(url);
  3532.  
  3533.       return result;
  3534. #endif
  3535.     }
  3536. }
  3537.  
  3538. char *
  3539. XFE_ThreadView::dragConvert(void *this_ptr,
  3540.                             Atom atom)
  3541. {
  3542.   XFE_ThreadView *thread_view = (XFE_ThreadView*)this_ptr;
  3543.   
  3544.   return thread_view->DragConvert(atom);
  3545. }
  3546. #endif /* USE_MOTIF_DND */
  3547.  
  3548. void
  3549. XFE_ThreadView::selectThread()
  3550. {
  3551.   const int *selected;
  3552.   int i,count;
  3553.   MessageKey *keys;
  3554.  
  3555.   m_outliner->getSelection(&selected, &count);
  3556.  
  3557.   if ( count <= 0 ) return;
  3558.   keys = new MessageKey[count];
  3559.  
  3560.   for ( i = 0; i < count ; i++ )
  3561.   {
  3562.         keys[i] = MSG_GetMessageKey(m_pane, selected[i]);
  3563.  
  3564.   }
  3565.   m_outliner->deselectAllItems();
  3566.  
  3567.   for ( i = 0; i < count; i++ )
  3568.   {
  3569.         MSG_ViewIndex index = MSG_ThreadIndexOfMsg( m_pane, keys[ i ] );
  3570.         int delta = MSG_ExpansionDelta(m_pane, index);
  3571.         if ( delta > 0 )
  3572.                 MSG_ToggleExpansion(m_pane, index, NULL);
  3573.         else
  3574.                 delta = -delta;
  3575.         m_outliner->selectRangeByIndices(index, index+delta);
  3576.   }
  3577.   delete[] keys;
  3578.  
  3579.   showMessage(-1);
  3580. }
  3581.