home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / src / AddressOutliner.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  54.9 KB  |  1,971 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. AddressOutliner.cpp -- Object wrapper around outline widget hack.
  20.    Created: Dora Hsu <dora@netscape.com>, Sept-30-96.
  21. */
  22.  
  23.  
  24.  
  25. #include "AddressOutliner.h"
  26. #include "addrbook.h"
  27.  
  28. #include "xp_core.h"
  29. #include "ComposeView.h"
  30. #include "ComposeFolderView.h"
  31. #include "AddressFolderView.h"
  32. #include "PopupMenu.h"
  33.  
  34. #include "xfe.h"
  35.  
  36. #include <Xfe/Xfe.h>
  37.  
  38. #include <Xm/TextF.h>
  39. #include "felocale.h"
  40. extern XtAppContext fe_XtAppContext;
  41.  
  42. #ifdef DEBUG_dora
  43. #define XDEBUG(x) x
  44. #else
  45. #define XDEBUG(x)
  46. #endif
  47.  
  48. extern int MSG_TotalHeaderCount();
  49. extern MSG_HEADER_SET MSG_HeaderValue( int pos );
  50.  
  51. extern "C"
  52. {
  53.  
  54. #include "addrbk.h"
  55.  
  56. XP_List* FE_GetDirServers();
  57. ABook*   fe_GetABook(MWContext *context);
  58.  
  59. static void KeyIn(
  60.     Widget w,
  61.          XEvent *event,
  62.          String *params,
  63.          Cardinal *nparam);
  64.  
  65. static void TableTraverse(
  66.     Widget w,
  67.          XEvent *event,
  68.          String *params,
  69.          Cardinal *nparam);
  70.  
  71. static void FieldTraverse(
  72.     Widget w,
  73.          XEvent *event,
  74.          String *params,
  75.          Cardinal *nparam);
  76. }
  77.  
  78. extern "C" char * xfe_ExpandForNameCompletion(char * pString);
  79. extern "C" char * xfe_ExpandName(char *pString);
  80.  
  81. const char *XFE_AddressOutliner::textFocusIn = "XFE_AddressOutliner::textFocusIn";
  82. const char *XFE_AddressOutliner::typeFocusIn = "XFE_AddressOutliner::typeFocusIn";
  83. const char *XFE_AddressOutliner::tabPrev = "XFE_AddressOutliner::tabPrev";
  84. const char *XFE_AddressOutliner::tabNext = "XFE_AddressOutliner::tabNext";
  85.  
  86. // Customized Traversal Actions
  87.  
  88. static XtActionsRec actions[] =
  89. { {"TableTraverse",     TableTraverse     },
  90.   {"FieldTraverse",     FieldTraverse     },
  91.   {"KeyIn",         KeyIn     }};
  92.  
  93. // XFE_AddressOutliner Constructor -----------------------------------------
  94.  
  95. XFE_AddressOutliner::XFE_AddressOutliner(
  96.         const char *name,
  97.         XFE_MNListView *parent_view,
  98.         MAddressable *addressable_view,
  99.         Widget widget_parent,
  100.         Boolean constantSize,
  101.         int numcolumns,
  102.         int *column_widths,
  103.         char *pos_prefname) :
  104.      XFE_Outliner(name, parent_view, parent_view->getToplevel(), 
  105.         widget_parent,
  106.             constantSize, False,
  107.             numcolumns, numcolumns, column_widths, pos_prefname )
  108. {
  109.   Widget baseWidget;
  110.   XmFontList fontList;
  111.   Pixel fg, bg;
  112.   EventMask event_mask =  FocusChangeMask|ButtonPressMask | ButtonReleaseMask;
  113.  
  114.   m_displayrows = 4; /* same default number of rows as windows */
  115.   m_parentView = parent_view;
  116.   m_addressable = addressable_view;
  117.   m_popup = NULL;
  118.   m_focusRow = 0;
  119.   m_focusCol = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
  120.   m_cursorPos = 0;
  121.   m_inPopup = False;
  122.   m_lastFocus = NULL; /* Obselete ?! - dh */
  123.   m_textTimer = 0;
  124.  
  125.   // Add actions
  126.   XtAppAddActions( fe_XtAppContext, actions,  3);
  127.  
  128.   XtVaGetValues(m_widget, XmNfontList, &fontList,  
  129.         XmNforeground, &fg,
  130.         XmNbackground, &bg, 0 );
  131.  
  132.   m_typeWidget = XtVaCreateWidget("addressText", 
  133.             xmTextFieldWidgetClass, m_widget,
  134.             XmNfontList, fontList,
  135.             XmNforeground, fg,    
  136.             XmNbackground, bg,    
  137.             XmNuserData, this,
  138.             XmNcursorPositionVisible, False,
  139.             XmNeditable, False,
  140.             XmNmarginHeight, 0,
  141.                         XmNmarginWidth, 3,
  142.                         XmNshadowThickness, 0,
  143.                         XmNhighlightThickness, 2,
  144.                         XmNx, 0,
  145.                         XmNy, 0,
  146.                         XmNwidth, 40,
  147.                         XmNheight, 40,
  148.             0 );
  149.   XmDropSiteUnregister(m_typeWidget); // prevent conflict with attachment dropsite
  150.   
  151.   m_textWidget = XtVaCreateWidget("addressText", 
  152.             xmTextFieldWidgetClass, m_widget,
  153.             XmNblinkRate, 200,
  154.             XmNcursorPositionVisible, True,
  155.             XmNtraversalOn, True,
  156.             XmNeditable, True,
  157.             XmNforeground, fg,    
  158.             XmNbackground, bg,    
  159.             XmNfontList, fontList,
  160.             XmNuserData, this,
  161.             XmNmarginHeight, 0,
  162.                         XmNmarginWidth, 3,
  163.                         XmNshadowThickness, 0,
  164.                         XmNhighlightThickness, 2,
  165.                         XmNx, 0,
  166.                         XmNy, 0,
  167.                         XmNwidth, 40,
  168.                         XmNheight, 40,
  169.             0);
  170.   XtVaSetValues(m_widget,
  171.         XmNuserData, this,
  172.         XmNhighlightRowMode, False,
  173.         XmNselectionPolicy, XmSELECT_NONE,
  174.                 XmNvisibleRows, m_displayrows,
  175.         XmNcellMarginLeft, 1,
  176.         XmNcellMarginRight, 1,
  177.                 XmNcellRightBorderType, XmBORDER_DASH,
  178.                 XmNcellBottomBorderType, XmBORDER_DASH,
  179.                 XtVaTypedArg, XmNcellBackground, XmRString, "white", 6,
  180.                 XtVaTypedArg, XmNcellRightBorderColor, XmRString, "Gray60", 7,
  181.                 XtVaTypedArg, XmNcellBottomBorderColor, XmRString, "Gray60", 7,
  182.                 XmNcellDefaults, True,
  183.                 XmNcellAlignment, XmALIGNMENT_LEFT,
  184.                 0);
  185.   XmDropSiteUnregister(m_textWidget); // prevent conflict with attachment dropsite
  186.  
  187.   XmProcessTraversal(m_widget, XmTRAVERSE_CURRENT);
  188.   int total = 0;
  189.  
  190.   if (m_addressable) 
  191.     total =  ((XFE_AddressFolderView*)m_addressable)->getTotalData();
  192.  
  193.   change(0,0 ,total+1 );
  194.  
  195.   //MapText(0);
  196.  
  197.   getToplevel()->registerInterest(XFE_Component::afterRealizeCallback,
  198.              this,
  199.              (XFE_FunctionNotification)afterRealizeWidget_cb); 
  200.   // Translations will be installed in the afterRealize routine,
  201.   // so that they will override XFE_Frame::hackTranslations.
  202.  
  203.   baseWidget = m_parentView->getParent()->getBaseWidget();
  204.  
  205.   XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
  206.  
  207.   XtAddCallback(m_widget, XmNscrollCallback, scrollCallback, this);
  208.   XtAddCallback(m_textWidget, XmNactivateCallback, textActivateCallback, this);
  209.  
  210.   XtAddCallback(m_typeWidget, XmNfocusCallback, typeFocusCallback, this);
  211.   XtAddCallback(m_textWidget, XmNfocusCallback, textFocusCallback, this);
  212.  
  213.   XtAddCallback(m_typeWidget, XmNlosingFocusCallback, textLosingFocusCallback, this);
  214.   XtAddCallback(m_textWidget, XmNlosingFocusCallback, textLosingFocusCallback, this);
  215.   XtAddCallback(m_textWidget, XmNmodifyVerifyCallback, textModifyCallback, this);
  216.  
  217.   // Insert our own event handler to the head of the list
  218.   // XFE_Component::m_widget is the grid widget
  219.   XtInsertEventHandler(m_widget,
  220.                        event_mask,
  221.                     False,
  222.                     eventHandler, this, XtListHead);
  223.   // Add Interests
  224.  
  225.   m_parentView->getToplevel()->registerInterest(XFE_AddressFolderView::tabNext, this,
  226.     (XFE_FunctionNotification)tabToGrid_cb);
  227.  
  228.   m_parentView->getParent()->getToplevel()->registerInterest(XFE_ComposeView::tabBeforeSubject, this,
  229.     (XFE_FunctionNotification)tabToGrid_cb);
  230.  
  231.   setMultiSelectAllowed(True);
  232.   m_firstSelected = -1;
  233.   m_lastSelected = -1;
  234. }
  235.  
  236. // Default Constructor
  237. XFE_AddressOutliner::XFE_AddressOutliner()
  238. {
  239. }
  240.  
  241. // Destructor
  242. XFE_AddressOutliner::~XFE_AddressOutliner()
  243. {
  244. }
  245.  
  246. // Install local translations -- this needs to be after realize time,
  247. // otherwise uparrow and downarrow will be overridden by XFE_Frame.
  248. XFE_CALLBACK_DEFN(XFE_AddressOutliner,
  249.                   afterRealizeWidget)(XFE_NotificationCenter *, void *, void*)
  250. {
  251.   XtOverrideTranslations(m_textWidget, fe_globalData.editing_translations);
  252.   XtOverrideTranslations(m_textWidget, fe_globalData.single_line_editing_translations);
  253.   XtOverrideTranslations(m_textWidget, fe_globalData.address_outliner_traverse_translations);
  254.  
  255.   XtOverrideTranslations(m_typeWidget, fe_globalData.address_outliner_key_translations);
  256.  
  257.   // shift focus to the first text field in the outliner if we
  258.   // don't already have a recipient:
  259.   Boolean has_recip = False;
  260.  
  261.   // Only "To" or "Newsgroup" counts as recipient (not Bcc, Reply-To, etc.)
  262.   int total = getTotalLines();
  263.   int i;
  264.   for (i=0; i<total; ++i)
  265.   {
  266.       char* type = GetCellValue(i,
  267.                          XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE);
  268.       if (type && (!XP_STRCMP(type, "To:") || !XP_STRCMP(type, "Newsgroup:")))
  269.       {
  270.           has_recip = True;
  271.           delete [] type;
  272.           break;
  273.       }
  274.       if (type)
  275.           delete [] type;
  276.   }
  277.   m_focusRow = total-1;
  278.  
  279.   if (!has_recip)
  280.   {
  281.       m_focusCol = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
  282.       PlaceText(m_focusRow, m_focusCol);
  283.       // PlaceText() is supposed to set the focus into the current field,
  284.       // but it doesn't always.  We need to be sure:
  285.       XmLGridSetFocus(m_widget, m_focusRow, m_focusCol);
  286.   }
  287. }
  288.  
  289. // Popup callback (for To: Cc: Followup: etc)
  290. void
  291. XFE_AddressOutliner::popupCallback(Widget w, XtPointer clientData, XtPointer)
  292. {
  293.     XFE_AddressOutliner *    obj = (XFE_AddressOutliner*) clientData;
  294.     XmString                xmstr;
  295.  
  296.     XtVaGetValues(w,XmNlabelString,&xmstr,NULL);
  297.  
  298.     if (xmstr)
  299.     {
  300.         String str = NULL;
  301.  
  302.         XmStringGetLtoR(xmstr,XmFONTLIST_DEFAULT_TAG,&str);
  303.  
  304.         if (str)
  305.         {
  306.             obj->selectedMenu(str);
  307.  
  308.             XtFree(str);
  309.         }
  310.         
  311.         XmStringFree(xmstr);
  312.     }
  313. }
  314.  
  315. // Static Methods for traverse actions
  316. void 
  317. XFE_AddressOutliner::fieldTraverse(
  318.     Widget    /*w*/,
  319.         XEvent*   /*event*/,
  320.         String*   /*params*/,
  321.         Cardinal* /*nparam*/)
  322. {
  323.    //XmLGridGetFocus(m_widget, &row, &col, &focus);
  324.    PlaceText(m_focusRow,m_focusCol);
  325.    if ( XtIsManaged(m_textWidget) )
  326.        XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
  327.    else if (XtIsManaged(m_typeWidget) )
  328.        XmProcessTraversal(m_typeWidget, XmTRAVERSE_CURRENT);
  329. }
  330.  
  331.  
  332. void 
  333. XFE_AddressOutliner::keyIn(
  334.         Widget /*w*/,
  335.         XEvent * /*event*/,
  336.         String *params,
  337.         Cardinal *nparam)
  338. {
  339.    XrmQuark q;
  340.    static int keyIn_quarksValid = 0;
  341.    static XrmQuark qTo, qReply, qNewsgroup, qFollowup, qCc, qBcc;
  342.  
  343.    int row, col;
  344.    Widget grid;
  345.    grid = m_widget;
  346.  
  347.    if (*nparam != 1)
  348.                 return;
  349.     if (!keyIn_quarksValid)
  350.     {
  351.         qTo = XrmStringToQuark(XFE_AddressFolderView::TO);
  352.         qReply = XrmStringToQuark(XFE_AddressFolderView::REPLY);
  353.         qFollowup = XrmStringToQuark(XFE_AddressFolderView::FOLLOWUP);
  354.         qNewsgroup = XrmStringToQuark(XFE_AddressFolderView::NEWSGROUP);
  355.         qCc = XrmStringToQuark(XFE_AddressFolderView::CC);
  356.         qBcc = XrmStringToQuark(XFE_AddressFolderView::BCC);
  357.         keyIn_quarksValid = 1;
  358.  
  359.     }
  360.  
  361.     q = XrmStringToQuark(params[0] );
  362.  
  363.     col = m_focusCol;
  364.     row = m_focusRow;
  365.  
  366.     if (col== XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT ) 
  367.          col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE;
  368.  
  369.     if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE )
  370.     {
  371.         if ( q == qTo )
  372.         {
  373.                XDEBUG(printf("*KEY IN TO * invalidate Line caused by %d\n", row);)
  374.                setTypeHeader(row, MSG_TO_HEADER_MASK);
  375.         }
  376.         else if ( q == qReply)
  377.         {
  378.                XDEBUG(printf("*KEY IN Reply * invalidate Line caused by %d\n", row);)
  379.                setTypeHeader(row, MSG_REPLY_TO_HEADER_MASK);
  380.         }
  381.         else if ( q == qNewsgroup)
  382.         {
  383.                XDEBUG(printf("*KEY IN Newsgroup * invalidate Line caused by %d\n", row);)
  384.                setTypeHeader(row, MSG_NEWSGROUPS_HEADER_MASK);
  385.         }
  386.         else if ( q == qFollowup)
  387.         {
  388.                XDEBUG(printf("*KEY IN Followup * invalidate Line caused by %d\n", row);)
  389.                setTypeHeader(row, MSG_FOLLOWUP_TO_HEADER_MASK);
  390.         }
  391.         else if (q == qCc)
  392.         {
  393.                XDEBUG(printf("*KEY IN CC * invalidate Line caused by %d\n", row);)
  394.                setTypeHeader(row, MSG_CC_HEADER_MASK);
  395.         }
  396.         else if ( q == qBcc)
  397.         {
  398.                XDEBUG(printf("*KEY IN BCC * invalidate Line caused by %d\n", row);)
  399.                setTypeHeader(row, MSG_BCC_HEADER_MASK);
  400.         }
  401.         else
  402.         {
  403.                XDEBUG(printf("*Invalide Key In value at %d\n", row);)
  404.             XP_ASSERT(0);
  405.         }
  406.     } /* COLUMN_TYPE */
  407. }
  408.  
  409. void 
  410. XFE_AddressOutliner::tableTraverse(
  411.     Widget /*w*/,
  412.         XEvent *  event,
  413.         String *  params,
  414.         Cardinal* nparam)
  415.  
  416. {
  417.    XrmQuark q;
  418.    static int quarksValid = 0;
  419.    static XrmQuark qLEFT, qRIGHT;
  420.    static XrmQuark qINSERT, qDELETE, qBACKSPACE;
  421.    static XrmQuark qNEXT, qPREVIOUS;
  422.    static XrmQuark qHOME, qEND, qUP, qDOWN;
  423.  
  424.    Widget grid;
  425.    int row, col;
  426.    grid = m_widget;
  427.  
  428.    if (*nparam != 1)
  429.                 return;
  430.     if (!quarksValid)
  431.     {
  432.         qINSERT = XrmStringToQuark("INSERT");
  433.         qDELETE = XrmStringToQuark("DELETE");
  434.         qBACKSPACE = XrmStringToQuark("BACKSPACE");
  435.         qEND = XrmStringToQuark("END");
  436.         qHOME = XrmStringToQuark("HOME");
  437.         qUP = XrmStringToQuark("UP");
  438.         qDOWN = XrmStringToQuark("DOWN");
  439.         qLEFT = XrmStringToQuark("LEFT");
  440.         qRIGHT = XrmStringToQuark("RIGHT");
  441.         qNEXT = XrmStringToQuark("NEXT");
  442.         qPREVIOUS = XrmStringToQuark("PREVIOUS");
  443.     quarksValid = 1;
  444.  
  445.     }
  446.     q = XrmStringToQuark(params[0] );
  447.  
  448.    row = m_focusRow;
  449.    col = m_focusCol;
  450.  
  451.  
  452.     if ( q == qINSERT)
  453.             doInsert( row,col);
  454.     else if ( q == qDELETE )
  455.               doDelete(row, col, event);
  456.     else if ( q == qBACKSPACE )
  457.               doBackSpace(row, col, event);
  458.     else if ( q == qEND)
  459.             doEnd(row, col);
  460.     else if ( q == qHOME)
  461.             doHome(row, col);
  462.     else if ( q == qUP )
  463.             doUp(row, col);
  464.     else if ( q == qDOWN )
  465.             doDown(row, col);
  466.     else if ( q == qLEFT )
  467.             doLeft(row, col);
  468.     else if ( q == qRIGHT)
  469.             doRight(row, col);
  470.     else if ( q == qNEXT)
  471.             doNext(row, col);
  472.     else if ( q == qPREVIOUS)
  473.             doPrevious(row, col);
  474.     else
  475.             XP_ASSERT(0);
  476. }
  477.  
  478. void
  479. XFE_AddressOutliner::selectedMenu(char *name)
  480. {
  481.    static Cardinal num = 1;
  482.    char *keyInStr = NULL;
  483.  
  484.    m_inPopup= False;
  485.    if ( name[0] == 'T')
  486.    {
  487.     keyInStr = XP_STRDUP(XFE_AddressFolderView::TO);
  488.    }
  489.    else if ( name[0] == 'C')
  490.    {
  491.     keyInStr = XP_STRDUP(XFE_AddressFolderView::CC);
  492.    }
  493.    else if ( name[0] == 'B')
  494.    {
  495.     keyInStr = XP_STRDUP(XFE_AddressFolderView::BCC);
  496.    }
  497.    else if ( name[0] == 'R' )
  498.    {
  499.     keyInStr = XP_STRDUP(XFE_AddressFolderView::REPLY);
  500.    }
  501.    else if ( name[0] == 'N' )
  502.    {
  503.     keyInStr = XP_STRDUP(XFE_AddressFolderView::NEWSGROUP);
  504.    }
  505.    else if ( name[0] == 'F' )
  506.    {
  507.     keyInStr = XP_STRDUP(XFE_AddressFolderView::FOLLOWUP);
  508.    }
  509.    else XP_ASSERT(0);
  510.  
  511.    keyIn(m_typeWidget, NULL, &keyInStr, &num);
  512.    XP_FREE(keyInStr);
  513.  
  514.    // Make sure the popup menu is not posted
  515.    if (XfeIsAlive(m_popup))
  516.    {
  517.        XtUnmanageChild(m_popup);
  518.    }
  519.  
  520.    XtAddCallback(m_typeWidget, 
  521.         XmNlosingFocusCallback, textLosingFocusCallback, this);
  522. }
  523.  
  524. // XFE_AddressOutliner ---------- Protected ---------------------
  525.  
  526. // NONE 
  527.  
  528. // XFE_AddressOutliner ---------- Private ---------------------
  529.  
  530.  
  531. void
  532. XFE_AddressOutliner::MapText(int row)
  533. {
  534.   int total;
  535.  
  536.   total = getTotalLines();
  537.  
  538.   if ( row >= total )
  539.     change(row, total,total+1 );
  540.  
  541.   PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT, False);
  542. }
  543.  
  544. void 
  545. XFE_AddressOutliner::PlaceText(int row, int col, Boolean doUpdate)
  546. {
  547.   XRectangle rect;
  548.   Boolean removed = False;
  549.  
  550.  
  551.   //XtVaGetValues(m_textWidget, XmNcursorPosition, &cursorPos, 0);
  552.  
  553.   if( XtIsManaged(m_textWidget) &&  doUpdate ) {
  554.     (void) updateAddresses();
  555.  
  556.   XtRemoveCallback(m_textWidget, 
  557.         XmNlosingFocusCallback, textLosingFocusCallback, this);
  558.   removed = True;
  559.   }
  560.   if ( XtIsManaged(m_textWidget) ) XtUnmanageChild(m_textWidget);
  561.  
  562.   if ( XtIsManaged(m_typeWidget) ) XtUnmanageChild(m_typeWidget);
  563.  
  564.   // UPDATE FOCUS CELL CURSOR POSITION & ROW & COL 
  565.   m_focusRow= row;
  566.   m_focusCol= col;
  567.  
  568.   makeVisible(row);
  569.  
  570.   //XtVaSetValues(m_widget, XmNscrollRow, row, NULL);
  571.  
  572.   XmLGridRowColumnToXY( m_widget, XmCONTENT, row,  XmCONTENT, col, False, &rect);
  573.  
  574.   //fe_SetTextFieldAndCallBack(m_textWidget, NULL);
  575.  
  576.   if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
  577.   {
  578.      char *str;
  579.             XtVaSetValues( m_textWidget, XmNx, rect.x,
  580.                            XmNy, rect.y, XmNwidth, rect.width,
  581.                            XmNheight, rect.height, 0);
  582.  
  583.      str = GetCellValue(row, col);
  584.  
  585.      // Force an update may not be necessary
  586.      XmUpdateDisplay(m_widget);
  587.  
  588.      fe_SetTextFieldAndCallBack(m_textWidget, str);
  589.  
  590.      if ( str ) 
  591.          /* allocated by new
  592.           */
  593.          delete str;
  594.  
  595.      XmUpdateDisplay(m_textWidget);
  596.      XmTextFieldShowPosition( m_textWidget, m_cursorPos);
  597.      // Set insertion pos before managing child, otherwise
  598.      // cruft sometimes appears at beginning of line (SGI bug?):
  599.      XmTextFieldSetInsertionPosition( m_textWidget, m_cursorPos);
  600.      XtManageChild(m_textWidget);
  601.      XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
  602.   }
  603.   else if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE)
  604.   {
  605.      char *str;    
  606.      XtVaSetValues( m_typeWidget, XmNx, rect.x,
  607.                     XmNy, rect.y, XmNwidth, rect.width,
  608.                     XmNheight, rect.height, 0);
  609.      str = GetCellValue(row, col);
  610.  
  611.      fe_SetTextFieldAndCallBack(m_typeWidget, str);
  612.      if ( str ) XtFree(str);
  613.  
  614.      XtManageChild(m_typeWidget);
  615.      XmProcessTraversal(m_typeWidget, XmTRAVERSE_CURRENT);
  616.   }
  617.   XmLGridSetFocus(m_widget, m_focusRow, m_focusCol);
  618.   if ( removed )
  619.     XtAddCallback(m_textWidget, 
  620.         XmNlosingFocusCallback, textLosingFocusCallback, this);
  621. }
  622.  
  623. void
  624. XFE_AddressOutliner::textFocus()
  625. {
  626.     m_parentView->getToplevel()->notifyInterested(XFE_AddressOutliner::textFocusIn, m_textWidget);
  627. }
  628.  
  629. void
  630. XFE_AddressOutliner::typeFocus()
  631. {
  632.     m_parentView->getToplevel()->notifyInterested(XFE_AddressOutliner::typeFocusIn, m_typeWidget);
  633. }
  634.  
  635. void
  636. XFE_AddressOutliner::textLosingFocus(XtPointer /* callData*/ )
  637. {
  638. #if 0
  639.     int oldrow = m_focusRow;
  640.     int oldcol = m_focusCol;
  641.     
  642.     XmTextPosition oldcurs = XmTextFieldGetInsertionPosition(m_textWidget);
  643.  
  644.     updateAddresses();
  645.     invalidate();               // redraw all grid elements
  646.  
  647.     XmTextPosition lastpos = XmTextFieldGetLastPosition(m_textWidget);
  648.     m_cursorPos = (oldcurs > lastpos ? lastpos : oldcurs);
  649.     m_focusRow = oldrow;
  650.     m_focusCol = oldcol;
  651.     XmLGridSetFocus(m_widget, m_focusRow, m_focusCol);
  652.     XmTextFieldSetInsertionPosition(m_textWidget, m_cursorPos);
  653. #endif
  654.     // To do: When we lose focus, we also lose the black highlight
  655.     // around the active text widget.  This is the place to fix that.
  656. }
  657.  
  658. void
  659. XFE_AddressOutliner::textactivate(XtPointer /* callData */)
  660. {
  661.     int oldrow = m_focusRow;
  662.     int count = getTotalLines();
  663.  
  664.     // Don't do anything if there's nothing in the text field:
  665.     if (XmTextFieldGetInsertionPosition(m_textWidget) <= 0)
  666.         return;
  667.  
  668.     //textLosingFocus(0);
  669.     updateAddresses();
  670.  
  671.     count = getTotalLines() - count;
  672.     int curline = m_focusRow + count;
  673.  
  674.     Boolean insertNewLine = !m_addressable->hasDataAt(curline+1);
  675.     if ( insertNewLine )
  676.     {
  677.         selectLine(-1);
  678.         m_addressable->insertNewDataAfter(curline);
  679.     }
  680.  
  681.     MapText(m_focusRow + count + 1);
  682.     m_focusRow = oldrow + count + 1;
  683.  
  684.     // As per the spec (don't blame me for the design!):
  685.     // increment the Type field of the next line to the next
  686.     // addressing mode, e.g. if this is To, make it Cc --
  687.     // but only if there were multiple comma-separated names typed in.
  688.     if ( insertNewLine && count > 0 )
  689.     {
  690.         // Make it stop at Bcc:
  691.         int headerPos = 0;
  692.         MSG_HEADER_SET mask;
  693.         if ( headerPos == MSG_TotalHeaderCount()-1 ) 
  694.             mask = MSG_HeaderValue(0);
  695.         else mask = MSG_HeaderValue(++headerPos);
  696.         const char* header = MSG_HeaderMaskToString((MSG_HEADER_SET)mask);
  697.         if (!XP_STRNCMP(header, "To", 2) || !XP_STRNCMP(header, "Cc", 2))
  698.             doDown(m_focusRow,
  699.                    XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE);
  700.     }
  701. }
  702.  
  703. char*
  704. XFE_AddressOutliner::getLastEnterredName(char* str, int* comma_pos, int* len, Boolean *moreRecipients)
  705. {
  706.    char *pSubstring = NULL;
  707.    char *string = NULL;
  708.    char *substring = NULL;
  709.    *len = 0;
  710.    *comma_pos = 0;
  711.  
  712.    *moreRecipients = False;
  713.  
  714.    if ( str && strlen(str) > 0 )
  715.    {
  716.      string = strdup(str);
  717.  
  718.      // Returns the pointer to the first occurances of ','
  719.      substring = strrchr(string, ',');
  720.      if (substring && strlen(substring) > 1)
  721.      {
  722.     pSubstring = (char*)XP_CALLOC(strlen(substring)+1, sizeof(char));
  723.     strcpy( pSubstring, substring+1);
  724.     *len = strlen(pSubstring) ;
  725.         *comma_pos  = strlen(str) - *len;
  726.     *moreRecipients = True;
  727.      }
  728.      else if (!substring) 
  729.      {
  730.     pSubstring = (char*)XP_CALLOC(strlen(string)+1, sizeof(char));
  731.     strcpy( pSubstring, string);
  732.     *len = strlen(pSubstring) ;
  733.      }
  734.      else {
  735.        *comma_pos = strlen(string);
  736.        *moreRecipients = True;
  737.      }
  738.      free(string);
  739.    }
  740.    else
  741.    {
  742.     *len = 0;
  743.         *comma_pos = 0;
  744.    }
  745.    return pSubstring;
  746. }
  747.  
  748. static void
  749. text_timer_func(XtPointer closure, XtIntervalId *)
  750. {
  751.     XFE_AddressOutliner* ao = (XFE_AddressOutliner*)closure;
  752.     if (ao)
  753.         ao->processInput();
  754. }
  755.  
  756. // This is the routine that looks for name completion.
  757. void
  758. XFE_AddressOutliner::processInput()
  759. {
  760.     m_textTimer = 0;        // Make sure the timer is clear
  761.  
  762.     char* textStr = fe_GetTextField(m_textWidget);
  763.  
  764.     XmTextPosition lastPos = XmTextFieldGetLastPosition(m_textWidget);
  765.     XmTextPosition insertPos = XmTextFieldGetInsertionPosition(m_textWidget);
  766.  
  767.     // if we're not at the end of the string, then we're done;
  768.     // no need for name completion:
  769.     if (insertPos < lastPos || textStr == 0)
  770.         return;
  771.  
  772.     char* curName = XP_STRRCHR(textStr, ',');
  773.     if (curName != 0)
  774.         ++curName;
  775.         // also need to skip past whitespace
  776.     else
  777.         curName = textStr;
  778.     char* completeName = nameCompletion(curName);
  779.     if (completeName)
  780.     {
  781.         char* buf = (char*)XP_CALLOC((size_t)lastPos
  782.                                      + XP_STRLEN(completeName) + 1,
  783.                                      sizeof (char));
  784.         if (curName != textStr)
  785.         {
  786.             strncpy(buf, textStr, curName - textStr);
  787.             XP_STRCAT(buf, completeName);
  788.         }
  789.         else
  790.             XP_STRCPY(buf, completeName);
  791.  
  792.         // Probably would be better to set all these
  793.         // with a single XtSetValues command and avoid
  794.         // having to worry about the callback from SetString.
  795.         fe_SetTextFieldAndCallBack(m_textWidget, buf);
  796.         XmTextFieldSetSelection(m_textWidget, lastPos,
  797.                                 XmTextFieldGetLastPosition(m_textWidget),
  798.                             XtLastTimestampProcessed(XtDisplay(m_textWidget)));
  799.         XmTextFieldSetInsertionPosition(m_textWidget, lastPos);
  800.         XP_FREE(completeName);
  801.         XP_FREE(buf);
  802.     }
  803.     XtFree(textStr);
  804. }
  805.  
  806. void
  807. XFE_AddressOutliner::textmodify(Widget, XtPointer callData)
  808. {
  809.     char *pCompleteName = NULL;
  810.     XmTextVerifyCallbackStruct *cbs;
  811.     char *pName = NULL;
  812.     char *pCurrString = NULL;
  813.     int len;
  814.     int comma_pos, length;
  815.     char *pNewName = NULL;
  816.     Boolean moreRecipients;
  817.     XmTextPosition lastpos = 0;
  818.  
  819.     cbs = (XmTextVerifyCallbackStruct *)callData;
  820.  
  821.     if (m_lastSelected > -1)     // there's a multiple selection
  822.     {
  823.         // Do nothing unless this is backspace or delete
  824.         if (cbs->text->ptr != NULL)
  825.             return;
  826.  
  827.         deleteRows(m_firstSelected, m_lastSelected);
  828.         return;
  829.     }
  830.  
  831.     // If one line is selected, deselect once we start typing:
  832.     else if (m_firstSelected > -1)
  833.         selectLine(-1);
  834.  
  835.     if ( cbs->text->length == 1 )
  836.     {
  837.         pCurrString = fe_GetTextField(m_textWidget);
  838.         lastpos = XmTextFieldGetLastPosition(m_textWidget);
  839.         XmTextPosition left, right;
  840.         if (XmTextFieldGetSelectionPosition(m_textWidget, &left, &right)
  841.             && lastpos <= right)
  842.             lastpos = left;
  843.  
  844.         if ( cbs->currInsert < lastpos ) 
  845.         {
  846.             XtFree(pCurrString);
  847.             pCurrString = NULL;
  848.             cbs->doit = True;
  849.         }
  850.         if ( pCurrString )
  851.         {
  852.             XmTextPosition insertPos;
  853.  
  854.             // We only want to match the part of pCurrString the user
  855.             // actually entered, not the part matched from the addrbook:
  856.             char* enteredString = (char*)XP_CALLOC(lastpos+1, sizeof(char));
  857.             strncpy(enteredString, pCurrString, lastpos);
  858.             pNewName = getLastEnterredName(enteredString, &comma_pos, &length,
  859.                                            &moreRecipients);
  860.             XP_FREE(enteredString);
  861.             len = length + cbs->text->length + 1;
  862.             pName = (char*)XP_CALLOC(len, sizeof(char));
  863.  
  864.             // If the field was empty before, it's easy:
  865.             if ( cbs->currInsert == 0 || (moreRecipients && length == 0))
  866.             {
  867.                 strcpy(pName, cbs->text->ptr);
  868.                 insertPos = 0;
  869.             }
  870.             else if ( length > 0 )
  871.             {
  872.                 XmTextPosition left, right;
  873.                 if (!XmTextFieldGetSelectionPosition(m_textWidget,
  874.                                                      &left, &right))
  875.                     left = cbs->currInsert;
  876.                 // "left", not cbs->currInsert, is really the insert position.
  877.  
  878.                 if (!moreRecipients)
  879.                     strncpy(pName, pCurrString, (size_t)left);
  880.                 else
  881.                     strncpy(pName, pNewName,
  882.                             (unsigned int)(cbs->currInsert - comma_pos));
  883.  
  884.                 strcat(pName, cbs->text->ptr);
  885.  
  886.                 // Now reset the timer -- when it runs out we'll try
  887.                 // name completion, rather than doing it on every char:
  888.                 if (m_textTimer)
  889.                     XtRemoveTimeOut(m_textTimer);
  890.                 m_textTimer = XtAppAddTimeOut(fe_XtAppContext, 650,
  891.                                               text_timer_func, this);
  892.                 pCompleteName = 0;
  893.                
  894.                 insertPos = left;
  895.             }
  896.  
  897.             cbs->doit = True;
  898.             XP_FREE (pName);
  899.         }
  900.         else
  901.         {
  902.             cbs->doit = True;
  903.         }
  904.         XtFree(pCurrString);
  905.     }
  906. }
  907.  
  908. void
  909. XFE_AddressOutliner::textmotion(XtPointer callData)
  910. {
  911.    XmTextVerifyCallbackStruct *cbs;
  912.  
  913.  
  914.   cbs = (XmTextVerifyCallbackStruct *)callData;
  915.  
  916. }
  917.  
  918. void
  919. XFE_AddressOutliner::scroll(XtPointer)
  920. {
  921.     selectLine(-1);
  922.  
  923.     // If we keep the child managed, then the Outliner will try to
  924.     // scroll back to keep the last focused row visible (makeVisible).
  925.     // We can either unmanage the text widget (so nothing has focus)
  926.     // or guess where to shift the focus upon scrolling.
  927.     XtUnmanageChild(m_textWidget);
  928.  
  929. #if 0
  930.     int focus_r, focus_c;
  931.     Boolean focusIn;
  932.     XRectangle rect;
  933.      XtUnmanageChild(m_textWidget);
  934.      XmLGridGetFocus(m_widget, &focus_r, &focus_c, &focusIn);
  935.      if ( XmLGridRowIsVisible(m_widget, focus_r) )
  936.      {
  937.          XmLGridRowColumnToXY( m_widget, XmCONTENT,
  938.         focus_r,  XmCONTENT, 2, False, &rect);
  939.          XtVaSetValues( m_textWidget, XmNx, rect.x,
  940.             XmNy, rect.y, XmNwidth, rect.width,
  941.             XmNheight, rect.height, 0);
  942.          XtManageChild(m_textWidget);
  943.          XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
  944.      }
  945. #endif
  946. }
  947.  
  948. void
  949. XFE_AddressOutliner::handleEvent(XEvent *event, Boolean *c)
  950. {
  951.   int x = event->xbutton.x;
  952.   int y = event->xbutton.y;
  953.   unsigned char rowtype;
  954.   unsigned char coltype;
  955.   int row, column;
  956.   static int press_row=0, press_col = 0;
  957.   // only handles button clicks for now.  See outline.c:ButtonEvent for details. 
  958.   *c = True;
  959.   switch (event->type)
  960.     {
  961.     case KeyPress:
  962.           XDEBUG(printf("KeyPressMask...\n");)
  963.         selectLine(-1);
  964.     break;
  965.     case FocusOut:
  966.           XDEBUG(printf("Focus out Mask...\n");)
  967.     break;
  968.     case FocusIn:
  969.           XDEBUG(printf("Focus In Mask...\n");)
  970.         *c = False;
  971.         //XmLGridGetFocus(m_widget, &row, &column, &focus);
  972.         if ( m_focusCol == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT ) {
  973.             XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
  974.         }
  975.     break;
  976.     case EnterNotify: // Enter Grid Widget and Leave the text widget
  977.       XDEBUG(printf("Enter Notify-Detail-%d\n", ((XCrossingEvent*)event)->detail);)
  978.       /***************************************************************/
  979.       // This is a HACK, we rely on details to give us more info
  980.       //  about the crossing events.
  981.  
  982.       // Here are some traces. But, details might be skipped if
  983.       // cursor pointer moves too fast. Aack.. it's X... dh
  984.  
  985.       // Leave from Grid to Outside Grid, details = NotifyAncestor(0)
  986.       // From Outsidget Gri enter to Grid, details = NotifyAncestor
  987.  
  988.       // Leave from Grid to Text Widget, details = NotifyInferior(2)
  989.       // Enter to Grid from Text Widget, details = NotifyInferior
  990.       /***************************************************************/
  991.  
  992.       // Only when one actually enter to the grid widget
  993.       // from outside the grid widget. 
  994.       if ( ((XCrossingEvent*)event)->detail == NotifyAncestor ) onEnter();
  995.       break;
  996.     case LeaveNotify:
  997.       // Don't do anthing now
  998.       break;
  999.     case MotionNotify:
  1000.       XDEBUG(printf("Motion Notify..........\n");)
  1001.       break;
  1002.     case ButtonPress:
  1003.       // Always ignore btn3. Btn3 is for popups. - dp 
  1004.       *c = False;
  1005.       if (event->xbutton.button == 3) break;
  1006.       XDEBUG(printf("Button Press....\n");)
  1007.  
  1008.       if (XmLGridXYToRowColumn(m_widget, x, y,
  1009.                                &rowtype, &row, &coltype, &column) >= 0)
  1010.         {
  1011.           m_inPopup = False;
  1012.           if (rowtype == XmHEADING)
  1013.             {
  1014.               // let microline handle the resizing of rows.
  1015.               if (XmLGridPosIsResize(m_widget, x, y))
  1016.                 {
  1017.           *c = True;
  1018.                   return;
  1019.                 }
  1020.             }
  1021.       else if (  column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_ICON )
  1022.     {
  1023.  
  1024.       // If it's a shift-click, we need to do multi selection,
  1025.       // otherwise select it exclusively:
  1026.       if ((event->xbutton.state & ShiftMask) != 0 && m_firstSelected >= 0)
  1027.           extendSelection(row);
  1028.       else
  1029.           selectLine(row);
  1030.  
  1031.       *c = True;
  1032.       return;
  1033.     }
  1034.       else if (column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE
  1035.                || column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_BTN)
  1036.           m_inPopup = True;
  1037.           else if ( column > 0 )
  1038.       {
  1039.               press_row = row;
  1040.               press_col = column;
  1041.           }
  1042.  
  1043.           // We had a click somewhere other than the icon, so clear selection:
  1044.           selectLine(-1);
  1045.  
  1046.       if ( m_inPopup )
  1047.       {
  1048.         *c = False;
  1049.  
  1050.           XtRemoveCallback(m_typeWidget, 
  1051.         XmNlosingFocusCallback, textLosingFocusCallback, this);
  1052.         // This call to PlaceText sets the focus into the type field,
  1053.         // which allows changing the type via keyboard but has the
  1054.         // unfortunate side effect that we can't pull down a menu
  1055.         // from this widget a second time.  But that's arguably better
  1056.         // than never allowing keyboard-based changes ...
  1057.         // ToDo: place a similar event handler on the m_typeWidget.
  1058.         PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE);
  1059.         if ( m_popup == NULL )
  1060.         {
  1061.             int i;
  1062.  
  1063.             m_popup = XFE_PopupMenu::CreatePopupMenu(FE_GetToplevelWidget(),
  1064.                                                      "AddressOutlinerPopup",
  1065.                                                      NULL,0);
  1066.             
  1067.             XtVaSetValues(m_popup,XmNmenuPost,"<Btn1Down>",NULL);
  1068.             
  1069.             int count = MSG_TotalHeaderCount();
  1070.  
  1071.             for ( i = 0; i < count; i++ )
  1072.             {
  1073.                 char *maskStr = XP_STRDUP(MSG_HeaderMaskToString(MSG_HeaderValue(i)));
  1074.                 
  1075.                 XmString xmstr = XmStringCreate(maskStr,
  1076.                                                 XmFONTLIST_DEFAULT_TAG);
  1077.                 
  1078.                 Widget item = XtVaCreateManagedWidget("PopupItem",
  1079.                                                       xmPushButtonWidgetClass,
  1080.                                                       m_popup,
  1081.                                                       XmNlabelString,    xmstr,
  1082.                                                       NULL);
  1083.             
  1084.                 XmStringFree(xmstr);
  1085.                 
  1086.                 XtAddCallback(item,XmNactivateCallback,popupCallback,this);
  1087.                 
  1088.                 XP_FREE(maskStr);
  1089.             }
  1090.         }
  1091.  
  1092.         Position x_root, y_root;
  1093.         XRectangle rect;
  1094.         XButtonPressedEvent press_event;
  1095.                 XmLGridRowColumnToXY(m_widget,
  1096.             XmCONTENT, row,
  1097.             XmCONTENT, 0,
  1098.             True,
  1099.             &rect);
  1100.         XtTranslateCoords(m_widget, 0,0, &x_root, &y_root);
  1101.  
  1102.         press_event.x_root = x_root+rect.x;
  1103.         press_event.y_root = y_root+rect.y + rect.height;
  1104.  
  1105.         // Position and post the popup menu
  1106.         XmMenuPosition(m_popup,(XButtonPressedEvent *) &press_event);
  1107.         XtManageChild(m_popup);
  1108.       }
  1109.         }
  1110.       break;
  1111.     case ButtonRelease:
  1112.       *c = False;
  1113.  
  1114.       if (event->xbutton.button == 3) break;
  1115.       if (XmLGridXYToRowColumn(m_widget, x, y,
  1116.                                &rowtype, &row, &coltype, &column) >= 0)
  1117.         {
  1118.           if (rowtype == XmHEADING)
  1119.             {
  1120.               // let microline handle the resizing of rows.
  1121.               if (XmLGridPosIsResize(m_widget, x, y))
  1122.                 {
  1123.           *c = True;
  1124.                   return;
  1125.                 }
  1126.             }
  1127.           else 
  1128.             {
  1129.         if (row == press_row && column == press_col ) 
  1130.         {
  1131.           if ( column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_ICON )
  1132.             *c = True;
  1133.           else if ( column > 0 )
  1134.           {
  1135.               PlaceText(row, column);
  1136.  
  1137.               // Translate mouse event coordinate to the text field char pos:
  1138.               if (column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT)
  1139.               {
  1140.                   Position x_grid, y_grid;    // root pos of grid origin
  1141.                   Position x_text, y_text;    // root pos of textf origin
  1142.                   XtTranslateCoords(m_widget, 0,0, &x_grid, &y_grid);
  1143.                   XtTranslateCoords(m_textWidget, 0,0, &x_text, &y_text);
  1144.  
  1145.                   XmTextFieldSetCursorPosition(m_textWidget,
  1146.                         XmTextFieldXYToPos(m_textWidget,
  1147.                                            x + x_grid - x_text,
  1148.                                            y + y_grid - y_text));
  1149.                   XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
  1150.               }
  1151.           }
  1152.           else *c = False;
  1153.         }
  1154.             }
  1155.         }
  1156.       break;
  1157.  }
  1158. }
  1159.  
  1160. void
  1161. XFE_AddressOutliner::selectLine(int row)
  1162. {
  1163.     Pixel bg;
  1164.  
  1165.     Time time = XtLastTimestampProcessed(XtDisplay(m_textWidget));
  1166.     XmTextFieldClearSelection(m_textWidget, time);
  1167.  
  1168.     XmLGridDeselectAllRows(getBaseWidget(), False);
  1169.  
  1170.     if (row < 0)        // clear selection
  1171.     {
  1172.         XmLGridRow rowp  = XmLGridGetRow(m_widget, XmCONTENT, 0);
  1173.         XmLGridColumn colp = XmLGridGetColumn(m_widget, XmCONTENT, 0);
  1174.         XtVaGetValues(m_widget,
  1175.                       XmNrowPtr, rowp,
  1176.                       XmNcolumnPtr, colp,
  1177.                       XmNcellBackground,&bg,
  1178.                       NULL);
  1179.         XmTextFieldClearSelection(m_textWidget, time);
  1180.         XtVaSetValues(m_textWidget, XmNbackground, bg, 0 );
  1181.         m_firstSelected = m_lastSelected = -1;
  1182.         return;
  1183.     }
  1184.  
  1185.     // highlight everything in the text field
  1186.     PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
  1187.     XmTextPosition last = XmTextFieldGetLastPosition(m_textWidget);
  1188.     XmTextFieldSetSelection(m_textWidget, 0, last, time);
  1189.     XmTextFieldSetCursorPosition(m_textWidget, 0);
  1190.  
  1191.     XmLGridSelectRow(getBaseWidget(), row, False);
  1192.  
  1193.     XtVaGetValues(m_widget,
  1194.                   XmNselectBackground, &bg,
  1195.                   NULL);
  1196.     XtVaSetValues(m_textWidget, XmNbackground, bg, 0 );
  1197.  
  1198.     m_firstSelected = row;
  1199.     m_lastSelected = -1;
  1200. }
  1201.  
  1202. void
  1203. XFE_AddressOutliner::extendSelection(int row)
  1204. {
  1205.     Time time = XtLastTimestampProcessed(XtDisplay(m_textWidget));
  1206.  
  1207.     // XmLGridSelectRow() may overwrite the selected text,
  1208.     // so make sure nothing is selected:
  1209.     XmTextFieldClearSelection(m_textWidget, time);
  1210.  
  1211.     XmLGridDeselectAllRows(getBaseWidget(), False);
  1212.  
  1213.     if (m_lastSelected < 0)     // only one selected item previously
  1214.     {
  1215.         if (row < m_firstSelected)
  1216.         {
  1217.             m_lastSelected = m_firstSelected;
  1218.             m_firstSelected = row;
  1219.         }
  1220.         else
  1221.             m_lastSelected = row;
  1222.     }
  1223.     else if (row < m_firstSelected)
  1224.         m_firstSelected = row;
  1225.     else /* if (row > m_lastSelected) */
  1226.         m_lastSelected = row;
  1227.  
  1228.     // Select everything in the text field -- not because we
  1229.     // really want to, but because it will force the text field
  1230.     // to pass both backspace and delete through to textmodify.
  1231.     // What a total hack!
  1232.     // Worse, if the text field is blank, we can't select it at all! :-(
  1233.     XmTextPosition last = XmTextFieldGetLastPosition(m_textWidget);
  1234. #ifdef notdef
  1235.     // This PlaceText causes lines to be deleted from the outliner
  1236.     // if the last line is blank!
  1237.     // It's not clear why it was needed, anyway.
  1238.     PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
  1239. #endif
  1240.     XmTextFieldSetSelection(m_textWidget, 0, last, time);
  1241.     XmTextFieldSetCursorPosition(m_textWidget, 0);
  1242.  
  1243.     int i;
  1244.     for (i = m_firstSelected; i <= m_lastSelected; ++i)
  1245.         XmLGridSelectRow(getBaseWidget(), i, False);
  1246.  
  1247.     Pixel bg;
  1248.     XtVaGetValues(m_widget,
  1249.                   XmNselectBackground, &bg,
  1250.                   NULL);
  1251.     XtVaSetValues(m_textWidget, XmNbackground, bg, 0 );
  1252. }
  1253.  
  1254.  
  1255. /* Caller has to free this return value */
  1256. char *
  1257. XFE_AddressOutliner::GetCellValue(int row, int col)
  1258. {
  1259.    XmString xmStr = 0;
  1260.    XmLGridRow rowp;
  1261.    XmLGridColumn colp;
  1262.    char *str;
  1263.    Pixel bg;
  1264.  
  1265.  
  1266.    m_addressable->getDataAt(row, col, &str);
  1267.    rowp = XmLGridGetRow(m_widget, XmCONTENT, row);
  1268.    colp = XmLGridGetColumn(m_widget, XmCONTENT, col);
  1269.  
  1270.    XtVaGetValues(m_widget,
  1271.                 XmNrowPtr, rowp,
  1272.                 XmNcolumnPtr, colp,
  1273.                 XmNcellString, &xmStr,
  1274.         XmNcellBackground,&bg,
  1275.                 NULL);
  1276.    XtVaSetValues(m_textWidget, XmNbackground, bg, 0 );
  1277.    XtVaSetValues(m_typeWidget, XmNbackground, bg, 0 );
  1278.    return str;
  1279. }
  1280.  
  1281. //
  1282. // This routine returns malloced memory which should be freed with XtFree()
  1283. //
  1284. static char*
  1285. getUnhighlightedText(Widget textW)
  1286. {
  1287.     XmTextPosition left, right;
  1288.     char* textStr = fe_GetTextField(textW);
  1289.     if (XmTextFieldGetSelectionPosition(textW, &left,&right))
  1290.         textStr[left] = 0;
  1291.     return textStr;
  1292. }
  1293.  
  1294. int
  1295. XFE_AddressOutliner::updateAddresses()
  1296. {
  1297.   int totalAddresses = 1;
  1298.  
  1299.   int focus_r, focus_c;
  1300.  
  1301.   char *textStr;
  1302.   int total = getTotalLines();
  1303.  
  1304.   //XmLGridGetFocus(m_widget, &focus_r, &focus_c, &focusIn);
  1305.  
  1306.   focus_r = m_focusRow;
  1307.   focus_c = m_focusCol;
  1308.  
  1309.   if ( focus_c == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
  1310.   {
  1311.     textStr = getUnhighlightedText(m_textWidget);
  1312.  
  1313.     setAddress(focus_r, (char*)textStr, True);
  1314.     XtFree(textStr);
  1315.     totalAddresses = getTotalLines();
  1316.     totalAddresses = totalAddresses - total + 1; // Include current line
  1317.  
  1318.     // Reset the value of the text field in case it has changed
  1319.     // from plural to singular:
  1320.     char* str = GetCellValue(m_focusRow,
  1321.                     XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
  1322.     if (str)
  1323.     {
  1324.         // Only update the string if it changed
  1325.         // (so we don't change the X selection unnecessesarily)
  1326.         char* curstr = fe_GetTextField(m_textWidget);
  1327.         if (!curstr || XP_STRCMP(curstr, str))
  1328.             fe_SetTextFieldAndCallBack(m_textWidget, str);
  1329.         delete [] str;
  1330.         if (curstr)
  1331.             XtFree(curstr);
  1332.     }
  1333.  
  1334.     XtVaGetValues(m_textWidget, XmNcursorPosition, &m_cursorPos, 0);
  1335.   }
  1336.   return totalAddresses;
  1337. }
  1338.  
  1339.  
  1340. // XFE_AddressOutliner -------- Private ------ static functions -----------
  1341.  
  1342. XFE_CALLBACK_DEFN(XFE_AddressOutliner, tabToGrid)(XFE_NotificationCenter*, void*, void*)
  1343. {
  1344.   if ( m_textWidget && XtIsManaged(m_textWidget))
  1345.     XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
  1346.   else if ( m_typeWidget && XtIsManaged(m_typeWidget))
  1347.     XmProcessTraversal(m_typeWidget, XmTRAVERSE_CURRENT);
  1348. }
  1349.  
  1350.  
  1351. void
  1352. XFE_AddressOutliner::textFocusCallback(Widget, XtPointer clientData, XtPointer)
  1353. {
  1354.   XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
  1355.  
  1356.  
  1357.   obj->textFocus();
  1358. }
  1359.  
  1360. void
  1361. XFE_AddressOutliner::typeFocusCallback(Widget, XtPointer clientData, XtPointer)
  1362. {
  1363.   XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
  1364.  
  1365.  
  1366.   obj->typeFocus();
  1367. }
  1368.  
  1369. void
  1370. XFE_AddressOutliner::textLosingFocusCallback(Widget, XtPointer clientData, XtPointer callData)
  1371. {
  1372.   XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
  1373.   obj->textLosingFocus(callData);
  1374. }
  1375. void
  1376. XFE_AddressOutliner::textActivateCallback(Widget, XtPointer clientData, XtPointer callData)
  1377. {
  1378.   XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
  1379.   obj->textactivate(callData);
  1380. }
  1381.  
  1382. void
  1383. XFE_AddressOutliner::textMotionCallback(Widget, XtPointer clientData, XtPointer callData)
  1384. {
  1385.   XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
  1386.   obj->textmotion(callData);
  1387. }
  1388.  
  1389. void
  1390. XFE_AddressOutliner::textModifyCallback(Widget w, XtPointer clientData, XtPointer callData)
  1391. {
  1392.   XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
  1393.   obj->textmodify(w, callData);
  1394. }
  1395.  
  1396. void
  1397. XFE_AddressOutliner::scrollCallback(Widget, XtPointer clientData, XtPointer callData)
  1398. {
  1399.   XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
  1400.    obj->scroll(callData);
  1401. }
  1402.  
  1403. void
  1404. XFE_AddressOutliner::eventHandler(Widget, XtPointer clientData, XEvent *event, Boolean *cont)
  1405. {
  1406.   XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
  1407.   obj->handleEvent(event, cont);
  1408. }
  1409.  
  1410. char *
  1411. XFE_AddressOutliner::nameCompletion(char *pString)
  1412. {
  1413.    return xfe_ExpandForNameCompletion(pString);
  1414. }
  1415.  
  1416. //----------------------------  Static Functions for action table
  1417. static void FieldTraverse(
  1418.     Widget w,
  1419.          XEvent *event,
  1420.          String *params,
  1421.          Cardinal *nparam)
  1422.  
  1423. {
  1424.   
  1425.    XtPointer client;
  1426.    XFE_AddressOutliner *obj ;
  1427.  
  1428.    XtVaGetValues( w, XmNuserData, &client, 0);
  1429.    obj = (XFE_AddressOutliner *) client;
  1430.    obj->fieldTraverse(w, event, params, nparam);
  1431.  
  1432. }
  1433.  
  1434. static void KeyIn(
  1435.     Widget w,
  1436.          XEvent *event,
  1437.          String *params,
  1438.          Cardinal *nparam)
  1439. {
  1440.    XtPointer client;
  1441.    XFE_AddressOutliner *obj ;
  1442.  
  1443.    XtVaGetValues( w, XmNuserData, &client, 0);
  1444.  
  1445.    obj = (XFE_AddressOutliner *) client;
  1446.    obj->keyIn(w, event, params, nparam);
  1447. }
  1448.  
  1449. static void TableTraverse(
  1450.     Widget w,
  1451.          XEvent *event,
  1452.          String *params,
  1453.          Cardinal *nparam)
  1454. {
  1455.    XtPointer client;
  1456.    XFE_AddressOutliner *obj ;
  1457.  
  1458.    XtVaGetValues( w, XmNuserData, &client, 0);
  1459.  
  1460.    obj = (XFE_AddressOutliner *) client;
  1461.    obj->tableTraverse(w, event, params, nparam);
  1462. }
  1463.  
  1464. //----------- Address Book stuff here ------------
  1465.  
  1466. extern "C" char * xfe_ExpandForNameCompletion(char * pString)
  1467. {
  1468.     ABID entryID;
  1469.     ABID field;
  1470.     ABook *pAddrBook = fe_GetABook(0);
  1471.     XP_List *pDirectories= FE_GetDirServers();
  1472.     char *pName = XP_STRDUP(pString);
  1473.  
  1474. #if defined(DEBUG_tao)
  1475.     printf("\n  xfe_ExpandForNameCompletion");
  1476. #endif
  1477.  
  1478.     DIR_Server* pDirServer = NULL;
  1479.     pAddrBook = fe_GetABook(0);
  1480.     DIR_GetComposeNameCompletionAddressBook(pDirectories, &pDirServer);
  1481.  
  1482.     AB_GetIDForNameCompletion(
  1483.         pAddrBook,
  1484.          pDirServer,
  1485.         &entryID,&field,(const char*)pName);
  1486.  
  1487.     XP_FREE(pName);
  1488.  
  1489.     if (entryID != (unsigned long)-1)
  1490.     {
  1491.     if ( field == ABNickname )
  1492.     {
  1493.         /* abdefn.h:const int kMaxFullNameLength = 256;
  1494.          */
  1495.         char szNickname[kMaxFullNameLength+1];
  1496.         szNickname[0] = '\0';
  1497.             AB_GetNickname(
  1498.         pDirServer,
  1499.             pAddrBook, entryID, szNickname);
  1500.                 if (strlen(szNickname))
  1501.                             return strdup(szNickname);
  1502.         }
  1503.         else if ( field == ABFullName )
  1504.     {
  1505.         char *szFullname;
  1506.         szFullname = (char*)XP_CALLOC(kMaxFullNameLength+1, sizeof(char));
  1507.         szFullname[0] = '\0';
  1508.         AB_GetFullName(pDirServer, 
  1509.                        pAddrBook,
  1510.                        entryID,
  1511.                        szFullname);
  1512.         if (szFullname && strlen(szFullname))
  1513.             {
  1514.                 return szFullname;
  1515.             }
  1516.         
  1517.     }
  1518.     }
  1519.  
  1520.         return NULL;
  1521. }
  1522.  
  1523. // New Communication methods with parent view
  1524.  
  1525. void 
  1526. XFE_AddressOutliner::setTypeHeader(int row, MSG_HEADER_SET header, Boolean redisplay)
  1527. {
  1528.    const char *type = MSG_HeaderMaskToString(header);
  1529.    m_focusRow = row;
  1530.  
  1531.    // Set Data
  1532.    m_addressable->setHeader(row, header);
  1533.  
  1534.    // Update the Type Field Display 
  1535.  
  1536.    if ( redisplay ) invalidateLine(row); // Should be invalidateCell
  1537.    if ( type )
  1538.    {
  1539.      fe_SetTextFieldAndCallBack(m_typeWidget, (char*)type );
  1540.      XmTextFieldSetHighlight(m_typeWidget, 0, 
  1541.                     strlen(type), XmHIGHLIGHT_SELECTED); 
  1542.    }
  1543.    else XP_ASSERT(0);
  1544. }
  1545.  
  1546.  
  1547.  
  1548. void
  1549. XFE_AddressOutliner::setAddress(int row, 
  1550.                 char *pAddressStr, Boolean redisplay)
  1551. {
  1552.    int oldCount = getTotalLines();
  1553.    int newReceipients = 1;
  1554.     
  1555.    m_focusRow = row;
  1556.  
  1557.    newReceipients = m_addressable->setReceipient(row, pAddressStr);
  1558.    if ( newReceipients > 1 )
  1559.    {
  1560.        change(m_focusRow, oldCount, oldCount+newReceipients-1);
  1561.    }
  1562.    else if (redisplay)
  1563.   {
  1564.     invalidate();
  1565.   }
  1566. }
  1567.  
  1568. void
  1569. XFE_AddressOutliner::doInsert(int row, int /* col */)
  1570. {
  1571.  
  1572.   (void)updateAddresses();
  1573.   m_addressable->insertNewDataAfter(row);
  1574.   m_cursorPos = 0;
  1575.   MapText(row+1);
  1576.   invalidate();
  1577. }
  1578.  
  1579. void
  1580. XFE_AddressOutliner::doDelete(int row, int col, XEvent *event)
  1581. {
  1582.   XmTextPosition cpos;
  1583.   XmTextPosition pos, newPos;
  1584.   char *textStr;
  1585.   Boolean deleterow = False;
  1586.  
  1587.   if ( col ==  XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT)
  1588.   {
  1589.        XtVaGetValues(m_textWidget, XmNcursorPosition, &cpos, 0);
  1590.        pos = XmTextFieldGetLastPosition(m_textWidget);
  1591.  
  1592.        if (pos ==0 && cpos== 0 && row+1 == getTotalLines() ) deleterow = False;
  1593.        else if (pos ==0 && cpos== 0) deleterow = True;
  1594.        else if ( pos == cpos ) deleterow = False;
  1595.        else if (pos > 0) 
  1596.        { 
  1597.         // Hack text widget action
  1598.         XtCallActionProc(m_textWidget, "delete-next-character", event,
  1599.                             NULL, 0 );
  1600.         newPos = XmTextFieldGetLastPosition(m_textWidget);
  1601.         textStr = fe_GetTextField(m_textWidget);
  1602.  
  1603.         if (newPos == pos && newPos == 0 ) deleterow = True;
  1604.         else{
  1605.            setAddress(row, textStr, False);
  1606.                invalidateLine(row);
  1607.             }
  1608.         XtFree(textStr);
  1609.        } /* pos > 0 */
  1610.    } /* col = */
  1611.  
  1612.   if (deleterow
  1613.       || col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE)
  1614.       deleteRow(row, col);
  1615. }
  1616.  
  1617. void
  1618. XFE_AddressOutliner::doBackSpace(int row, int col, XEvent *event)
  1619. {
  1620.   XmTextPosition cpos;
  1621.   XmTextPosition pos;
  1622.   Boolean deleterow = False;
  1623.  
  1624.   if ( col ==  XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT)
  1625.   {
  1626.        XtVaGetValues(m_textWidget, XmNcursorPosition, &cpos, 0);
  1627.        pos = XmTextFieldGetLastPosition(m_textWidget);
  1628.  
  1629.        if (pos == 0 && cpos == 0 )
  1630.            deleterow = True;
  1631.        else if (pos > 0) 
  1632.        { 
  1633.            // Hack text widget action
  1634.            XtCallActionProc(m_textWidget, "delete-previous-character",
  1635.                             event, NULL, 0 );
  1636.        } /* pos > 0 */
  1637.    } /* col = */
  1638.  
  1639.   if (deleterow
  1640.       || col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE)
  1641.   {
  1642.       deleteRow(row, col);
  1643.  
  1644.       // shift focus to end of previous row
  1645.       if ( row > 0 ) {
  1646.           PlaceText(row-1,
  1647.                     XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
  1648.           m_cursorPos = XmTextFieldGetLastPosition(m_textWidget);
  1649.           XmTextFieldSetInsertionPosition(m_textWidget, m_cursorPos);
  1650.       }
  1651.   }
  1652. }
  1653.  
  1654. void
  1655. XFE_AddressOutliner::deleteRow(int row, int col)
  1656. {
  1657.    selectLine(-1);
  1658.  
  1659.    if ( getTotalLines() == 1)
  1660.    {
  1661.       m_cursorPos= 0;
  1662.       setAddress(row, NULL, False);
  1663.       setTypeHeader(row, MSG_TO_HEADER_MASK, False);
  1664.       invalidateLine(row);
  1665.  
  1666.       PlaceText(0,XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT, False );
  1667.    }
  1668.    else
  1669.    {
  1670.       //m_cursorPos = 0;
  1671.       if (row >= 0 && m_addressable->removeDataAt(row) )
  1672.       {
  1673.         XtRemoveCallback(m_textWidget, XmNlosingFocusCallback,
  1674.                          textLosingFocusCallback, this);
  1675.         int total = getTotalLines();
  1676.         if ( total > row+1)
  1677.         {
  1678.            change(row, total, total-1);
  1679.                PlaceText(row, col, False);
  1680.         }
  1681.         else
  1682.         {
  1683.            change(row, total, total-1);
  1684.                PlaceText(row-1, col, False);
  1685.         }
  1686.         XtAddCallback(m_textWidget, XmNlosingFocusCallback,
  1687.                       textLosingFocusCallback, this);
  1688.         m_cursorPos = 0;
  1689.         XmTextFieldSetCursorPosition(m_textWidget, 0); 
  1690.       }
  1691.        col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
  1692.     }
  1693. }
  1694.  
  1695. void
  1696. XFE_AddressOutliner::deleteRows(int startrow, int endrow)
  1697. {
  1698.    selectLine(-1);
  1699.  
  1700.    XtUnmanageChild(m_textWidget);
  1701.  
  1702.    if (endrow >= getTotalLines()-1)
  1703.        endrow = getTotalLines()-1;
  1704.  
  1705.    for (int i = endrow; i >= startrow; --i)
  1706.        m_addressable->removeDataAt(i);
  1707.  
  1708.    // Make sure we have at least one row:
  1709.    Boolean deletedAll = False;
  1710.    if (startrow == 0 && endrow == getTotalLines()-1)
  1711.    {
  1712.        startrow = 1;
  1713.        deletedAll = True;
  1714.    }
  1715.    change(startrow, endrow-startrow+1, getTotalLines()-endrow+startrow-1);
  1716.  
  1717.    // Should get the text widget managed again ...
  1718.  
  1719.    if (deletedAll)
  1720.    {
  1721.        PlaceText(0, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
  1722.        fe_SetTextFieldAndCallBack(m_textWidget, "");
  1723.    }
  1724. }
  1725.  
  1726. void
  1727. XFE_AddressOutliner::doEnd(int row, int col)
  1728. {
  1729.     if (col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT)
  1730.     {
  1731.         m_cursorPos = XmTextFieldGetLastPosition(m_textWidget);
  1732.         XmTextFieldSetCursorPosition(m_textWidget, m_cursorPos);
  1733.     }
  1734.     else
  1735.     {
  1736.         row = getTotalLines(); 
  1737.         col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
  1738.         PlaceText(row, col);
  1739.     }
  1740. }
  1741.  
  1742. void
  1743. XFE_AddressOutliner::doHome(int row, int col)
  1744. {
  1745.     if (col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT)
  1746.     {
  1747.         XmTextFieldSetCursorPosition(m_textWidget, (XmTextPosition)0);
  1748.     }
  1749.     else
  1750.     {
  1751.         row = 0; col = 1;
  1752.         PlaceText(row, col);
  1753.     }
  1754. }
  1755.  
  1756. void
  1757. XFE_AddressOutliner::doUp(int row, int col)
  1758. {
  1759.     const char *header;
  1760.     int headerPos = 0;
  1761.     MSG_HEADER_SET mask;
  1762.  
  1763.     if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
  1764.     {
  1765.         if ( row > 0 ) row--;
  1766.         PlaceText(row,XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
  1767.     }
  1768.     else
  1769.     {
  1770.         static Cardinal doUp_num = 1;
  1771.        char *headerStr;
  1772.  
  1773.        headerPos = m_addressable->getHeader(row);
  1774.        
  1775.        if ( headerPos == 0 ) 
  1776.             mask = MSG_HeaderValue(MSG_TotalHeaderCount()-1);
  1777.        else mask = MSG_HeaderValue(--headerPos);
  1778.  
  1779.            header = MSG_HeaderMaskToString((MSG_HEADER_SET)mask);
  1780.  
  1781.        headerStr = XP_STRDUP(header);
  1782.           keyIn( m_typeWidget, NULL, &headerStr, &doUp_num );
  1783.        XP_FREE(headerStr);
  1784.     }
  1785. }
  1786.  
  1787. void
  1788. XFE_AddressOutliner::doDown(int row, int col)
  1789. {    
  1790.   const char *header;
  1791.   MSG_HEADER_SET mask;
  1792.   int headerPos;
  1793.  
  1794.   if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
  1795.   {
  1796.     updateAddresses();
  1797.  
  1798.     if ( row+1 < getTotalLines() ) 
  1799.         {
  1800.             row++;
  1801.         }
  1802.     PlaceText(row,
  1803.         XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT, False);
  1804.   }
  1805.   else 
  1806.   {
  1807.         static Cardinal doDown_num = 1;
  1808.        char *headerStr;
  1809.        headerPos = m_addressable->getHeader(row);
  1810.        
  1811.        if ( headerPos == MSG_TotalHeaderCount()-1 ) 
  1812.             mask = MSG_HeaderValue(0);
  1813.        else mask = MSG_HeaderValue(++headerPos);
  1814.  
  1815.            header = MSG_HeaderMaskToString((MSG_HEADER_SET)mask);
  1816.  
  1817.        headerStr = XP_STRDUP(header);
  1818.        keyIn( m_typeWidget, NULL, &headerStr, &doDown_num );
  1819.        XP_FREE(headerStr);
  1820.   }
  1821. }
  1822.  
  1823. void 
  1824. XFE_AddressOutliner::doLeft(int row, int col)
  1825. {
  1826.     XmTextPosition pos;
  1827.  
  1828.     if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
  1829.         {
  1830.         pos = XmTextFieldGetInsertionPosition(m_textWidget);
  1831.        if ( pos == 0 )
  1832.          PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE);
  1833.        else 
  1834.        {
  1835.          m_cursorPos = pos-1;
  1836.          XmTextFieldSetInsertionPosition(m_textWidget, m_cursorPos);
  1837.        }
  1838.     }
  1839. }
  1840.  
  1841.  
  1842. void
  1843. XFE_AddressOutliner::doRight(int row, int col)
  1844. {
  1845.     XmTextPosition pos;
  1846.     XmTextPosition lastpos;
  1847.  
  1848.     if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE )
  1849.     {
  1850.        PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
  1851.        XmTextFieldSetInsertionPosition(m_textWidget, 0 );
  1852.     }
  1853.     else if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
  1854.     {
  1855.         lastpos = XmTextFieldGetLastPosition(m_textWidget);
  1856.         pos = XmTextFieldGetInsertionPosition(m_textWidget);
  1857.        if ( pos < lastpos )
  1858.        {
  1859.           m_cursorPos = pos+1;
  1860.           XmTextFieldSetInsertionPosition(m_textWidget, m_cursorPos);
  1861.        }
  1862.        else if ( row+1 < getTotalLines() )
  1863.           PlaceText(row+1, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE);
  1864.        else
  1865.           PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
  1866.     
  1867.     }
  1868. }
  1869.  
  1870. void
  1871. XFE_AddressOutliner::doNext(int row, int col)
  1872. {
  1873.   updateAddresses();
  1874.  
  1875.   if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
  1876.   {
  1877.       if ( row+1 == getTotalLines() )
  1878.       {
  1879.         // Register Action
  1880.  
  1881.           XtUnmanageChild(m_textWidget);
  1882.           XtUnmanageChild(m_typeWidget);
  1883.         m_parentView->getToplevel()->notifyInterested(XFE_AddressOutliner::tabNext, this);
  1884.         invalidate();
  1885.         return;
  1886.       }
  1887.       else if ( row < getTotalLines() ) row++;
  1888.       col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE;
  1889.   }
  1890.   else 
  1891.     col= XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
  1892.   PlaceText(row, col, False);
  1893. }
  1894.  
  1895.  
  1896. void
  1897. XFE_AddressOutliner::doPrevious(int row, int col)
  1898. {
  1899.   updateAddresses();
  1900.  
  1901.   if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE )
  1902.   {
  1903.      if ( row == 0 )
  1904.      {
  1905.         m_parentView->getToplevel()->notifyInterested(XFE_AddressOutliner::tabPrev, this);
  1906.         return;
  1907.      }
  1908.      else 
  1909.         row --;
  1910.      col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
  1911.   }
  1912.   else col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE;
  1913.   PlaceText(row, col, False);
  1914. }
  1915.  
  1916. void
  1917. XFE_AddressOutliner::onLeave()
  1918. {
  1919.   XtVaGetValues(m_textWidget, XmNcursorPosition, &m_cursorPos, 0);
  1920.   XtUnmanageChild(m_textWidget);
  1921.   XtUnmanageChild(m_typeWidget);
  1922.  
  1923.   updateAddresses();
  1924.   invalidate();
  1925.  
  1926.   XmLGridSetFocus(m_widget, m_focusRow, m_focusCol);
  1927.   XmUpdateDisplay(m_widget);
  1928.   if ( m_lastFocus )
  1929.     XmProcessTraversal(m_lastFocus, XmTRAVERSE_CURRENT);
  1930.   else 
  1931.   m_parentView->getToplevel()->notifyInterested(XFE_AddressOutliner::tabNext, this);
  1932. }
  1933.  
  1934. void
  1935. XFE_AddressOutliner::onEnter()
  1936. {
  1937.   int row, column;
  1938.   Widget base;
  1939.  
  1940.   base =  m_parentView->getParent()->getParent()->getBaseWidget();
  1941.   row = m_focusRow;
  1942.   column = m_focusCol;
  1943.  
  1944.   if ( XtIsManaged(m_textWidget) || XtIsManaged(m_typeWidget) )
  1945.   {
  1946.     return;
  1947.   }
  1948.  
  1949.   if ( column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT ) 
  1950.   {
  1951.     // Value has been updated on Leave. No need to update it again
  1952.     PlaceText(row, column, False );
  1953.   }
  1954.   else if ( column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE)
  1955.   { 
  1956.        XtManageChild(m_typeWidget);
  1957.        XmProcessTraversal(m_typeWidget, XmTRAVERSE_CURRENT);
  1958.   }
  1959. //  m_parentView->getToplevel()->notifyInterested(XFE_AddressFolderView::tabNext, this);
  1960. }
  1961.  
  1962. void
  1963. XFE_AddressOutliner::fillText(char *text)
  1964. {
  1965.     if (m_textWidget && text)
  1966.         fe_SetTextFieldAndCallBack(m_textWidget, text);
  1967. }
  1968.  
  1969.  
  1970.  
  1971.