home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / src / Outliner.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  85.6 KB  |  3,541 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.    Outliner.cpp -- Outliner class hack.
  20.    Created: Chris Toshok <toshok@netscape.com>, 7-Aug-96.
  21.    */
  22.  
  23.  
  24.  
  25. #include "xpassert.h"
  26. #include "xp_mem.h"
  27.  
  28. #include "Outliner.h"
  29. #include "Outlinable.h"
  30.  
  31. #if defined(USE_MOTIF_DND)
  32. #include "OutlinerDrop.h"
  33. #endif /* USE_MOTIF_DND */
  34.  
  35. #include "xfe.h"
  36. #include "icondata.h"
  37. #include "prefapi.h"
  38. #include "xp_qsort.h"
  39.  
  40. #include <Xfe/XfeP.h>
  41.  
  42. #if !defined(USE_MOTIF_DND)
  43. #include <Xm/Label.h>
  44. #endif /* USE_MOTIF_DND */
  45.  
  46. #ifdef DEBUG_toshok
  47. #define D(x) x
  48. #else
  49. #define D(x)
  50. #endif
  51.  
  52. extern "C" {
  53.  
  54. #include "XmL/GridP.h"
  55.  
  56. };
  57.  
  58. // please change this if you change any of the *parent.gif images.
  59. #define PIPEIMAGESIZE 16
  60.  
  61. #if defined(USE_MOTIF_DND)
  62. #undef NONMOTIF_DND
  63. #else
  64. #define NONMOTIF_DND
  65. #endif /* USE_MOTIF_DND */
  66.  
  67. #ifdef FREEIF
  68. #undef FREEIF
  69. #endif
  70. #define FREEIF(obj) do { if (obj) { XP_FREE (obj); obj = 0; }} while (0)
  71.  
  72. #define MIN_COLUMN_WIDTH 6    /* So that the user can manipulate it -- make it the same as the grid's minimum */
  73. #define MAX_COLUMN_WIDTH 10000    /* So that we don't overflow any 16-bit
  74.                                    numbers. */
  75.  
  76. #ifdef DEBUG_toshok
  77. #define D(x) x
  78. #else
  79. #define D(x)
  80. #endif
  81.  
  82. #include "xpgetstr.h"
  83. extern int XFE_SHOW_COLUMN;
  84. extern int XFE_HIDE_COLUMN;
  85.  
  86. fe_icon XFE_Outliner::closedParentIcon = { 0 };
  87. fe_icon XFE_Outliner::openParentIcon = { 0 };
  88. fe_icon XFE_Outliner::showColumnIcon = { 0 };
  89. fe_icon XFE_Outliner::showColumnInsensIcon = { 0 };
  90. fe_icon XFE_Outliner::hideColumnIcon = { 0 };
  91. fe_icon XFE_Outliner::hideColumnInsensIcon = { 0 };
  92.  
  93. #if !defined(USE_MOTIF_DND)
  94. fe_dnd_Source _xfe_dragsource = {0};
  95. #endif /* USE_MOTIF_DND */
  96.  
  97. //
  98. #if defined(DEBUG_tao_)
  99. #define XDBG(x) x
  100. #else
  101. #define XDBG(x) 
  102. #endif
  103.  
  104. #if defined(DEBUG_tao)
  105. #define TRACE(str)   printf("\n At %s: %d, %s", __FILE__, __LINE__, str)
  106. #else
  107. #define TRACE(str)   
  108. #endif
  109.  
  110. void
  111. XFE_Outliner::tip_cb(Widget w, XtPointer clientData, XtPointer cb_data)
  112. {
  113.     XFE_Outliner *obj = (XFE_Outliner *) clientData;
  114.  
  115.     obj->tipCB(w, cb_data);
  116. }
  117.  
  118. void
  119. XFE_Outliner::tipCB(Widget /* w */, XtPointer cb_data)
  120. {
  121.     XFE_TipStringCallbackStruct* cbs = (XFE_TipStringCallbackStruct*)cb_data;
  122.     char *strFromView = 0;
  123.     XP_FREEIF(m_doc_msg_buf);
  124.     XP_FREEIF(m_tip_msg_buf);
  125.  
  126.     //
  127.     // cbs->x <= -10 is not really possible to happen!
  128.     //
  129.     if (cbs->x <= -10 || 
  130.         cbs->x >= m_totalLines ||
  131.         cbs->y < 0 ||
  132.         cbs->y >= m_numcolumns)
  133.         return;
  134.  
  135.     int sourcecol = m_columnIndex[cbs->y];
  136.     if (cbs->reason == XFE_DOCSTRING) {
  137.         strFromView = m_outlinable->getCellDocString(cbs->x, sourcecol);
  138.         
  139.         m_doc_msg_buf = XP_STRDUP(strFromView?strFromView:"");
  140.         *cbs->string = m_doc_msg_buf;
  141.         cbs->x = -10;
  142.         cbs->y = -10;
  143.     } else if (cbs->reason == XFE_TIPSTRING) {
  144.         if (cbs->y >= m_numvisible && m_hideColumnsAllowed) {
  145.             if (cbs->x != -1) {
  146.                 m_tip_msg_buf = XP_STRDUP("");
  147.                 *cbs->string = m_tip_msg_buf;
  148.                 return;
  149.             }/* if */
  150.  
  151.             if (cbs->y == m_numvisible) {
  152.                 /* show header */
  153.                 strFromView = XP_GetString(XFE_SHOW_COLUMN);
  154.             }/* if */
  155.             else {
  156.                 /* hide header */
  157.                 strFromView = XP_GetString(XFE_HIDE_COLUMN);
  158.             }/* else */
  159.         }/* if */
  160.         else
  161.             strFromView = m_outlinable->getCellTipString(cbs->x, sourcecol);
  162.  
  163.         m_tip_msg_buf = XP_STRDUP(strFromView?strFromView:"");
  164.         *cbs->string = m_tip_msg_buf;
  165.  
  166.         XRectangle rect;
  167.         if (XmLGridRowColumnToXY(m_widget, 
  168.                                  (cbs->x < 0)?XmHEADING:XmCONTENT, 
  169.                                  (cbs->x < 0)?0:cbs->x,  
  170.                                  XmCONTENT, 
  171.                                  cbs->y, 
  172.                                  False, 
  173.                                  &rect) < 0) {
  174.             cbs->x = -10;
  175.             cbs->y = -10;
  176.         }/* if */
  177.         else {
  178.             XDBG(printf("\n tipCB: (total,r,c,w,h)=(%d,%d,%d,%d,%d)\n",
  179.                    m_totalLines, cbs->x, cbs->y, rect.width, rect.height));
  180.             cbs->x = rect.x + textStart(cbs->y, rect.width);
  181.             cbs->y = rect.y + rect.height;
  182.         }/* else */
  183.     }
  184. }
  185.  
  186. int XFE_Outliner::textStart(int col, int maxX)
  187. {
  188.     fe_icon *icon;
  189.     int sourcecol = m_columnIndex[col];
  190.     int startX = 0;
  191.     icon = m_outlinable->getColumnIcon(sourcecol);
  192.  
  193.     if (sourcecol == m_pipeColumn) {
  194.         OutlinerAncestorInfo * ancestorInfo;
  195.         int depth;
  196.  
  197.         m_outlinable->getTreeInfo(NULL, NULL, &depth, &ancestorInfo);
  198.         
  199.         for (int i = 0; i < depth; i ++) {
  200.             if ( ( i + 1 ) * PIPEIMAGESIZE <= maxX )
  201.                 if (ancestorInfo && ancestorInfo[ i ].has_next) {
  202.                     // the the vertical pipe for this line's ancestors.
  203.                     startX += PIPEIMAGESIZE;
  204.                 }
  205.                 else {
  206.                     // don't know about this block.. must ask will.
  207.                     startX += PIPEIMAGESIZE;
  208.                 }
  209.         }/* for i */
  210.  
  211.         if (ancestorInfo) 
  212.             startX += PIPEIMAGESIZE;
  213.     }/* if pipeCol */
  214.  
  215.     /* if there's an icon, we need to push the text over. */
  216.     if (icon) {
  217.         startX = startX + icon->width + 4;
  218.     }/* if */
  219.     return startX;
  220. }
  221.  
  222. XP_Bool XFE_Outliner::isColTextFit(char *str, int row, int col)
  223. {
  224.     XDBG(printf("\n XFE_Outliner::isColTextFit, row=%d, col=%d, str=%s\n", 
  225.                 row, col, str));
  226.     if (str && XP_STRLEN(str)) {
  227.  
  228.         XRectangle rect;
  229.         if (XmLGridRowColumnToXY(m_widget, 
  230.                                  (row < 0)?XmHEADING:XmCONTENT, 
  231.                                  (row < 0)?0:row,  
  232.                                  XmCONTENT, 
  233.                                  col, 
  234.                                  False, 
  235.                                  &rect) < 0) {
  236.             return False;
  237.         }/* if */
  238.         else {
  239.             char *style = 
  240.                 (row < 0)?
  241.                 (char*)styleToTag(m_outlinable->getColumnHeaderStyle(col)):
  242.                 (char*)styleToTag(m_outlinable->getColumnStyle(col));
  243.             
  244.             XmString xmstr = XmStringCreate(str, style);
  245.             XmFontList fontList;
  246.             XtVaGetValues(m_widget,
  247.                           XmNfontList, &fontList,
  248.                           NULL);
  249.             Dimension strWidth = XmStringWidth(fontList, xmstr);
  250.             XmStringFree(xmstr);
  251.             strWidth += textStart(col, rect.width);
  252.             XDBG(printf("\n (str, strWidth, rect.width, row, col)=(%s, %d, %d, %d, %d)\n", 
  253.                         str, strWidth, rect.width, row, col));
  254.             return (strWidth < (rect.width-1));
  255.         }/* else */
  256.     }/* if */
  257.     else
  258.         return True;
  259. }/* XFE_Outliner::getStringWidth */
  260.  
  261. //
  262.  
  263. XFE_Outliner::XFE_Outliner(const char *name,
  264.                            XFE_Outlinable *o,
  265.                            XFE_Component *toplevel_component,
  266.                            Widget widget_parent, 
  267.                            Boolean constantSize, 
  268.                            XP_Bool hasHeadings,
  269.                            int num_columns, 
  270.                            int num_visible,
  271.                            int *column_widths,
  272.                            char *geom_prefname)
  273.     : XFE_Component(toplevel_component)
  274. {
  275.     m_lastRow = -2;
  276.     m_lastCol = -2;
  277.     m_inGrid = False;
  278.  
  279.     m_tip_msg_buf = 0;
  280.     m_doc_msg_buf = 0;
  281.  
  282.     Widget outline;
  283.     Arg av[10];
  284.     int ac = 0;
  285.     short avgwidth, avgheight;
  286.     XmFontList fontList;
  287.     int i;
  288.     XP_Bool defaultGeometryOK = FALSE;
  289.  
  290.     m_geominfo = NULL;
  291.     m_prefname = NULL;
  292.  
  293.     if (geom_prefname)
  294.         {
  295.             m_prefname = XP_STRDUP(geom_prefname);
  296.             PREF_CopyCharPref(geom_prefname, &m_geominfo);
  297.         }
  298.  
  299.     m_visibleLine = -1;
  300.     m_DataRow = -1;
  301.     m_draggc = NULL;
  302.     m_dragrow = -1;
  303.  
  304. #if !defined(USE_MOTIF_DND)
  305.     m_dragtype = FE_DND_NONE;
  306. #else
  307.     m_dragTargetFunc = NULL;
  308.     m_dropTargetFunc = NULL;
  309.     m_dragIconDataFunc = NULL;
  310.     m_outlinerdrag = NULL;
  311. #endif /* USE_MOTIF_DND */
  312.  
  313.     m_activity = 0;
  314.     m_lastx = -999;
  315.     m_lasty = -999;
  316. #if !defined(USE_MOTIF_DND)
  317.     m_lastmotionx = 0;
  318.     m_lastmotiony = 0;
  319. #endif /* USE_MOTIF_DND */
  320.     m_totalLines = 0;
  321.     m_numcolumns = num_columns;
  322.     m_numvisible = num_visible;
  323.     m_pipeColumn = -1;
  324.     m_sortColumn = -1;
  325.     m_resizeColumn = -1;
  326.     m_visibleTimer = 0;
  327.  
  328.     m_hideColumnsAllowed = False;
  329.     m_descendantSelectAllowed = False;
  330.     m_isFocus = False;
  331.  
  332.     if (constantSize)
  333.         {
  334.             XtSetArg(av[ac], XmNhorizontalSizePolicy, XmCONSTANT); ac++;
  335.         }
  336.     else
  337.         {
  338.             XtSetArg(av[ac], XmNhorizontalSizePolicy, XmVARIABLE); ac++;
  339.         }
  340.  
  341.     XtSetArg(av[ac], XmNautoSelect, False); ac++;
  342.     XtSetArg(av[ac], XmNtraversalOn, False); ac++;
  343.  
  344.     outline = XmLCreateGrid(widget_parent, (char*)name, av, ac);
  345.  
  346.     Pixel bgColor;
  347.     XtVaGetValues(outline, XmNbackground, &bgColor,  0);
  348.     XtVaSetValues(outline,
  349.                   XmNborderWidth, 2,
  350.                   XmNborderColor,  bgColor,
  351.                   XmNcellDefaults, True,
  352.                   XmNcellLeftBorderType, XmBORDER_NONE,
  353.                   XmNcellRightBorderType, XmBORDER_NONE,
  354.                   XmNcellTopBorderType, XmBORDER_NONE,
  355.                   XmNcellBottomBorderType, XmBORDER_NONE,
  356.                   XmNcellAlignment, XmALIGNMENT_LEFT,
  357.                   0);
  358.  
  359.     m_columnwidths = (int*)XP_CALLOC(m_numcolumns, sizeof(int));
  360.  
  361.     // whether or not columns are resizable
  362.     m_columnResizable = (XP_Bool*)XP_CALLOC(m_numcolumns, sizeof(XP_Bool));
  363.     memset(m_columnResizable, True, sizeof(XP_Bool) * m_numcolumns);
  364.   
  365.     m_columnIndex = (int*) XP_ALLOC(sizeof(int) * (m_numcolumns));
  366.  
  367. #if defined(USE_MOTIF_DND)
  368.     XtAddEventHandler(outline,
  369.                       ButtonPressMask | ButtonReleaseMask,
  370.                       False,
  371.                       buttonEventHandler, this);
  372. #else
  373.     XtInsertEventHandler(outline, ButtonPressMask | ButtonReleaseMask
  374.                          | PointerMotionMask, False,
  375.                          buttonEventHandler, this, XtListHead);
  376. #endif
  377.     XtAddCallback(outline, XmNcellDrawCallback, celldrawCallback, this);
  378.   
  379.     m_buttonfunc_data = XP_NEW_ZAP(OutlineButtonFuncData);
  380.     m_flippyfunc_data = XP_NEW_ZAP(OutlineFlippyFuncData);
  381.  
  382. #if !defined(USE_MOTIF_DND)
  383.     // initialize the drag/drop stuff
  384.     m_dragtype = FE_DND_NONE;
  385.     m_dragicon = 0;
  386.     m_sourcedropfunc = 0;
  387. #endif
  388.  
  389.     // initialize the selection stuff
  390.     m_selBlocked = False;
  391.     m_selectedIndices = new int[5];
  392.     m_selectedItems = NULL;
  393.     m_selectedItemCount = 0;
  394.     m_selectedCount = 0;
  395.     m_selectedSize = 5;
  396.     m_firstSelectedIndex = (unsigned int)(1 << 31) - 1; // INT_MAX
  397.     m_lastSelectedIndex = -1;
  398.     m_selectionDirection = 1; // safe default.
  399.  
  400.     // initialize the magic list change (finished, starting) depth.
  401.     m_listChangeDepth = 0;
  402.  
  403.     // keep track of our peer
  404.     m_outlinable = o;
  405.  
  406.     // and set our base widget
  407.     setBaseWidget(outline);
  408.  
  409. #if defined(USE_MOTIF_DND)
  410.     m_outlinerdrop = new XFE_OutlinerDrop(m_widget, this);
  411.     m_outlinerdrop->enable();
  412. #endif /* USE_MOTIF_DND */
  413.  
  414.     defaultGeometryOK = setDefaultGeometry();
  415.  
  416.     if (hasHeadings)
  417.         XmLGridAddRows(m_widget, XmHEADING, 0, 1);
  418.  
  419.     if (!defaultGeometryOK)
  420.         {
  421.             int i;
  422.  
  423.             D(printf ("default geometry is NOT OK!\n");)
  424.  
  425.             m_numvisible = num_visible;
  426.             for (i = 0; i < m_numcolumns; i ++)
  427.                 m_columnIndex[i] = i;
  428.  
  429.             XtVaGetValues(outline, XmNfontList, &fontList, NULL);
  430.             XmLFontListGetDimensions(fontList, &avgwidth, &avgheight, TRUE);
  431.         }
  432.  
  433.     XmLGridAddColumns(outline, XmCONTENT, -1, m_numvisible);
  434.  
  435.     for (i = 0; i < m_numcolumns; i ++)
  436.         {
  437.             if (!defaultGeometryOK)
  438.                 m_columnwidths[i] = column_widths[i] * avgwidth;
  439.             
  440.             if (i < m_numvisible)
  441.                 XtVaSetValues(m_widget,
  442.                               XmNcolumn, i,
  443.                               XmNcolumnSizePolicy, XmCONSTANT,
  444.                               XmNcolumnWidth, m_columnwidths[i],
  445.                               0);
  446.         }
  447.  
  448.     if (!defaultGeometryOK)
  449.         {
  450.             // since it wasn't ok before, we can be assured that it is now.
  451.             // Save it so we won't do the above stuff again.
  452.             rememberGeometry();
  453.         }
  454.  
  455.     XtVaSetValues(m_widget, XmNallowColumnResize, True, 0);
  456.  
  457.     XtAddCallback(m_widget, XmNresizeCallback, resizeCallback, this);
  458.  
  459.     // Tooltip
  460.     fe_AddTipStringCallback(outline, XFE_Outliner::tip_cb, this);
  461.  
  462.     // create our icons, if we need to.
  463.     if (!closedParentIcon.pixmap)
  464.         {
  465.             Pixel bg_pixel;
  466.  
  467.             XtVaGetValues(m_widget, XmNbackground, &bg_pixel, 0);
  468.  
  469.             fe_NewMakeIcon(m_toplevel->getBaseWidget(),
  470.                            toplevel_component->getFGPixel(),
  471.                            bg_pixel,
  472.                            &closedParentIcon,
  473.                            NULL, 
  474.                            cparent.width, cparent.height,
  475.                            cparent.mono_bits, cparent.color_bits, 
  476.                            cparent.mask_bits, FALSE);
  477.  
  478.             fe_NewMakeIcon(m_toplevel->getBaseWidget(),
  479.                            toplevel_component->getFGPixel(),
  480.                            bg_pixel,
  481.                            &openParentIcon,
  482.                            NULL, 
  483.                            oparent.width, oparent.height,
  484.                            oparent.mono_bits, oparent.color_bits,
  485.                            oparent.mask_bits, FALSE);
  486.  
  487.             fe_NewMakeIcon(m_toplevel->getBaseWidget(),
  488.                            toplevel_component->getFGPixel(),
  489.                            bg_pixel,
  490.                            &showColumnIcon,
  491.                            NULL, 
  492.                            showcolumn.width, showcolumn.height,
  493.                            showcolumn.mono_bits, showcolumn.color_bits,
  494.                            showcolumn.mask_bits, FALSE);
  495.  
  496.             fe_NewMakeIcon(m_toplevel->getBaseWidget(),
  497.                            toplevel_component->getFGPixel(),
  498.                            bg_pixel,
  499.                            &showColumnInsensIcon,
  500.                            NULL, 
  501.                            showcolumn_i.width, showcolumn_i.height,
  502.                            showcolumn_i.mono_bits, showcolumn_i.color_bits,
  503.                            showcolumn_i.mask_bits, FALSE);
  504.  
  505.             fe_NewMakeIcon(m_toplevel->getBaseWidget(),
  506.                            toplevel_component->getFGPixel(),
  507.                            bg_pixel,
  508.                            &hideColumnIcon,
  509.                            NULL, 
  510.                            hidecolumn.width, hidecolumn.height,
  511.                            hidecolumn.mono_bits, hidecolumn.color_bits,
  512.                            hidecolumn.mask_bits, FALSE);
  513.  
  514.             fe_NewMakeIcon(m_toplevel->getBaseWidget(),
  515.                            toplevel_component->getFGPixel(),
  516.                            bg_pixel,
  517.                            &hideColumnInsensIcon,
  518.                            NULL, 
  519.                            hidecolumn_i.width, hidecolumn_i.height,
  520.                            hidecolumn_i.mono_bits, hidecolumn_i.color_bits,
  521.                            hidecolumn_i.mask_bits, FALSE);
  522.         }
  523. }
  524.  
  525. XFE_Outliner::XFE_Outliner()
  526. {
  527.     m_selBlocked = False;
  528.     m_outlinable = NULL;
  529. }
  530.  
  531. XFE_Outliner::~XFE_Outliner()
  532. {
  533.     D(printf ("In XFE_Outliner::~XFE_Outliner()\n");)
  534.     FREEIF(m_columnwidths);
  535.     FREEIF(m_columnIndex);
  536.     FREEIF(m_columnResizable);
  537.     FREEIF(m_prefname);
  538.     FREEIF(m_selectedItems);
  539.     FREEIF(m_geominfo);
  540.     //
  541.     XP_FREEIF(m_doc_msg_buf);
  542.     XP_FREEIF(m_tip_msg_buf);
  543.  
  544.     // if our outlinable still has line data allocated,
  545.     // tell it to release it.   
  546.     if (m_DataRow != -1)
  547.         m_outlinable->releaseLineData();
  548.  
  549. #if defined(USE_MOTIF_DND)
  550.     if (m_outlinerdrop)
  551.         delete m_outlinerdrop;
  552. #endif /* USE_MOTIF_DND */
  553. }
  554.  
  555. void
  556. XFE_Outliner::setPipeColumn(int column)
  557. {
  558.     XP_ASSERT(column >= 0 && column < m_numcolumns);
  559.  
  560.     m_pipeColumn = column;
  561. }
  562.  
  563. int
  564. XFE_Outliner::getPipeColumn()
  565. {
  566.     return m_pipeColumn;
  567. }
  568.  
  569. void
  570. XFE_Outliner::setSortColumn(int column, EOutlinerSortDirection direction)
  571. {
  572.     XP_ASSERT(column >= -1 && column < m_numcolumns);
  573.  
  574.     m_sortColumn = column;
  575.     m_sortDirection = direction;
  576. }
  577.  
  578. int
  579. XFE_Outliner::getSortColumn()
  580. {
  581.     return m_sortColumn;
  582. }
  583.  
  584. void
  585. XFE_Outliner::toggleSortDirection()
  586. {
  587.     if (m_sortDirection == OUTLINER_SortAscending)
  588.         m_sortDirection = OUTLINER_SortDescending;
  589.     else
  590.         m_sortDirection = OUTLINER_SortAscending;
  591. }
  592.  
  593. EOutlinerSortDirection
  594. XFE_Outliner::getSortDirection()
  595. {
  596.     return m_sortDirection;
  597. }
  598.  
  599. void
  600. XFE_Outliner::setColumnResizable(int column,
  601.                                  XP_Bool resizable)
  602. {
  603.     XP_ASSERT(column >= 0 && column < m_numcolumns);
  604.     int column_index;
  605.  
  606.     for (column_index = 0; column_index < m_numcolumns; column_index ++)
  607.         if (m_columnIndex[ column_index ] == column)
  608.             break;
  609.  
  610.     setColumnResizableByIndex(column_index, resizable);
  611. }
  612.  
  613. XP_Bool
  614. XFE_Outliner::getColumnResizable(int column)
  615. {
  616.     XP_ASSERT(column >= 0 && column < m_numcolumns);
  617.     int column_index;
  618.  
  619.     for (column_index = 0; column_index < m_numcolumns; column_index ++)
  620.         if (m_columnIndex[ column_index ] == column)
  621.             break;
  622.  
  623.     return getColumnResizableByIndex(column_index);
  624. }
  625.  
  626. void
  627. XFE_Outliner::setColumnWidth(int column,
  628.                              int width)
  629. {
  630.     XP_ASSERT(column >= 0 && column < m_numcolumns);
  631.     int column_index;
  632.  
  633.     for (column_index = 0; column_index < m_numcolumns; column_index ++)
  634.         if (m_columnIndex[ column_index ] == column)
  635.             break;
  636.  
  637.     setColumnWidthByIndex(column_index, width);
  638. }
  639.  
  640. int
  641. XFE_Outliner::getColumnWidth(int column)
  642. {
  643.     XP_ASSERT(column >= 0 && column < m_numcolumns);
  644.     int column_index;
  645.  
  646.     for (column_index = 0; column_index < m_numcolumns; column_index ++)
  647.         if (m_columnIndex[ column_index ] == column)
  648.             break;
  649.  
  650.     return getColumnWidthByIndex(column_index);
  651. }
  652.  
  653.  
  654. // Return the number of visible rows in the grid, including header rows.
  655. int XFE_Outliner::getNumContextAndHeaderRows()
  656. {
  657.     XP_ASSERT(m_widget != 0);
  658.     
  659.     int numContentRows = 0;
  660.     int numHeadingRows = 0;
  661.     XtVaGetValues(m_widget,
  662.                   XmNrows,        &numContentRows,
  663.                   XmNheadingRows, &numHeadingRows,
  664.                   0);
  665.  
  666.     return numContentRows + numHeadingRows;
  667. }
  668.  
  669.  
  670. /*
  671. ** Resize the grid to show all rows, but enforce a
  672. ** minimum and maximum number of rows.
  673. */
  674. void XFE_Outliner::showAllRowsWithRange(int minRows, int maxRows)
  675. {
  676.     XP_ASSERT(m_widget != 0);
  677.     
  678.     int numRows = this->getNumContextAndHeaderRows();
  679.     if((numRows > minRows)&&(numRows < maxRows)) {
  680.         // We are within the range, show them all.
  681.         XtVaSetValues(m_widget,
  682.                       XmNvisibleRows, numRows,
  683.                       0);
  684.     } else if(numRows >= maxRows) {
  685.         // Maximum number of rows.
  686.         XtVaSetValues(m_widget,
  687.                       XmNvisibleRows, maxRows,
  688.                       0);
  689.     } else if(numRows <= minRows) {
  690.         // Minimum number of rows.
  691.         XtVaSetValues(m_widget,
  692.                       XmNvisibleRows, minRows,
  693.                       0);        
  694.     } else {
  695.         XP_ASSERT(0);
  696.     }
  697. }
  698.  
  699. void
  700. XFE_Outliner::setBlockSel(XP_Bool b)
  701. {
  702.     m_selBlocked = b;
  703. }
  704.  
  705. void
  706. XFE_Outliner::scroll2Item(int index)
  707. {
  708.     if (index >=0 && index < m_totalLines) {
  709.         selectItemExclusive(index);
  710.         makeVisible(index);
  711.     }/* if */
  712.     else
  713.         deselectAllItems();
  714. }
  715.  
  716. void
  717. XFE_Outliner::setMultiSelectAllowed(Boolean flag)
  718. {
  719.     XP_ASSERT(m_widget != 0);
  720.  
  721.     if (flag)
  722.         {
  723.             XtVaSetValues(m_widget,
  724.                           XmNselectionPolicy, XmSELECT_MULTIPLE_ROW,
  725.                           0);
  726.         }
  727.     else
  728.         {
  729.             XtVaSetValues(m_widget, 
  730.                           XmNselectionPolicy, XmSELECT_BROWSE_ROW, 
  731.                           0);
  732.         }
  733. }
  734.  
  735. Boolean
  736. XFE_Outliner::getMultiSelectAllowed()
  737. {
  738.     unsigned char selectionPolicy;
  739.  
  740.     XP_ASSERT(m_widget != 0);
  741.  
  742.     XtVaGetValues(m_widget,
  743.                   XmNselectionPolicy, &selectionPolicy,
  744.                   NULL);
  745.  
  746.     return (selectionPolicy == XmSELECT_MULTIPLE_ROW);
  747. }
  748.  
  749. void
  750. XFE_Outliner::setDescendantSelectAllowed(XP_Bool flag)
  751. {
  752.     m_descendantSelectAllowed = flag;
  753. }
  754.  
  755. XP_Bool
  756. XFE_Outliner::getDescendantSelectAllowed()
  757. {
  758.     return m_descendantSelectAllowed;
  759. }
  760.  
  761. void
  762. XFE_Outliner::setHideColumnsAllowed(XP_Bool flag)
  763. {
  764.     if (m_hideColumnsAllowed != flag)
  765.         {
  766.             if (flag)
  767.                 {
  768.                     // show the hide/show buttons.
  769.                     XtVaSetValues(m_widget,
  770.                                   XmNlayoutFrozen, True,
  771.                                   NULL);
  772.  
  773.                     applyDelta(-1 * (12 + 12));
  774.  
  775.                     XmLGridAddColumns(m_widget,XmCONTENT, m_numvisible, 2);
  776.  
  777.                     XtVaSetValues(m_widget,
  778.                                   XmNcolumn, m_numvisible,
  779.                                   XmNcolumnWidth, 12, //XX magic number alert !!!
  780.                                   XmNcolumnSizePolicy, XmCONSTANT,
  781.                                   XmNcolumnResizable, False, // can't resize the show/hide columns.
  782.                                   NULL);
  783.  
  784.                     XtVaSetValues(m_widget,
  785.                                   XmNcolumn, m_numvisible + 1,
  786.                                   XmNcolumnWidth, 12, //XX magic number alert !!!
  787.                                   XmNcolumnSizePolicy, XmCONSTANT,
  788.                                   XmNcolumnResizable, False, // can't resize the show/hide columns.
  789.                                   NULL);
  790.  
  791.                     XtVaSetValues(m_widget,
  792.                                   XmNlayoutFrozen, False,
  793.                                   NULL);
  794.                 }
  795.             else
  796.                 {
  797.                     // remove the hide/show buttons.
  798.                     XmLGridDeleteColumns(m_widget, XmCONTENT, m_numvisible, 2);
  799.  
  800.                     applyDelta(12 + 12);
  801.  
  802.                 }
  803.  
  804.             m_hideColumnsAllowed = flag;
  805.         }
  806. }
  807.  
  808. XP_Bool
  809. XFE_Outliner::getHideColumnsAllowed()
  810. {
  811.     return m_hideColumnsAllowed;
  812. }
  813.  
  814. #if !defined(USE_MOTIF_DND)
  815. void
  816. XFE_Outliner::setDragType(fe_dnd_Type dragtype, fe_icon *dragicon, 
  817.                           XFE_Component *drag_source, fe_dnd_SourceDropFunc sourcedropfunc)
  818. {
  819.     m_dragtype = dragtype;
  820.     m_dragicon = dragicon;
  821.     m_source = drag_source;
  822.     m_sourcedropfunc = sourcedropfunc;
  823. }
  824.  
  825. fe_dnd_Type
  826. XFE_Outliner::getDragType()
  827. {
  828.     return m_dragtype;
  829. }
  830.  
  831. fe_icon *
  832. XFE_Outliner::getDragIcon()
  833. {
  834.     return m_dragicon;
  835. }
  836.  
  837. fe_dnd_SourceDropFunc
  838. XFE_Outliner::getSourceDropFunc()
  839. {
  840.     return m_sourcedropfunc;
  841. }
  842.  
  843. #else
  844. void
  845. XFE_Outliner::enableDragDrop(void *this_ptr,
  846.                              FEGetDropTargetFunc drop_target_func,
  847.                              FEGetDragTargetFunc drag_target_func,
  848.                              FEGetDragIconDataFunc drag_icon_func,
  849.                              FEConvertDragDataFunc drag_conv_func,
  850.                              FEProcessTargetsFunc process_targets_func)
  851. {
  852.   m_dragsource = this_ptr;
  853.   m_dropTargetFunc = drop_target_func;
  854.   m_dragTargetFunc = drag_target_func;
  855.   m_dragIconDataFunc = drag_icon_func;
  856.   m_dragConvFunc = drag_conv_func;
  857.   m_processTargetsFunc = process_targets_func;
  858.  
  859.   if (!m_outlinerdrag)
  860.     m_outlinerdrag = new XFE_OutlinerDrag(m_widget, this);
  861.  
  862.   /* update the dropsite's idea of its targets. */
  863.   m_outlinerdrop->update();
  864. }
  865.  
  866.  
  867. void
  868. XFE_Outliner::getDropTargets(Atom **targets,
  869.                              int *numtargets)
  870. {
  871.   if (m_dropTargetFunc == NULL)
  872.     {
  873.       *targets = NULL;
  874.       *numtargets = 0;
  875.     }
  876.   else
  877.     {
  878.       (*m_dropTargetFunc)(m_outlinable, targets, numtargets);
  879.     }
  880. }
  881.  
  882. void
  883. XFE_Outliner::getDragTargets(int row, int column,
  884.                              Atom **targets,
  885.                              int *numtargets)
  886. {
  887.   if (m_dragTargetFunc == NULL)
  888.     {
  889.       *targets = NULL;
  890.       *numtargets = 0;
  891.     }
  892.   else
  893.     {
  894.       (*m_dragTargetFunc)(m_dragsource, row, column, targets, numtargets);
  895.     }
  896. }
  897.  
  898. fe_icon_data *
  899. XFE_Outliner::getDragIconData(int row, int column)
  900. {
  901.   if (m_dragIconDataFunc == NULL)
  902.     return NULL;
  903.   else
  904.     return (*m_dragIconDataFunc)(m_dragsource, row, column);
  905. }
  906.  
  907. char *
  908. XFE_Outliner::dragConvert(Atom atom)
  909. {
  910.   if (m_dragConvFunc == NULL)
  911.     return NULL;
  912.   else
  913.     return (*m_dragConvFunc)(m_dragsource, atom);
  914. }
  915.  
  916.  
  917. int
  918. XFE_Outliner::processTargets(int row, int col,
  919.                              Atom *targets,
  920.                              const char **data,
  921.                              int numItems)
  922. {
  923.   if (m_processTargetsFunc == NULL)
  924.     return FALSE;
  925.   else
  926.     return (*m_processTargetsFunc)(m_dragsource, row, col,
  927.                                    targets, data, numItems);
  928. }
  929. #endif /* USE_MOTIF_DND */
  930.  
  931. XP_Bool
  932. XFE_Outliner::setDefaultGeometry()
  933. {
  934.     int i;
  935.     char* ptr;
  936.     char* ptr2;
  937.     char* ptr3;
  938.     int value;
  939.     int width;
  940.     int height = 0;
  941.  
  942.     for (i = 0; i < m_numcolumns; i ++)
  943.         m_columnIndex[i] = i;
  944.  
  945.     ptr = m_geominfo;
  946.  
  947.     // first parse the height of the outliner in pixel
  948.     if (ptr != NULL)
  949.         {
  950.             ptr2 = XP_STRCHR(ptr, 'x');
  951.             if (ptr2) *ptr2 = '\0';
  952.             height = atoi(ptr);
  953.  
  954.             if (height > 0 && height < MAX_COLUMN_WIDTH)
  955.                 {
  956.                     *ptr2 = 'x';
  957.  
  958.                     ptr = ptr2 + 1;
  959.                 }
  960.             else
  961.                 {
  962.                     FREEIF(m_geominfo);
  963.                     ptr = m_geominfo;
  964.                 }
  965.  
  966.         }
  967.  
  968.     // then parse the number of visible columns
  969.     if (ptr != NULL)
  970.         {
  971.             ptr2 = XP_STRCHR(ptr, ')');
  972.             if (ptr2) *ptr2 = '\0';
  973.             ptr3 = XP_STRCHR(ptr, '(');
  974.             if (ptr3)
  975.                 {
  976.                     m_numvisible = atoi(ptr3 + 1);
  977.                     
  978.                     if (m_numvisible <= 0 || m_numvisible > m_numcolumns)
  979.                         m_numvisible = m_numcolumns;
  980.                     
  981.                     *ptr3 = '(';
  982.                     *ptr2 = ')';
  983.                     ptr = ptr2 + 1;
  984.                 }
  985.             else
  986.                 {
  987.                     FREEIF(m_geominfo);
  988.                     ptr = m_geominfo;
  989.                 }
  990.         }
  991.     
  992.     for (i=0 ; i<m_numcolumns ; i++) 
  993.         {
  994.             if (ptr == NULL) 
  995.                 {
  996.                     FREEIF(m_geominfo);
  997.                     break;
  998.                 }
  999.       
  1000.             ptr2 = XP_STRCHR(ptr, ';');
  1001.             if (ptr2) *ptr2 = '\0';
  1002.             ptr3 = XP_STRCHR(ptr, ':');
  1003.             if (!ptr3) 
  1004.                 {
  1005.                     FREEIF(m_geominfo);
  1006.                     break;
  1007.                 }
  1008.             *ptr3 = '\0';
  1009.  
  1010.             for (value = 0 ; value < m_numcolumns ; value++) 
  1011.                 {
  1012.                     if (m_outlinable->getColumnName(value) == NULL
  1013.                         || strcmp(m_outlinable->getColumnName(value), ptr) == 0)
  1014.                         break;
  1015.                 }
  1016.  
  1017.             if (value >= m_numcolumns) 
  1018.                 {
  1019.                     FREEIF(m_geominfo);
  1020.                     break;
  1021.                 }
  1022.  
  1023.             m_columnIndex[i] = value;
  1024.             width = atoi(ptr3 + 1);
  1025.             *ptr3 = ':';
  1026.  
  1027.             if (width < MIN_COLUMN_WIDTH) width = MIN_COLUMN_WIDTH;
  1028.             if (width > MAX_COLUMN_WIDTH) width = MAX_COLUMN_WIDTH;
  1029.  
  1030.             m_columnwidths[ i ] = width;
  1031.  
  1032.             if (ptr2) *ptr2++ = ';';
  1033.             ptr = ptr2;
  1034.         }
  1035.  
  1036.     if (m_geominfo) 
  1037.         {
  1038.             /* Check that every column was mentioned, and no duplicates
  1039.                occurred. */
  1040.             int* check = (int*)XP_CALLOC(m_numcolumns, sizeof(int));
  1041.             for (i=0 ; i<m_numcolumns ; i++) check[i] = 0;
  1042.             for (i=0 ; i<m_numcolumns ; i++) 
  1043.                 {
  1044.                     int w = m_columnIndex[i];
  1045.                     if (w < 0 || w > m_numcolumns || check[w]) 
  1046.                         {
  1047.                             FREEIF(m_geominfo);
  1048.                             break;
  1049.                         }
  1050.                     check[w] = 1;
  1051.                 }
  1052.             XP_FREE(check);
  1053.         }
  1054.  
  1055.     if (m_geominfo != NULL)
  1056.         XtVaSetValues(m_widget,
  1057.                       XmNheight, height,
  1058.                       NULL);
  1059.  
  1060.     return (m_geominfo != NULL);
  1061. }
  1062.  
  1063. void
  1064. XFE_Outliner::setInFocus(XP_Bool infocus)
  1065. {
  1066.    Pixel bgColor, fgColor;
  1067.  
  1068.    XtVaGetValues(m_widget, 
  1069.         XmNbackground, &bgColor, 
  1070.         XmNforeground, &fgColor, 0);
  1071.    if ( infocus )
  1072.     XtVaSetValues(m_widget, XmNborderColor,
  1073.          fgColor, 0);
  1074.    else
  1075.     XtVaSetValues(m_widget, XmNborderColor,
  1076.          bgColor, 0);
  1077.  
  1078.    m_isFocus = infocus;
  1079.  
  1080. }
  1081.  
  1082. XP_Bool
  1083. XFE_Outliner::isFocus()
  1084. {
  1085.     return m_isFocus;
  1086. }
  1087.  
  1088. void
  1089. XFE_Outliner::selectItem(int index)
  1090. {
  1091.     XP_ASSERT(m_widget != 0);
  1092.  
  1093.     /*
  1094.     ** invalidate the line without calling invalidateLine, since
  1095.     ** that function calls XmLGridRedrawRow, and we're already
  1096.     ** going to redraw it with the selectrow call below.
  1097.     */
  1098.     if (m_DataRow != -1)
  1099.         m_outlinable->releaseLineData();
  1100.  
  1101.     m_DataRow = -1;
  1102.  
  1103.     XmLGridSelectRow(m_widget, index, False);
  1104.  
  1105.     addSelection(index);
  1106. }
  1107.  
  1108.  
  1109. void
  1110. XFE_Outliner::selectItemExclusive(int index)
  1111. {
  1112.     XP_ASSERT(m_widget != 0);
  1113.  
  1114.     deselectAllItems();
  1115.  
  1116.     selectItem(index);
  1117. }
  1118.  
  1119. void
  1120. XFE_Outliner::deselectItem(int index)
  1121. {
  1122.     XP_ASSERT(m_widget != 0);
  1123.  
  1124.     /*
  1125.     ** invalidate the line without calling invalidateLine, since
  1126.     ** that function calls XmLGridRedrawRow, and we're already
  1127.     ** going to redraw it with the selectrow call below.
  1128.     */
  1129.     if (m_DataRow != -1)
  1130.         m_outlinable->releaseLineData();
  1131.  
  1132.     m_DataRow = -1;
  1133.  
  1134.     XmLGridDeselectRow(m_widget, index, False);
  1135.  
  1136.     if (m_selectedCount)
  1137.         removeSelection(index);
  1138. }
  1139.  
  1140. void
  1141. XFE_Outliner::toggleSelected(int index)
  1142. {
  1143.     XP_ASSERT(m_widget != 0);
  1144.  
  1145.     if (isSelected(index))
  1146.         deselectItem(index);
  1147.     else
  1148.         selectItem(index);
  1149. }
  1150.  
  1151. /*
  1152. ** Here, we either expand or contract the selected area by
  1153. ** following rules.
  1154. **
  1155. ** 1) if new_index < first_index, select from new_index to last_index.
  1156. ** 2) if new_index > last_index, select from first_index to new_index.
  1157. ** 3) if new_index > first_index && new_index < last_index
  1158. **    
  1159. **    3a)  if new_index > (last_index + first_index) / 2, select
  1160. **         from new_index to last_index.
  1161. **    3b)  if new_index < (last_index + first_index) / 2, select
  1162. **         from first_index to new_index.
  1163. **
  1164. ** funkygroovycool
  1165. */
  1166. void
  1167. XFE_Outliner::trimOrExpandSelection(int new_index)
  1168. {
  1169.     // always do something reasonable...
  1170.     if (m_selectedCount == 0)
  1171.         selectItem(new_index);
  1172.     else
  1173.         {
  1174.             if (m_selectionDirection == -1)
  1175.                 {
  1176.                     if (new_index < m_lastSelectedIndex)
  1177.                         {
  1178.                             if (new_index < m_firstSelectedIndex)
  1179.                                 selectRangeByIndices(m_firstSelectedIndex, new_index);
  1180.                             else if (new_index > m_firstSelectedIndex)
  1181.                                 deselectRangeByIndices(new_index - 1, m_firstSelectedIndex);
  1182.  
  1183.                             /* don't need to do anything if
  1184.                                new_index == m_firstSelectedIndex */
  1185.                         }
  1186.                     else
  1187.                         {
  1188.                             deselectRangeByIndices(m_lastSelectedIndex - 1, m_firstSelectedIndex);
  1189.                             selectRangeByIndices(m_lastSelectedIndex, new_index);
  1190.                         }
  1191.                 }
  1192.             else
  1193.                 {
  1194.                     if (new_index > m_firstSelectedIndex)
  1195.                         {
  1196.                             if (new_index > m_lastSelectedIndex)
  1197.                                 selectRangeByIndices(m_lastSelectedIndex, new_index);
  1198.                             else if (new_index < m_lastSelectedIndex)
  1199.                                 deselectRangeByIndices(new_index + 1, m_lastSelectedIndex);
  1200.  
  1201.                             /* don't need to do anything if 
  1202.                                new_index == m_lastSelectedIndex */
  1203.                         }
  1204.                     else
  1205.                         {
  1206.                             deselectRangeByIndices(m_firstSelectedIndex + 1, m_lastSelectedIndex);
  1207.                             selectRangeByIndices(m_firstSelectedIndex, new_index);
  1208.                         }
  1209.                 }
  1210.         }
  1211.  
  1212. }
  1213.  
  1214. void
  1215. XFE_Outliner::selectAllItems()
  1216. {
  1217.     XP_ASSERT(m_widget != 0);
  1218.  
  1219.     XmLGridSelectAllRows(m_widget, False);
  1220.  
  1221.     for (int i = 0; i < m_totalLines; i ++)
  1222.         {
  1223.             selectItem(i);
  1224.         }
  1225.     
  1226.     m_selectionDirection = 1;
  1227. }
  1228.  
  1229. void
  1230. XFE_Outliner::deselectAllItems()
  1231. {
  1232.     XP_ASSERT(m_widget != 0);
  1233.  
  1234.     XmLGridDeselectAllRows(m_widget, False);
  1235.  
  1236.     deselectAll();
  1237. }
  1238.  
  1239. void
  1240. XFE_Outliner::makeVisible(int index)
  1241. {
  1242.     int firstrow, lastrow;
  1243.     Dimension height, shadowthickness;
  1244.  
  1245.     if (index < 0) 
  1246.         return;
  1247.  
  1248.     if (m_visibleTimer) 
  1249.         {
  1250.             m_visibleLine = index;
  1251.             return;
  1252.         }
  1253.  
  1254.     XtVaGetValues(m_widget,
  1255.                   XmNscrollRow, &firstrow, 
  1256.                   XmNheight, &height,
  1257.                   XmNshadowThickness, &shadowthickness, 
  1258.                   NULL);
  1259.  
  1260.     height -= shadowthickness;
  1261.  
  1262.     for (lastrow = firstrow + 1 ; ; lastrow++) 
  1263.         {
  1264.             XRectangle rect;
  1265.  
  1266.             if (XmLGridRowColumnToXY(m_widget,
  1267.                                      XmCONTENT, lastrow,
  1268.                                      XmCONTENT, 0,
  1269.                                      False, &rect) < 0)
  1270.                 {
  1271.                     break;
  1272.                 }
  1273.             if (rect.y + rect.height >= height) break;
  1274.         }
  1275.   
  1276.     if (index >= firstrow && index < lastrow) 
  1277.         return;
  1278.  
  1279.     firstrow = index - ((lastrow - firstrow) / 2);
  1280.   
  1281.     if (firstrow < 0) 
  1282.         firstrow = 0;
  1283.   
  1284.     XtVaSetValues(m_widget,
  1285.                   XmNscrollRow, firstrow, 
  1286.                   NULL);
  1287. }
  1288.  
  1289. void
  1290. XFE_Outliner::invalidate()
  1291. {
  1292.     if (m_DataRow != -1)
  1293.         m_outlinable->releaseLineData();
  1294.  
  1295.     m_DataRow = -1;
  1296.  
  1297.     XmLGridRedrawAll(m_widget);
  1298. }
  1299.  
  1300. void
  1301. XFE_Outliner::invalidateLine(int line)
  1302. {
  1303.     if (m_DataRow != -1)
  1304.         m_outlinable->releaseLineData();
  1305.  
  1306.     m_DataRow = -1;
  1307.  
  1308.     XmLGridRedrawRow(m_widget, XmCONTENT, line);
  1309. }
  1310.  
  1311. void
  1312. XFE_Outliner::invalidateLines(int start, int count)
  1313. {
  1314.     int i;
  1315.  
  1316.     for (i = start; i < start + count; i ++)
  1317.         invalidateLine(i);
  1318. }
  1319.  
  1320. void
  1321. XFE_Outliner::invalidateHeaders()
  1322. {
  1323.     if (m_DataRow != -1)
  1324.         m_outlinable->releaseLineData();
  1325.  
  1326.     m_DataRow = -1;
  1327.  
  1328.     XmLGridRedrawRow(m_widget, XmHEADING, 0);
  1329. }
  1330.  
  1331. int
  1332. XFE_Outliner::numResizableVisibleColumns(int starting_at)
  1333. {
  1334.     int i;
  1335.     int count = 0;
  1336.  
  1337.     for (i = starting_at; i < m_numvisible; i ++)
  1338.         {
  1339.             if (getColumnResizableByIndex(i))
  1340.                 count ++;
  1341.         }
  1342.  
  1343.     return count;
  1344. }
  1345.  
  1346. /*
  1347. ** applyDelta is one of the grossest functions ever, in my opinion.
  1348. **
  1349. ** The idea is that we give it a delta and a column to start applying it at,
  1350. ** and it will start there and divide up the delta evenly (well, using
  1351. ** percentages) across all the resizable columns from the given one to the
  1352. ** right-most one.  It will try to resize them all enough to get rid of the
  1353. ** delta, but in the event that it can't distribute the delta entirely, it
  1354. ** returns the amount left over.  This is used by resize() method below to fix
  1355. ** up the resized column.
  1356. **
  1357. ** That being said, the way things are done here is icky.  We build up an
  1358. ** array of delta_struct's, one for each resizable column we're going to be
  1359. ** dealing with.  Then we sort them so that lower indices have smaller widths.
  1360. ** This is so that if we can't apply enough of the delta to a smaller width
  1361. ** column, it'll get pushed off to the larger ones (well, the largest one -- 
  1362. ** the last one in the array.)  We make up for all the multiplicative errors 
  1363. ** -- and instances of not being able to fully apply a column delta with the 
  1364. ** last column in the array.  Since it's the largest, we have the best chance
  1365. ** of doing it there.
  1366. */
  1367. typedef struct delta_struct
  1368. {
  1369.     int column_index;
  1370.     int column_width;
  1371. } delta_struct;
  1372.  
  1373. static int compare_deltas(const void *d1, const void *d2)
  1374. {
  1375.     delta_struct *delta1 = (delta_struct *)d1;
  1376.     delta_struct *delta2 = (delta_struct *)d2;
  1377.  
  1378.     return delta1->column_width - delta2->column_width;
  1379. }
  1380.  
  1381. int
  1382. XFE_Outliner::applyDelta(int delta, int starting_at)
  1383. {
  1384.     int current_column;
  1385.     int num_resizable = numResizableVisibleColumns(starting_at);
  1386.     int total_resizable_column_width = 0;
  1387.     int delta_distributed = 0;
  1388.     delta_struct *deltas;
  1389.     int i;
  1390.  
  1391.     D(printf ("Applying a delta of %d from column %d to column %d\n",
  1392.               delta,
  1393.               starting_at,
  1394.               m_numvisible - 1);)
  1395.  
  1396.     if (num_resizable == 0)
  1397.       return delta;
  1398.  
  1399.     deltas = (delta_struct*)XP_CALLOC(num_resizable, sizeof(delta_struct));
  1400.     i = 0;
  1401.     for (current_column = starting_at; current_column < m_numvisible; current_column ++)
  1402.         if (getColumnResizableByIndex(current_column))
  1403.             {
  1404.                 deltas[i].column_index = current_column;
  1405.                 deltas[i].column_width = getColumnWidthByIndex(current_column);
  1406.                 total_resizable_column_width += deltas[i].column_width;
  1407.                 i++;
  1408.             }
  1409.  
  1410.     XP_ASSERT(total_resizable_column_width > 0);
  1411.     if (total_resizable_column_width <= 0)
  1412.         {
  1413.             XP_FREE(deltas);
  1414.             return delta;
  1415.         }
  1416.  
  1417.     XP_QSORT(deltas, num_resizable, sizeof(delta_struct), compare_deltas);
  1418.  
  1419.     current_column = starting_at;
  1420.  
  1421.     for (i = 0; i < num_resizable; i ++)
  1422.         {
  1423.             int orig_column_width = deltas[i].column_width;
  1424.             int column_width;
  1425.             int column_delta = delta * ((float)orig_column_width / total_resizable_column_width);
  1426.             
  1427.             D(printf ("Column %d (Before delta = %d).  Percentage of delta applied = %f (%d pixels)\n",
  1428.                       deltas[i].column_index,
  1429.                       orig_column_width,
  1430.                       (float)orig_column_width / total_resizable_column_width,
  1431.                       column_delta);)
  1432.                 
  1433.             if (i == num_resizable - 1)
  1434.                 {
  1435.                     /* make up for our cumulative errors with the last column */
  1436.                     D(printf ("making up for the differences in column %d by adding %d to its width.\n",
  1437.                               deltas[i].column_index, delta - delta_distributed);)
  1438.                     
  1439.                     column_delta += delta - delta_distributed - column_delta;
  1440.                 }
  1441.  
  1442.             column_width = orig_column_width + column_delta;
  1443.             
  1444.             if (column_width < MIN_COLUMN_WIDTH)
  1445.                 {
  1446.                     column_width = MIN_COLUMN_WIDTH;
  1447.                 
  1448.                     column_delta = column_width - orig_column_width;
  1449.                 }
  1450.             else if (column_width > MAX_COLUMN_WIDTH)
  1451.                 {
  1452.                     column_width = MAX_COLUMN_WIDTH;
  1453.  
  1454.                     column_delta = column_width - orig_column_width;
  1455.                 }
  1456.             
  1457.             delta_distributed += column_delta;
  1458.  
  1459.             D(printf ("After delta = %d\n", column_width);)
  1460.             setColumnWidthByIndex(deltas[i].column_index, column_width);
  1461. #if defined(DEBUG_tao_)
  1462.             printf("\n>>XFE_Outliner::applyDelta:setColumnWidthByIndex(i=%d, ind=%d, wid=%d)", 
  1463.                    i, deltas[i].column_index, column_width);
  1464. #endif
  1465.         }
  1466.  
  1467.     XP_FREE(deltas);
  1468.     return delta - delta_distributed;
  1469. }
  1470.  
  1471. void
  1472. XFE_Outliner::hideColumn()
  1473. {
  1474.     Dimension width;
  1475.             
  1476.     m_numvisible --;
  1477.  
  1478.     XP_ASSERT(m_numvisible > 0);
  1479.     width = getColumnWidthByIndex(m_numvisible);
  1480.  
  1481.     D(printf ("I'm hiding a column of width %d\n", width);)
  1482.  
  1483.     XtVaSetValues(m_widget,
  1484.                   XmNlayoutFrozen, True,
  1485.                   NULL);
  1486.  
  1487.     XmLGridDeleteColumns(m_widget, XmCONTENT, m_numvisible, 1);
  1488.     
  1489.     applyDelta(width);
  1490.  
  1491.     XtVaSetValues(m_widget,
  1492.                   XmNlayoutFrozen, False,
  1493.                   NULL);
  1494.  
  1495.     rememberGeometry();
  1496. }
  1497.  
  1498. void
  1499. XFE_Outliner::showColumn()
  1500. {
  1501.     int width;
  1502.  
  1503.     XP_ASSERT(m_numvisible < m_numcolumns);
  1504.  
  1505.     width = getColumnWidthByIndex( m_numvisible );
  1506.  
  1507.     D(printf ("I'm showing a column of width %d\n", width);)
  1508.  
  1509.     XtVaSetValues(m_widget,
  1510.                   XmNlayoutFrozen, True,
  1511.                   NULL);
  1512.  
  1513.     if (m_resizeColumn != -1 && m_columnIndex [ m_resizeColumn ] < m_numvisible)
  1514.         {
  1515.             Dimension column_width;
  1516.             
  1517.             column_width = getColumnWidthByIndex(m_columnIndex[ m_resizeColumn] );
  1518.             
  1519.             setColumnWidthByIndex(m_columnIndex[ m_resizeColumn ],
  1520.                                   column_width - width);
  1521.         }
  1522.     else
  1523.         {
  1524.             applyDelta(-1 * width);
  1525.         }
  1526.    
  1527.     XmLGridRow rowp;
  1528.     XmLGridColumn colp;
  1529.  
  1530.     rowp = XmLGridGetRow(m_widget, XmHEADING, 0);
  1531.     colp = XmLGridGetColumn(m_widget, XmCONTENT, m_numvisible);
  1532.  
  1533.     Pixel row_cell_bg;
  1534.  
  1535.     XtVaGetValues(m_widget,
  1536.                   XmNrowPtr, rowp,
  1537.                   XmNcolumnPtr, colp,
  1538.                   XmNcellBackground, &row_cell_bg,
  1539.                   NULL);
  1540.  
  1541.     XmLGridAddColumns(m_widget, XmCONTENT, m_numvisible, 1);
  1542.  
  1543.     XtVaSetValues(m_widget,
  1544.                   XmNcolumn, m_numvisible,
  1545.                   XmNcolumnSizePolicy, XmCONSTANT,
  1546.                   XmNcolumnWidth, width,
  1547.                   XmNcolumnResizable, m_columnResizable[ m_numvisible ],
  1548.                   NULL);
  1549.  
  1550.     XtVaSetValues(m_widget,
  1551.                   XmNlayoutFrozen, False,
  1552.                   NULL);
  1553.  
  1554.     XtVaSetValues(m_widget,
  1555.                   XmNrowType, XmHEADING,
  1556.                   XmNcellBackground, row_cell_bg,
  1557.                   NULL);
  1558.  
  1559.     m_numvisible ++;
  1560.  
  1561.     rememberGeometry();
  1562. }
  1563.  
  1564. void
  1565. XFE_Outliner::moveColumn(int column_to_move,
  1566.                          int destination)
  1567. {
  1568.     int delta;
  1569.     int tmp;
  1570.     int tmp_width;
  1571.     XP_Bool tmp_resizable;
  1572.     int i;
  1573.  
  1574.     if (column_to_move < destination)
  1575.         delta = 1;
  1576.     else
  1577.         delta = -1;
  1578.  
  1579.     /* save off all information about the column number we're moving */
  1580.     tmp = m_columnIndex[ column_to_move ];
  1581.     tmp_width = m_columnwidths[ column_to_move ];
  1582.     tmp_resizable = m_columnResizable[ column_to_move ];
  1583.  
  1584.     /* move all the other columns out of the way. */
  1585.     for (i = column_to_move; i != destination; i += delta)
  1586.         {
  1587.             m_columnIndex[ i ] = m_columnIndex[ i + delta ];
  1588.             m_columnwidths[ i ] = m_columnwidths[ i + delta ];
  1589.             m_columnResizable[ i ] = m_columnResizable[ i + delta ];
  1590.         }
  1591.  
  1592.     /* replace the column we moved in the place we moved it to */
  1593.     m_columnIndex[ destination ] = tmp;
  1594.     m_columnwidths[ destination ] = tmp_width;
  1595.     m_columnResizable[ destination ] = tmp_resizable;
  1596.  
  1597.     XmLGridMoveColumns(m_widget, destination, column_to_move, 1);
  1598.  
  1599.     rememberGeometry();
  1600. }
  1601.  
  1602. int
  1603. XFE_Outliner::getSelection(const int **indices, int *count)
  1604. {
  1605.     if (indices)
  1606.         *indices = m_selectedIndices;
  1607.  
  1608.     if (count)
  1609.         *count = m_selectedCount;
  1610.  
  1611.     return m_selectedCount;
  1612. }
  1613.  
  1614. int
  1615. XFE_Outliner::getTotalLines()
  1616. {
  1617.     return m_totalLines;
  1618. }
  1619.  
  1620. int
  1621. XFE_Outliner::XYToRow(int x, int y, XP_Bool *nearbottom)
  1622. {
  1623.     int row;
  1624.     int column;
  1625.     unsigned char rowtype;
  1626.     unsigned char coltype;
  1627.  
  1628.     if (x < 0 || y < 0 ||
  1629.         x >= _XfeWidth(m_widget) || y >= _XfeHeight(m_widget)) 
  1630.         {
  1631.             return -1;
  1632.         }
  1633.  
  1634.     if (XmLGridXYToRowColumn(m_widget, x, y, &rowtype, &row,
  1635.                              &coltype, &column) < 0) {
  1636.         return -1;
  1637.     }
  1638.  
  1639.     if (rowtype != XmCONTENT || coltype != XmCONTENT) 
  1640.       return -1;
  1641.  
  1642.     if (nearbottom) {
  1643.         int row2;
  1644.         *nearbottom = (XmLGridXYToRowColumn(m_widget, x, y + 5,
  1645.                                             &rowtype, &row2,
  1646.                                             &coltype, &column) >= 0 &&
  1647.                        row2 > row);
  1648.     }
  1649.     return row;
  1650. }
  1651.  
  1652. void
  1653. XFE_Outliner::addSelection(int selected)
  1654. {
  1655.     int i;
  1656.  
  1657.     // if it's already selected, just return.
  1658.     for (i = 0; i < m_selectedCount; i ++) 
  1659.         {
  1660.             if ( m_selectedIndices [ i ] == selected )
  1661.                 {
  1662.                     return;
  1663.                 }
  1664.         }
  1665.  
  1666.     if (i >= m_selectedSize)
  1667.         {
  1668.             // Resize storage array (exponential growth)
  1669.             int *tmp = new int [ m_selectedSize * 2 ];
  1670.             memcpy (tmp, m_selectedIndices, m_selectedSize * sizeof(int));
  1671.             delete [] m_selectedIndices;
  1672.             m_selectedIndices = tmp;
  1673.             m_selectedSize *= 2;
  1674.         }
  1675.  
  1676.     m_selectedIndices [ i ] = selected;
  1677.     m_selectedCount ++;
  1678.  
  1679.     if (selected > m_lastSelectedIndex)
  1680.         m_lastSelectedIndex = selected;
  1681.     if (selected < m_firstSelectedIndex)
  1682.         m_firstSelectedIndex = selected;
  1683.  
  1684.     D(printf ("m_firstSelectedIndex = %d\n", m_firstSelectedIndex);)
  1685.     D(printf ("m_lastSelectedIndex = %d\n", m_lastSelectedIndex);)
  1686.  
  1687.     invalidateLine( selected );
  1688. }
  1689.  
  1690. void
  1691. XFE_Outliner::removeSelection(int selected)
  1692. {
  1693.     int i, j;
  1694.  
  1695.     for (i = 0, j = 0; i < m_selectedCount; i ++) 
  1696.         {
  1697.             if (m_selectedIndices [ i ] == selected)
  1698.                 {
  1699.                     invalidateLine( selected );
  1700.                 }
  1701.             else
  1702.                 {
  1703.                     m_selectedIndices [ j ] = m_selectedIndices [ i ];
  1704.                     j ++;
  1705.                 }
  1706.         }
  1707.  
  1708.     m_selectedCount = j;
  1709.  
  1710.     m_firstSelectedIndex = (unsigned int)(1 << 31) - 1;
  1711.     m_lastSelectedIndex = -1;
  1712.  
  1713.     for (j = 0; j < m_selectedCount; j ++)
  1714.         {
  1715.             if (m_selectedIndices [ j ] > m_lastSelectedIndex)
  1716.                 m_lastSelectedIndex = m_selectedIndices [ j ];
  1717.             if (m_selectedIndices [ j ] < m_firstSelectedIndex)
  1718.                 m_firstSelectedIndex = m_selectedIndices [ j ];
  1719.         }
  1720.  
  1721.     D(printf ("m_firstSelectedIndex = %d\n", m_firstSelectedIndex);)
  1722.     D(printf ("m_lastSelectedIndex = %d\n", m_lastSelectedIndex);)
  1723. }
  1724.  
  1725. void
  1726. XFE_Outliner::deselectAll()
  1727. {
  1728.     m_selectedCount = 0;
  1729.     m_firstSelectedIndex = (unsigned int)(1 << 31) - 1;
  1730.     m_lastSelectedIndex = -1;
  1731.     m_selectionDirection = 1;
  1732. }
  1733.  
  1734. void
  1735. XFE_Outliner::deselectRangeByIndices(int selection_begin,
  1736.                                      int selection_end)
  1737. {
  1738.     int i;
  1739.  
  1740.     if (selection_begin > selection_end)
  1741.         {
  1742.             int tmp;
  1743.             tmp = selection_end;
  1744.             selection_end = selection_begin;
  1745.             selection_begin = tmp;
  1746.         }
  1747.  
  1748.     for (i = selection_begin; i <= selection_end; i ++)
  1749.         {
  1750.             deselectItem(i);
  1751.         }
  1752. }
  1753.  
  1754. Boolean
  1755. XFE_Outliner::isSelected (int line)
  1756. {
  1757.     int i;
  1758.  
  1759.     for (i = 0; i < m_selectedCount; i ++) 
  1760.         {
  1761.             if ( m_selectedIndices[ i ] == line)
  1762.                 {
  1763.                     return TRUE;
  1764.                 }
  1765.         }
  1766.  
  1767.     return FALSE;
  1768. }
  1769.  
  1770. void
  1771. XFE_Outliner::selectRangeByIndices(int selection_begin, int selection_end)
  1772. {
  1773.     int i;
  1774.  
  1775.     /*
  1776.     ** we need to keep track of the direction the user last selected in
  1777.     ** whether the first selected item was below or above the newest
  1778.     ** selected item.)  This comes in handy in the trimOrExpandSelection
  1779.     ** routine where we need to know which range to deselect.
  1780.     */
  1781.     m_selectionDirection = XfeSgn(selection_end - selection_begin);
  1782.  
  1783.     if (selection_begin > selection_end)
  1784.         {
  1785.             int tmp;
  1786.             tmp = selection_end;
  1787.             selection_end = selection_begin;
  1788.             selection_begin = tmp;
  1789.         }
  1790.  
  1791.     for (i = selection_begin; i <= selection_end; i ++)
  1792.         {
  1793.             selectItem(i);
  1794.         }
  1795. }
  1796.  
  1797. Boolean
  1798. XFE_Outliner::insertLines(int start, int count)
  1799. {
  1800.     int i;
  1801.     XP_Bool firstSelectedDone = False;
  1802.     XP_Bool lastSelectedDone = False;
  1803.  
  1804.     // shift down the selected items (if they're after the start)
  1805.     for (i = 0; i < m_selectedCount; i ++) 
  1806.         {
  1807.             if (m_selectedIndices[ i ] >= start)
  1808.                 {
  1809.                     if (!firstSelectedDone && 
  1810.                         m_selectedIndices[ i ] == m_firstSelectedIndex)
  1811.                         {
  1812.                             m_firstSelectedIndex += count;
  1813.                             firstSelectedDone = True;
  1814.                         }
  1815.  
  1816.                     if (!lastSelectedDone &&
  1817.                         m_selectedIndices[ i ] == m_lastSelectedIndex)
  1818.                         {
  1819.                             m_lastSelectedIndex += count;
  1820.                             lastSelectedDone = True;
  1821.                         }
  1822.  
  1823.                     m_selectedIndices[ i ] += count;
  1824.                 }
  1825.         }
  1826.  
  1827.     // now invalidate the new lines so they get drawn
  1828.     invalidateLines(start, m_totalLines - start + count);
  1829.  
  1830.     return FALSE;
  1831. }
  1832.  
  1833. Boolean
  1834. XFE_Outliner::deleteLines(int start, int count)
  1835. {
  1836.     Boolean res = FALSE;
  1837.     int i, j;
  1838.     XP_Bool firstSelectedDone = False;
  1839.     XP_Bool lastSelectedDone = False;
  1840.  
  1841.  
  1842.     for (i = 0, j = 0; i < m_selectedCount; i++) 
  1843.         {
  1844.             if ( m_selectedIndices[i] >= start ) 
  1845.                 {
  1846.                     if (m_selectedIndices[i] < (start + count)) 
  1847.                         {
  1848.                             res = TRUE;
  1849.                             continue;
  1850.                         } 
  1851.                     else 
  1852.                         {
  1853.                             if (!firstSelectedDone && 
  1854.                                 m_selectedIndices[ i ] == m_firstSelectedIndex)
  1855.                                 {
  1856.                                     m_firstSelectedIndex -= count;
  1857.                                     firstSelectedDone = True;
  1858.                                 }
  1859.                             
  1860.                             if (!lastSelectedDone &&
  1861.                                 m_selectedIndices[ i ] == m_lastSelectedIndex)
  1862.                                 {
  1863.                                     m_lastSelectedIndex -= count;
  1864.                                     lastSelectedDone = True;
  1865.                                 }
  1866.  
  1867.                             m_selectedIndices[i] -= count; // Shift into gap
  1868.                         }
  1869.                 }
  1870.             m_selectedIndices[j] = m_selectedIndices[i];
  1871.             j++;
  1872.         }
  1873.  
  1874.     invalidateLines(start, m_totalLines - start + count);
  1875.  
  1876.     return FALSE;
  1877. }
  1878.  
  1879. void 
  1880. XFE_Outliner::setColumnResizableByIndex(int column_index,
  1881.                                         XP_Bool resizable)
  1882. {
  1883.     if (column_index < m_numvisible)
  1884.         {
  1885.             XtVaSetValues(m_widget,
  1886.                           XmNcolumn, column_index,
  1887.                           XmNcolumnResizable, resizable,
  1888.                           NULL);
  1889.         }
  1890.  
  1891.     m_columnResizable[ column_index ] = resizable;
  1892. }
  1893.  
  1894. XP_Bool
  1895. XFE_Outliner::getColumnResizableByIndex(int column_index)
  1896. {
  1897.     return m_columnResizable[ column_index ];
  1898. }
  1899.  
  1900. void
  1901. XFE_Outliner::setColumnWidthByIndex(int column_index, int width)
  1902. {
  1903.     // clamp the width to within acceptable limits.
  1904.     if (width < MIN_COLUMN_WIDTH)
  1905.         width = MIN_COLUMN_WIDTH;
  1906.     else if (width > MAX_COLUMN_WIDTH)
  1907.         width = MAX_COLUMN_WIDTH;
  1908.  
  1909.     if (column_index < m_numvisible)
  1910.         {
  1911.             XtVaSetValues(m_widget,
  1912.                           XmNcolumn, column_index,
  1913.                           XmNcolumnSizePolicy, XmCONSTANT,
  1914.                           XmNcolumnWidth, width,
  1915.                           NULL);
  1916.         }
  1917.  
  1918.     m_columnwidths[ column_index ] = width;
  1919. }
  1920.  
  1921. int
  1922. XFE_Outliner::getColumnWidthByIndex(int column_index)
  1923. {
  1924.     return m_columnwidths[ column_index ];
  1925. }
  1926.  
  1927. void
  1928. XFE_Outliner::rememberGeometry()
  1929. {
  1930.     int i;
  1931.     char *ptr;
  1932.     int length;
  1933.     Dimension height;
  1934.  
  1935.     FREEIF(m_geominfo);
  1936.  
  1937.     length = m_numcolumns * 25 + 40; /* ### got a better size in mind? */
  1938.  
  1939.     XtVaGetValues(m_widget,
  1940.                   XmNheight, &height,
  1941.                   NULL);
  1942.  
  1943.     m_geominfo = (char*)XP_ALLOC(length);
  1944.     ptr = m_geominfo;
  1945.  
  1946.     PR_snprintf(ptr, m_geominfo + length - ptr,
  1947.                 "%dx(%d)", height, m_numvisible);
  1948.     ptr += strlen(ptr);
  1949.  
  1950.     for (i = 0; i < m_numcolumns; i ++)
  1951.         {
  1952.             PR_snprintf(ptr, m_geominfo + length - ptr,
  1953.                         "%s:%d;", 
  1954.                         m_outlinable->getColumnName(m_columnIndex[i]), 
  1955.                         getColumnWidthByIndex(i));
  1956.  
  1957.             ptr += strlen(ptr);
  1958.         }
  1959.  
  1960.     if (ptr > m_geominfo) *ptr = '\0';
  1961.  
  1962.     if (m_prefname)
  1963.         {
  1964.             D(printf ("PREF[%s] = %s\n", m_prefname, m_geominfo);)
  1965.             PREF_SetCharPref(m_prefname, m_geominfo);
  1966.         }
  1967.  
  1968.     FREEIF(m_geominfo);
  1969. }
  1970.  
  1971. void
  1972. XFE_Outliner::PixmapDraw(Pixmap pixmap, Pixmap mask,
  1973.                          int pixmapWidth, int pixmapHeight, unsigned char alignment, GC gc,
  1974.                          XRectangle *rect, XRectangle *clipRect, Pixel bg_pixel)
  1975. {
  1976.     Display *dpy;
  1977.     Window win;
  1978.     int needsClip;
  1979.     int x, y, width, height;
  1980.  
  1981.     XP_ASSERT(pixmap != (Pixmap)0);
  1982.  
  1983.     if (pixmap == XmUNSPECIFIED_PIXMAP) return;
  1984.     if (rect->width <= 4 || rect->height <= 4) return;
  1985.     if (clipRect->width < 3 || clipRect->height < 3) return;
  1986.     if (!XtIsRealized(m_widget)) return;
  1987.     dpy = XtDisplay(m_widget);
  1988.     win = XtWindow(m_widget);
  1989.  
  1990.     width = pixmapWidth;
  1991.     height = pixmapHeight;
  1992.     if (!width || !height) {
  1993.         alignment = XmALIGNMENT_TOP_LEFT;
  1994.         width = clipRect->width - 4;
  1995.         height = clipRect->height - 4;
  1996.     }
  1997.  
  1998.     if (alignment == XmNONE)
  1999.         {
  2000.             x = rect->x;
  2001.         }
  2002.     else if (alignment == XmALIGNMENT_TOP_LEFT ||
  2003.              alignment == XmALIGNMENT_LEFT ||
  2004.              alignment == XmALIGNMENT_BOTTOM_LEFT) 
  2005.         {
  2006.             x = rect->x + 2;
  2007.         } 
  2008.     else if (alignment == XmALIGNMENT_TOP ||
  2009.              alignment == XmALIGNMENT_CENTER ||
  2010.              alignment == XmALIGNMENT_BOTTOM) 
  2011.         {
  2012.             x = rect->x + ((int)rect->width - width) / 2;
  2013.         } 
  2014.     else 
  2015.         {
  2016.             x = rect->x + rect->width - width - 2;
  2017.         }
  2018.  
  2019.     if (alignment == XmNONE)
  2020.         {
  2021.             y = rect->y;
  2022.         }
  2023.     if (alignment == XmALIGNMENT_TOP ||
  2024.         alignment == XmALIGNMENT_TOP_LEFT ||
  2025.         alignment == XmALIGNMENT_TOP_RIGHT) 
  2026.         {
  2027.             y = rect->y + 2;
  2028.         } 
  2029.     else if (alignment == XmALIGNMENT_LEFT ||
  2030.              alignment == XmALIGNMENT_CENTER ||
  2031.              alignment == XmALIGNMENT_RIGHT) 
  2032.         {
  2033.             y = rect->y + ((int)rect->height - height) / 2;
  2034.         } 
  2035.     else 
  2036.         {
  2037.             y = rect->y + rect->height - height - 2;
  2038.         }
  2039.  
  2040.     needsClip = 1;
  2041.     if (clipRect->x <= x &&
  2042.         clipRect->y <= y &&
  2043.         clipRect->x + clipRect->width >= x + width &&
  2044.         clipRect->y + clipRect->height >= y + height) {
  2045.         needsClip = 0;
  2046.     }
  2047.  
  2048.     if (needsClip) 
  2049.         {
  2050.             Pixmap tmp_pixmap;
  2051.             GC tmp_gc;
  2052.             XWindowAttributes attr;
  2053.  
  2054.             XGetWindowAttributes(dpy, win, &attr);
  2055.             tmp_pixmap = XCreatePixmap(dpy, win, clipRect->width, clipRect->height, attr.depth);
  2056.             tmp_gc = XCreateGC(dpy, tmp_pixmap, 0, NULL);
  2057.  
  2058.             XSetForeground(dpy, tmp_gc, bg_pixel);
  2059.  
  2060.             XFillRectangle(dpy, tmp_pixmap, tmp_gc, 0, 0, clipRect->width + 1, clipRect->height + 1);
  2061.  
  2062.             if (mask)
  2063.                 {
  2064.                     XSetClipMask(dpy, tmp_gc, mask);
  2065.                     XSetClipOrigin(dpy, tmp_gc, 0, 0);
  2066.                 }
  2067.  
  2068.             XCopyArea(dpy, pixmap, tmp_pixmap, tmp_gc, 0, 0, width, height, 0, 0);
  2069.  
  2070.             XFreeGC(dpy, tmp_gc);
  2071.  
  2072.             XSetClipRectangles(dpy, gc, 0, 0, clipRect, 1, Unsorted);
  2073.  
  2074.             XSetGraphicsExposures(dpy, gc, False);
  2075.             XCopyArea(dpy, tmp_pixmap, win, gc, 0, 0, width, height, x, y);
  2076.             XSetGraphicsExposures(dpy, gc, True);
  2077.  
  2078.             XSetClipMask(dpy, gc, None);
  2079.  
  2080.             XFreePixmap(dpy, tmp_pixmap);
  2081.         } 
  2082.     else
  2083.         {
  2084.             if (mask)
  2085.                 {
  2086.                     XSetClipMask(dpy, gc, mask);
  2087.                     XSetClipOrigin(dpy, gc, x, y);
  2088.                 }
  2089.             XSetGraphicsExposures(dpy, gc, False);
  2090.             XCopyArea(dpy, pixmap, win, gc, 0, 0, width, height, x, y);
  2091.             XSetGraphicsExposures(dpy, gc, True);
  2092.  
  2093.             if (mask) 
  2094.                 {
  2095.                     XSetClipMask(dpy, gc, None);
  2096.                 }
  2097.         }
  2098. }
  2099.  
  2100. EOutlinerPipeType
  2101. XFE_Outliner::getPipeType(XP_Bool expandable,
  2102.                           XP_Bool expanded,
  2103.                           int depth,
  2104.                           OutlinerAncestorInfo *ancestorInfo)
  2105. {
  2106.     if (expandable)
  2107.         {
  2108.             if (ancestorInfo->has_prev && ancestorInfo->has_next)
  2109.                 return (expanded ? PIPE_OPENMIDDLEPARENT : PIPE_CLOSEDMIDDLEPARENT);
  2110.             else if (ancestorInfo->has_prev)
  2111.                 return (expanded ? PIPE_OPENBOTTOMPARENT : PIPE_CLOSEDBOTTOMPARENT);
  2112.             else if (ancestorInfo->has_next && depth)
  2113.                 return (expanded ? PIPE_OPENMIDDLEPARENT : PIPE_CLOSEDMIDDLEPARENT);
  2114.             else if (ancestorInfo->has_next)
  2115.                 return (expanded ? PIPE_OPENTOPPARENT : PIPE_CLOSEDTOPPARENT);
  2116.             else if (depth)
  2117.                 return (expanded ? PIPE_OPENBOTTOMPARENT : PIPE_CLOSEDBOTTOMPARENT);
  2118.             else
  2119.                 return (expanded ? PIPE_OPENSINGLEPARENT : PIPE_CLOSEDSINGLEPARENT);
  2120.         }
  2121.     else /* !expandable */
  2122.         {
  2123.             if (ancestorInfo->has_prev && ancestorInfo->has_next)
  2124.                 return PIPE_MIDDLEITEM;
  2125.             else if (ancestorInfo->has_prev)
  2126.                 return PIPE_BOTTOMITEM;
  2127.             else if (ancestorInfo->has_next && depth)
  2128.                 return PIPE_MIDDLEITEM;
  2129.             else if (ancestorInfo->has_next)
  2130.                 return PIPE_TOPITEM;
  2131.             else if (depth)
  2132.                 return PIPE_BOTTOMITEM;
  2133.         }
  2134.  
  2135.     return PIPE_EMPTYITEM;
  2136. }
  2137.  
  2138. void
  2139. XFE_Outliner::drawDottedLine(GC gc,
  2140.                              XRectangle *clipRect,
  2141.                              int x1,
  2142.                              int y1,
  2143.                              int x2,
  2144.                              int y2)
  2145. {
  2146.     int i, x, y;
  2147.     XPoint points[100];
  2148.   
  2149.     i = 0;
  2150.     for (x = x1; x <= x2; x++)
  2151.         for (y = y1; y <= y2; y++)
  2152.             {
  2153.                 if (((x & 1) == (y & 1)) ||
  2154.                     x < clipRect->x ||
  2155.                     x >= (clipRect->x + (int)clipRect->width) ||
  2156.                     y < clipRect->y ||
  2157.                     y >= (clipRect->y + (int)clipRect->height))
  2158.                     continue;
  2159.                 points[i].x = x;
  2160.                 points[i].y = y;
  2161.                 if (++i < 100)
  2162.                     continue;
  2163.                 XDrawPoints(XtDisplay(m_widget), XtWindow(m_widget), gc, points, i, CoordModeOrigin);
  2164.                 i = 0;
  2165.             }
  2166.     if (i)
  2167.         XDrawPoints(XtDisplay(m_widget), XtWindow(m_widget), gc, points, i, CoordModeOrigin);
  2168. }
  2169.  
  2170. void
  2171. XFE_Outliner::pipeDraw(XmLGridCallbackStruct *call)
  2172. {
  2173.     /*
  2174.     ** we draw the pipes necessary for this line, and adjust the 
  2175.     ** rectangles within the callback struct to reflect the new,
  2176.     ** probably smaller, area.
  2177.     */
  2178.     XmLGridDrawStruct *draw = call->drawInfo;
  2179.     Boolean drawSelected = draw->drawSelected;
  2180.     OutlinerAncestorInfo * ancestorInfo;
  2181.     int depth;
  2182.     int i;
  2183.     int maxX = draw->cellRect->width;
  2184.     XP_Bool expanded, expandable;
  2185.  
  2186.     m_outlinable->getTreeInfo(&expandable, &expanded, &depth, &ancestorInfo);
  2187.  
  2188.     XSetForeground(XtDisplay(m_widget), draw->gc, draw->foreground);
  2189.  
  2190.     /* save space to draw the descendantselect stuff. */
  2191.     if (m_descendantSelectAllowed)
  2192.         {
  2193.             draw->cellRect->x += PIPEIMAGESIZE; // XXX
  2194.             draw->cellRect->width -= PIPEIMAGESIZE;
  2195.         }
  2196.  
  2197.     for (i = 0; i < depth; i ++)
  2198.         if ( ( i + 1 ) * PIPEIMAGESIZE <= maxX )
  2199.             if (ancestorInfo && ancestorInfo[ i ].has_next) 
  2200.                 {
  2201.                     // the the vertical pipe for this line's ancestors.
  2202.                     drawDottedLine(draw->gc,
  2203.                                    call->clipRect,
  2204.                                    draw->cellRect->x + PIPEIMAGESIZE/2, draw->cellRect->y,
  2205.                                    draw->cellRect->x + PIPEIMAGESIZE/2, draw->cellRect->y + draw->cellRect->height);
  2206.              
  2207.                     draw->cellRect->x += PIPEIMAGESIZE;
  2208.                     draw->cellRect->width -= PIPEIMAGESIZE;
  2209.                 }
  2210.             else
  2211.                 {
  2212.                     // don't know about this block.. must ask will.
  2213.                     draw->cellRect->x += PIPEIMAGESIZE;
  2214.                     draw->cellRect->width -= PIPEIMAGESIZE;
  2215.                 }
  2216.  
  2217.     if (ancestorInfo) 
  2218.         {
  2219.             fe_icon *parent_icon;
  2220.             fe_icon *spool_icon = NULL;
  2221.             EOutlinerPipeType pipeType = getPipeType(expandable, expanded, depth, &ancestorInfo[depth]);
  2222.  
  2223.             if (m_descendantSelectAllowed && depth == 0 /*&& expandable*/)
  2224.                 spool_icon = m_outlinable->getColumnIcon(-1 /* special super secret column */);
  2225.  
  2226.             // draw the pipe specific to this line
  2227.  
  2228.             switch (pipeType)
  2229.                 {
  2230.                 case PIPE_OPENTOPPARENT:
  2231.                 case PIPE_OPENMIDDLEPARENT:
  2232.                 case PIPE_OPENSINGLEPARENT:
  2233.                 case PIPE_OPENBOTTOMPARENT:
  2234.                     parent_icon = &openParentIcon;
  2235.                     break;
  2236.                 case PIPE_CLOSEDTOPPARENT:
  2237.                 case PIPE_CLOSEDMIDDLEPARENT:
  2238.                 case PIPE_CLOSEDSINGLEPARENT:
  2239.                 case PIPE_CLOSEDBOTTOMPARENT:
  2240.                     parent_icon = &closedParentIcon;
  2241.                     break;
  2242.                 default:
  2243.                     parent_icon = 0;
  2244.                 }
  2245.  
  2246.             if (pipeType == PIPE_CLOSEDSINGLEPARENT
  2247.                 || pipeType == PIPE_OPENSINGLEPARENT)
  2248.                 {
  2249.                     drawDottedLine(draw->gc, 
  2250.                                    call->clipRect,
  2251.                                    draw->cellRect->x + PIPEIMAGESIZE/2, 
  2252.                                    draw->cellRect->y + draw->cellRect->height/2,
  2253.                                    draw->cellRect->x + PIPEIMAGESIZE - 2,
  2254.                                    draw->cellRect->y + draw->cellRect->height/2);
  2255.                 }
  2256.  
  2257.             if (pipeType == PIPE_TOPITEM
  2258.                 || pipeType == PIPE_OPENTOPPARENT
  2259.                 || pipeType == PIPE_CLOSEDTOPPARENT)
  2260.                 {
  2261.                     drawDottedLine(draw->gc, 
  2262.                                    call->clipRect,
  2263.                                    draw->cellRect->x + PIPEIMAGESIZE/2, draw->cellRect->y + draw->cellRect->height/2,
  2264.                                    draw->cellRect->x + PIPEIMAGESIZE/2, draw->cellRect->y + draw->cellRect->height);
  2265.  
  2266.                     drawDottedLine(draw->gc, 
  2267.                                    call->clipRect,
  2268.                                    draw->cellRect->x + PIPEIMAGESIZE/2, 
  2269.                                    draw->cellRect->y + draw->cellRect->height/2,
  2270.                                    draw->cellRect->x + PIPEIMAGESIZE - 2,
  2271.                                    draw->cellRect->y + draw->cellRect->height/2);
  2272.  
  2273.                 }
  2274.             else if (pipeType == PIPE_BOTTOMITEM
  2275.                      || pipeType == PIPE_OPENBOTTOMPARENT
  2276.                      || pipeType == PIPE_CLOSEDBOTTOMPARENT)
  2277.                 {
  2278.                     drawDottedLine(draw->gc, 
  2279.                                    call->clipRect,
  2280.                                    draw->cellRect->x + PIPEIMAGESIZE/2, draw->cellRect->y,
  2281.                                    draw->cellRect->x + PIPEIMAGESIZE/2, draw->cellRect->y + draw->cellRect->height/2);
  2282.  
  2283.                     drawDottedLine(draw->gc, 
  2284.                                    call->clipRect,
  2285.                                    draw->cellRect->x + PIPEIMAGESIZE/2, 
  2286.                                    draw->cellRect->y + draw->cellRect->height/2,
  2287.                                    draw->cellRect->x + PIPEIMAGESIZE - 2,
  2288.                                    draw->cellRect->y + draw->cellRect->height/2);
  2289.                 }
  2290.             else if (pipeType == PIPE_MIDDLEITEM
  2291.                      || pipeType == PIPE_OPENMIDDLEPARENT
  2292.                      || pipeType == PIPE_CLOSEDMIDDLEPARENT)
  2293.                 {
  2294.                     drawDottedLine(draw->gc, 
  2295.                                    call->clipRect,
  2296.                                    draw->cellRect->x + PIPEIMAGESIZE/2, draw->cellRect->y,
  2297.                                    draw->cellRect->x + PIPEIMAGESIZE/2, draw->cellRect->y + draw->cellRect->height);
  2298.       
  2299.                     drawDottedLine(draw->gc, 
  2300.                                    call->clipRect,
  2301.                                    draw->cellRect->x + PIPEIMAGESIZE/2, 
  2302.                                    draw->cellRect->y + draw->cellRect->height/2,
  2303.                                    draw->cellRect->x + PIPEIMAGESIZE - 2,
  2304.                                    draw->cellRect->y + draw->cellRect->height/2);
  2305.                 }
  2306.  
  2307.             if (m_descendantSelectAllowed && spool_icon)
  2308.                 {
  2309.                     // take back our saved space.
  2310.                     draw->cellRect->x -= PIPEIMAGESIZE;
  2311.                     draw->cellRect->width += PIPEIMAGESIZE;
  2312.  
  2313.                     PixmapDraw(spool_icon->pixmap, spool_icon->mask, 
  2314.                                spool_icon->width, spool_icon->height,
  2315.                                XmNONE, draw->gc, draw->cellRect,
  2316.                                call->clipRect,
  2317.                                drawSelected ? draw->selectBackground : draw->background);
  2318.  
  2319.                     draw->cellRect->x += PIPEIMAGESIZE;
  2320.                     draw->cellRect->width -= PIPEIMAGESIZE;
  2321.                 }
  2322.  
  2323.             if (parent_icon)
  2324.                 {
  2325.                     PixmapDraw(parent_icon->pixmap, parent_icon->mask, 
  2326.                                parent_icon->width, parent_icon->height,
  2327.                                XmNONE, draw->gc, draw->cellRect,
  2328.                                call->clipRect,
  2329.                                drawSelected ? draw->selectBackground : draw->background);
  2330.                 }
  2331.  
  2332. #if 0
  2333.             if (pipeType != PIPE_EMPTYITEM)
  2334.                 {
  2335. #endif
  2336.                     draw->cellRect->x += PIPEIMAGESIZE;
  2337.                     draw->cellRect->width -= PIPEIMAGESIZE;
  2338. #if 0
  2339.                 }
  2340. #endif
  2341.         }
  2342. }
  2343.  
  2344. void
  2345. XFE_Outliner::showHeaderClick()
  2346. {
  2347.     D(printf ("trying to show column\n");)
  2348.     if (m_numvisible < m_numcolumns)
  2349.         {
  2350.             showColumn();
  2351.             D(printf ("succeeded.\n");)
  2352.         }
  2353. }
  2354.  
  2355. void
  2356. XFE_Outliner::hideHeaderClick()
  2357. {
  2358.     D(printf ("trying to hide column\n");)
  2359.     if (m_numvisible > 1)
  2360.         {
  2361.             hideColumn();
  2362.             D(printf ("succeeded.\n");)
  2363.         }
  2364. }
  2365.  
  2366. void
  2367. XFE_Outliner::showHeaderDraw(XmLGridCallbackStruct *call)
  2368. {
  2369.     XmLGridDrawStruct *draw = call->drawInfo;
  2370.     Boolean drawSelected = draw->drawSelected;
  2371.     fe_icon *icon;
  2372.  
  2373.     _XmDrawShadows(XtDisplay(m_widget),
  2374.                    XtWindow(m_widget),
  2375.                    ((XmLGridWidget)m_widget)->manager.top_shadow_GC,
  2376.                    ((XmLGridWidget)m_widget)->manager.bottom_shadow_GC,
  2377.                    draw->cellRect->x, draw->cellRect->y,
  2378.                    draw->cellRect->width, draw->cellRect->height,
  2379.                    1, XmSHADOW_OUT);
  2380.  
  2381.     draw->cellRect->x += 1;
  2382.     draw->cellRect->width -= 2;
  2383.     draw->cellRect->y += 1;
  2384.     draw->cellRect->height -= 2;
  2385.  
  2386.     if (m_numvisible < m_numcolumns)
  2387.         icon = &showColumnIcon;
  2388.     else
  2389.         icon = &showColumnInsensIcon;
  2390.     PixmapDraw(icon->pixmap, icon->mask, 
  2391.                icon->width, icon->height,
  2392.                XmALIGNMENT_CENTER, draw->gc, draw->cellRect,
  2393.                call->clipRect,
  2394.                drawSelected ? draw->selectBackground : draw->background);
  2395. }
  2396.  
  2397. void
  2398. XFE_Outliner::hideHeaderDraw(XmLGridCallbackStruct *call)
  2399. {
  2400.     XmLGridDrawStruct *draw = call->drawInfo;
  2401.     Boolean drawSelected = draw->drawSelected;
  2402.     fe_icon *icon;
  2403.  
  2404.     _XmDrawShadows(XtDisplay(m_widget),
  2405.                    XtWindow(m_widget),
  2406.                    ((XmLGridWidget)m_widget)->manager.top_shadow_GC,
  2407.                    ((XmLGridWidget)m_widget)->manager.bottom_shadow_GC,
  2408.                    draw->cellRect->x, draw->cellRect->y,
  2409.                    draw->cellRect->width, draw->cellRect->height,
  2410.                    1, XmSHADOW_OUT);
  2411.   
  2412.     draw->cellRect->x += 1;
  2413.     draw->cellRect->width -= 2;
  2414.     draw->cellRect->y += 1;
  2415.     draw->cellRect->height -= 2;
  2416.  
  2417.     if (m_numvisible > 1)
  2418.         icon = &hideColumnIcon;
  2419.     else
  2420.         icon = &hideColumnInsensIcon;
  2421.  
  2422.     PixmapDraw(icon->pixmap, icon->mask, 
  2423.                icon->width, icon->height,
  2424.                XmALIGNMENT_CENTER, draw->gc, draw->cellRect,
  2425.                call->clipRect,
  2426.                drawSelected ? draw->selectBackground : draw->background);
  2427. }
  2428.  
  2429. void
  2430. XFE_Outliner::headerCellDraw(XmLGridCallbackStruct *call)
  2431. {
  2432.     XmLGridDrawStruct *draw = call->drawInfo;
  2433.     Boolean drawSelected = draw->drawSelected;
  2434.     char *cstr;
  2435.     char *style;
  2436.     fe_icon *icon;
  2437.     int sourcecol;
  2438.     XRectangle /*r,*/ textRect;
  2439.     XmString xmstr = NULL;
  2440.  
  2441.     sourcecol = m_columnIndex[call->column];
  2442.   
  2443.     style = (char*)styleToTag(m_outlinable->getColumnHeaderStyle(sourcecol));
  2444.     cstr = m_outlinable->getColumnHeaderText(sourcecol);
  2445.     icon = m_outlinable->getColumnHeaderIcon(sourcecol);
  2446.   
  2447.     /*
  2448.     ** This is pretty much a hack for the mail/news stuff.
  2449.     ** we need to keep two columns together, one that has an
  2450.     ** icon and one that has text, so we just make them one
  2451.     ** column, and handle the button clicks specially, and also
  2452.     ** draw funky shadows in the case that a header has both
  2453.     ** text and an icon.
  2454.     */
  2455.     if (cstr && icon)
  2456.         {
  2457.             _XmDrawShadows(XtDisplay(m_widget),
  2458.                            XtWindow(m_widget),
  2459.                            ((XmLGridWidget)m_widget)->manager.top_shadow_GC,
  2460.                            ((XmLGridWidget)m_widget)->manager.bottom_shadow_GC,
  2461.                            draw->cellRect->x, draw->cellRect->y,
  2462.                            icon->width + 2, draw->cellRect->height,
  2463.                            1, XmSHADOW_OUT);
  2464.             _XmDrawShadows(XtDisplay(m_widget),
  2465.                            XtWindow(m_widget),
  2466.                            ((XmLGridWidget)m_widget)->manager.top_shadow_GC,
  2467.                            ((XmLGridWidget)m_widget)->manager.bottom_shadow_GC,
  2468.                            draw->cellRect->x + icon->width + 2, 
  2469.                            draw->cellRect->y,
  2470.                            draw->cellRect->width - (icon->width + 2),
  2471.                            draw->cellRect->height,
  2472.                            1, XmSHADOW_OUT);
  2473.         }
  2474.     else
  2475.         {
  2476.             _XmDrawShadows(XtDisplay(m_widget),
  2477.                            XtWindow(m_widget),
  2478.                            ((XmLGridWidget)m_widget)->manager.top_shadow_GC,
  2479.                            ((XmLGridWidget)m_widget)->manager.bottom_shadow_GC,
  2480.                            draw->cellRect->x, draw->cellRect->y,
  2481.                            draw->cellRect->width, draw->cellRect->height,
  2482.                            1, XmSHADOW_OUT);
  2483.         }
  2484.  
  2485.     draw->cellRect->x += 1;
  2486.     draw->cellRect->width -= 2;
  2487.     draw->cellRect->y += 1;
  2488.     draw->cellRect->height -= 2;
  2489.  
  2490.     if (icon)
  2491.         {
  2492.             PixmapDraw(icon->pixmap, icon->mask, 
  2493.                        icon->width, icon->height,
  2494.                        XmALIGNMENT_LEFT, draw->gc, draw->cellRect,
  2495.                        call->clipRect,
  2496.                        drawSelected ? draw->selectBackground : draw->background);
  2497.       
  2498.             textRect.x = draw->cellRect->x + icon->width + 4;
  2499.             textRect.y = draw->cellRect->y;
  2500.             textRect.width = draw->cellRect->width - icon->width - 4;
  2501.             textRect.height = draw->cellRect->height;
  2502.         }
  2503.     else
  2504.         {
  2505.             textRect = *draw->cellRect;
  2506.         }
  2507.  
  2508.     if (cstr)
  2509.         {
  2510.             xmstr = XmStringCreate(cstr, style);
  2511.  
  2512.             XSetForeground(XtDisplay(m_widget), draw->gc,
  2513.                            draw->foreground);
  2514.  
  2515.             XmLStringDraw(m_widget, xmstr, draw->stringDirection, draw->fontList, draw->alignment,
  2516.                           draw->gc, &textRect, call->clipRect);
  2517.         }
  2518.  
  2519.     if (xmstr) XmStringFree(xmstr);
  2520.  
  2521.     if (sourcecol == m_sortColumn
  2522.         && textRect.width > textRect.height - 4)
  2523.         {
  2524.             int arrow_direction = (m_sortDirection == OUTLINER_SortAscending 
  2525.                                    ? XmARROW_DOWN : XmARROW_UP);
  2526.             int arrow_size = textRect.height - 4;
  2527.  
  2528.             if (arrow_size > 0)
  2529.                 {
  2530.                     XSetForeground(XtDisplay(m_widget), draw->gc,
  2531.                                    draw->background);
  2532.                     
  2533.                     _XmDrawArrow(XtDisplay(m_widget),
  2534.                                  XtWindow(m_widget),
  2535.                                  ((XmManagerWidget)m_widget)->manager.bottom_shadow_GC,
  2536.                                  ((XmManagerWidget)m_widget)->manager.top_shadow_GC,
  2537.                                  draw->gc,
  2538.                                  textRect.x + textRect.width - arrow_size - 4,
  2539.                                  textRect.y + (textRect.height / 2 - arrow_size / 2),
  2540.                                  arrow_size,
  2541.                                  arrow_size,
  2542.                                  2,
  2543.                                  arrow_direction);
  2544.                 }
  2545.         }
  2546. }
  2547.  
  2548. void
  2549. XFE_Outliner::contentCellDraw(XmLGridCallbackStruct *call)
  2550. {
  2551.     XmLGridDrawStruct *draw = call->drawInfo;
  2552.     Boolean drawSelected = draw->drawSelected;
  2553.     char *cstr;
  2554.     XmString xmstr = NULL;
  2555.     fe_icon *icon;
  2556.     XRectangle textRect;
  2557.     int sourcecol;
  2558.  
  2559.     /*
  2560.     ** This function will get called (potentially) many times for
  2561.     ** one line -- once per cell.  We only do the aquireLineData
  2562.     ** once, for the first cell.
  2563.     */
  2564.     if (call->row != m_DataRow) 
  2565.         {
  2566.             // if the last line was valid, get rid of it.
  2567.             if (m_DataRow != -1)
  2568.                 m_outlinable->releaseLineData();
  2569.  
  2570.             m_DataRow = call->row;
  2571.  
  2572.             // get the new line's info.
  2573.             if (! m_outlinable->acquireLineData(call->row) )
  2574.                 {
  2575.                     m_DataRow = -1;
  2576.                     return;
  2577.                 }
  2578.         }
  2579.  
  2580.     sourcecol = m_columnIndex[call->column];
  2581.  
  2582.     cstr = m_outlinable->getColumnText(sourcecol);
  2583.     icon = m_outlinable->getColumnIcon(sourcecol);
  2584.  
  2585.     if (sourcecol == m_pipeColumn)
  2586.         pipeDraw(call);
  2587.  
  2588.     /* if there's an icon, we need to push the text over. */
  2589.     if (icon)
  2590.         {
  2591.             PixmapDraw(icon->pixmap, icon->mask, 
  2592.                        icon->width, icon->height,
  2593.                        XmALIGNMENT_LEFT, draw->gc, draw->cellRect,
  2594.                        call->clipRect,
  2595.                        drawSelected ? draw->selectBackground : draw->background);
  2596.       
  2597.             textRect.x = draw->cellRect->x + icon->width + 4;
  2598.             textRect.y = draw->cellRect->y;
  2599.             textRect.width = draw->cellRect->width - icon->width - 4;
  2600.             textRect.height = draw->cellRect->height;
  2601.         }
  2602.     else
  2603.         {
  2604.             textRect = *draw->cellRect;
  2605.         }
  2606.  
  2607.     if (cstr)
  2608.         if (call->clipRect->width > 4) 
  2609.             {
  2610.                 /* Impose some spacing between columns.  What a hack. ### */
  2611.                 call->clipRect->width -= 4;
  2612.     
  2613.                 xmstr = XmStringCreate(cstr, (char*)styleToTag(m_outlinable->getColumnStyle(sourcecol)));
  2614.     
  2615.                 XSetForeground(XtDisplay(m_widget), draw->gc,
  2616.                                drawSelected ? draw->selectForeground : draw->foreground);
  2617.  
  2618.                 XmLStringDraw(m_widget, xmstr, draw->stringDirection, draw->fontList, draw->alignment,
  2619.                               draw->gc, &textRect, call->clipRect);
  2620.  
  2621.                 call->clipRect->width += 4;
  2622.             }
  2623.  
  2624.     if (call->row == m_dragrow && sourcecol >= 0)
  2625.         {
  2626.             int y;
  2627.             int x2 = draw->cellRect->x + draw->cellRect->width - 1;
  2628.             XP_Bool rightedge = FALSE;
  2629.             if (call->column == m_numcolumns - 1) 
  2630.                 {
  2631.                     rightedge = TRUE;
  2632. #ifdef TERRYS_RIGHT_COLUMN_WIDTH_HACK
  2633.                     if (xmstr) 
  2634.                         {
  2635.                             int xx = draw->cellRect->x + XmStringWidth(draw->fontList, xmstr) + 4;
  2636.                             if (x2 > xx) x2 = xx;
  2637.                         }
  2638. #endif
  2639.                 }
  2640.  
  2641.             if (m_draggc == NULL) 
  2642.                 {
  2643.                     XGCValues gcv;
  2644. #if 0
  2645.                     Pixel foreground;
  2646. #endif
  2647.                     gcv.foreground = drawSelected ? draw->selectForeground : draw->foreground;
  2648.  
  2649.                     m_draggc = XCreateGC(XtDisplay(m_widget), XtWindow(m_widget),
  2650.                                          GCForeground, &gcv);
  2651.                 }
  2652.             y = draw->cellRect->y + draw->cellRect->height - 1;
  2653.             XDrawLine(XtDisplay(m_widget), XtWindow(m_widget), m_draggc,
  2654.                       draw->cellRect->x, y, x2, y);
  2655.             if (m_dragrowbox) 
  2656.                 {
  2657.                     int y0 = draw->cellRect->y;
  2658.                     if (call->column == 0) 
  2659.                         {
  2660.                             XDrawLine(XtDisplay(m_widget), XtWindow(m_widget), m_draggc,
  2661.                                       draw->cellRect->x, y0, draw->cellRect->x, y);
  2662.                         }
  2663.                     if (rightedge) 
  2664.                         {
  2665.                             XDrawLine(XtDisplay(m_widget), XtWindow(m_widget), m_draggc,
  2666.                                       x2, y0, x2, y);
  2667.                         }    
  2668.                     XDrawLine(XtDisplay(m_widget), XtWindow(m_widget), m_draggc,
  2669.                               draw->cellRect->x, y0, x2, y0);
  2670.                 }
  2671.         }
  2672.   
  2673.     if (xmstr) XmStringFree(xmstr);
  2674. }
  2675.  
  2676. void
  2677. XFE_Outliner::celldraw(XtPointer callData)
  2678. {
  2679.     XmLGridCallbackStruct* call = (XmLGridCallbackStruct*) callData;
  2680.  
  2681.     if (call->rowType == XmHEADING)
  2682.         if (m_hideColumnsAllowed
  2683.             && call->column >= m_numvisible)
  2684.             {
  2685.                 if (call->column == m_numvisible)
  2686.                     showHeaderDraw(call);
  2687.                 else
  2688.                     hideHeaderDraw(call);
  2689.             }
  2690.         else
  2691.             {
  2692.                 headerCellDraw(call);
  2693.             }
  2694.     else /* XmCONTENT */
  2695.         if (! m_hideColumnsAllowed
  2696.             || call->column < m_numvisible)
  2697.             contentCellDraw(call);
  2698. }
  2699.  
  2700. void
  2701. XFE_Outliner::resize(XtPointer callData)
  2702. {
  2703.     XmLGridCallbackStruct *cbs = (XmLGridCallbackStruct*)callData;
  2704.     int i;
  2705.     int width_of_visible_columns = 0;
  2706.     int width_of_grid = XtWidth(m_widget) - 2 * MGR_ShadowThickness(m_widget);
  2707.     int delta;
  2708.  
  2709.     /*
  2710.     ** in the event of a widget resize, we do the following:
  2711.     ** o All resizable, visible columns are resized equally.
  2712.     **
  2713.     ** in the event of a column resize, we do the following:
  2714.     ** o resize the leftmost resizable column to the right of the column
  2715.     **   that was resized larger or smaller.
  2716.     **
  2717.     ** we don't allow the right hand side of the right most visible column to
  2718.     ** be dragged.
  2719.     */
  2720.  
  2721.     XP_ASSERT(m_widget);
  2722.     if(!m_widget)
  2723.         return;
  2724.  
  2725.     for (i = 0; i < m_numvisible + (m_hideColumnsAllowed ? 2 : 0); i ++)
  2726.         {
  2727.           /*
  2728.           ** don't change this to calls to getColumnWidthByIndex.  It doesn't
  2729.           ** work
  2730.           ** correctly in the face of the show/hide buttons.
  2731.           */
  2732.             XmLGridColumn col;
  2733.             Dimension column_width = 0;
  2734.             
  2735.             col = XmLGridGetColumn(m_widget, XmCONTENT, i);
  2736.             XtVaGetValues(m_widget,
  2737.                           XmNcolumnPtr, col,
  2738.                           XmNcolumnWidth, &column_width,
  2739.                           NULL);
  2740.             
  2741.             width_of_visible_columns += column_width;
  2742.         }
  2743.  
  2744.     delta = width_of_grid - width_of_visible_columns;
  2745.  
  2746.     if (delta == 0)
  2747.       {
  2748.         /*
  2749.         ** even if the outliner doesn't change in width, we still need to
  2750.         ** remember the geometry so that the height will come back the same
  2751.         */
  2752.         rememberGeometry();
  2753.         return;
  2754.       }
  2755.  
  2756.     /*
  2757.     ** The grid resize handling is simple.  We just figure out the delta and
  2758.     ** apply it to all columns of the grid. We also make sure to resize the
  2759.     ** columns that are not visible, so that when they are next shown they
  2760.     ** don't overwhelm the outliner.
  2761.     */
  2762.     if (cbs->reason == XmCR_RESIZE_GRID)
  2763.         {
  2764.             D(    printf ("Inside XFE_Outliner::resize(GRID)\n");) 
  2765.             int num_resizable;
  2766.             
  2767.             D( printf ("Width of visible columns is %d.  Width of outliner is %d\n",
  2768.                        width_of_visible_columns, width_of_grid); )
  2769.                     
  2770.             num_resizable = numResizableVisibleColumns();
  2771.             
  2772.             XtVaSetValues(m_widget,
  2773.                           XmNlayoutFrozen, True,
  2774.                           NULL);
  2775.             
  2776.             // apply the delta to the visible columns.
  2777.             applyDelta(delta);
  2778.             
  2779.             /*
  2780.             ** now we resize the hidden columns so when they are unhidden
  2781.             ** their size is in line with what we've been doing to the
  2782.             ** outliner -- shrinking or expanding.  You dig?
  2783.             */
  2784.             for (i = m_numvisible; i < m_numcolumns; i ++)
  2785.                 {
  2786.                     if (getColumnResizableByIndex(i))
  2787.                         {
  2788.                             m_columnwidths[ i ] += delta / m_numcolumns;
  2789.                             
  2790.                             if (m_columnwidths[ i ] < MIN_COLUMN_WIDTH)
  2791.                                 m_columnwidths[ i ] = MIN_COLUMN_WIDTH;
  2792.                             if (m_columnwidths[ i ] > MAX_COLUMN_WIDTH)
  2793.                                 m_columnwidths[ i ] = MAX_COLUMN_WIDTH;
  2794.                         }
  2795.                 }
  2796.             
  2797.             XtVaSetValues(m_widget,
  2798.                           XmNlayoutFrozen, False,
  2799.                           NULL);
  2800.         }
  2801.     /*
  2802.     ** The column resize handling is a bit more involved than the grid resize
  2803.     ** handling.  The grid actually resizes the column before invoking this
  2804.     ** callback, so we can figure out the delta the same way we do above.  So,
  2805.     ** the delta will be negative if the user dragged the column to the right,
  2806.     ** and positive if they dragged to the left.
  2807.     **
  2808.     ** We apply the delta to all the columns to the right of the resized one,
  2809.     ** and if their is any residual, unapplied delta we add it to the width of
  2810.     ** the resized column.
  2811.     */
  2812.     else if (cbs->reason == XmCR_RESIZE_COLUMN)
  2813.         {
  2814.             D(    printf ("Inside XFE_Outliner::resize(COLUMN, %d)\n", cbs->column);) 
  2815.             Dimension resize_column_width;
  2816.             int delta_left;
  2817.  
  2818.             XtVaSetValues(m_widget,
  2819.                           XmNlayoutFrozen, True,
  2820.                           NULL);
  2821.             
  2822.             delta_left = applyDelta(delta, cbs->column + 1);
  2823.  
  2824.             D(printf ("delta_left is %d, delta was %d\n", delta_left, delta);)
  2825.  
  2826.               /*
  2827.             ** our m_columnwidths array isn't updated by the grid for the
  2828.             ** resized column, so we have to use GetValues to get it.  It's
  2829.             ** set below (taking into account any unapplied delta.
  2830.             */
  2831.             {
  2832.                 XmLGridColumn col;
  2833.                 Dimension column_width = 0;
  2834.                 
  2835.                 col = XmLGridGetColumn(m_widget, XmCONTENT, cbs->column);
  2836.                 XtVaGetValues(m_widget,
  2837.                               XmNcolumnPtr, col,
  2838.                               XmNcolumnWidth, &column_width,
  2839.                               NULL);
  2840.                 
  2841.                 resize_column_width = column_width;
  2842.             }
  2843.  
  2844.             if (delta_left != 0)
  2845.                 resize_column_width += delta_left;
  2846.  
  2847.             setColumnWidthByIndex(cbs->column, resize_column_width);
  2848.  
  2849.             XtVaSetValues(m_widget,
  2850.                           XmNlayoutFrozen, False,
  2851.                           NULL);
  2852.         }
  2853.     else
  2854.         {
  2855.             XP_ASSERT(0);
  2856.         }
  2857.  
  2858.     rememberGeometry();
  2859. }
  2860.  
  2861. void
  2862. XFE_Outliner::outlineLine(int line)
  2863. {
  2864.     int old = m_dragrow;
  2865.     if (old == line && m_dragrowbox) return;
  2866.     m_dragrowbox = TRUE;
  2867.     m_dragrow = line;
  2868.     if (old >= 0) invalidateLine(old);
  2869.     if (line >= 0 && line != old) invalidateLine(line);
  2870. }
  2871.  
  2872. void
  2873. XFE_Outliner::underlineLine(int line)
  2874. {
  2875.     int old = m_dragrow;
  2876.     if (old == line && !m_dragrowbox) return;
  2877.     m_dragrowbox = FALSE;
  2878.     m_dragrow = line;
  2879.     if (old >= 0) invalidateLine(old);
  2880.     if (line >= 0 && line != old) invalidateLine(line);
  2881. }
  2882.  
  2883. void
  2884. XFE_Outliner::sendClick(XEvent *event,
  2885.                         Boolean only_if_not_selected)
  2886. {
  2887.     int x = event->xbutton.x;
  2888.     int y = event->xbutton.y;
  2889.     int button = ((XButtonEvent *)event)->button;
  2890.     int numclicks = 1;
  2891.     unsigned char rowtype;
  2892.     unsigned char coltype;
  2893.     int row;
  2894.     int column;
  2895.     unsigned int state = event->xbutton.state;
  2896.     int sourcecol;
  2897.     XRectangle rect;
  2898.  
  2899.     if (!only_if_not_selected &&
  2900.         abs(x - m_lastx) < 5 && abs(y - m_lasty) < 5 &&
  2901.         (m_lastdowntime - m_lastuptime <=
  2902.          XtGetMultiClickTime(XtDisplay(m_widget)))) {
  2903.         numclicks = 2;        /* ### Allow triple clicks? */
  2904.     }
  2905.     m_lastx = x;
  2906.     m_lasty = y;
  2907.  
  2908.     if (XmLGridXYToRowColumn(m_widget, x, y,
  2909.                              &rowtype, &row, &coltype, &column) >= 0) 
  2910.         {
  2911.             rect.x = 0;
  2912.             rect.y = 0;
  2913.             XmLGridRowColumnToXY(m_widget, rowtype, row, coltype, column,
  2914.                                  False, &rect);
  2915.  
  2916.             if (rowtype == XmHEADING) row = -1;
  2917.  
  2918.             m_activity = ButtonPressMask;
  2919.             m_ignoreevents = True;
  2920.  
  2921.             if (column >= m_numvisible && m_hideColumnsAllowed)
  2922.                 {
  2923.                     if (row != -1)
  2924.                         return;
  2925.  
  2926.                     if (column == m_numvisible)
  2927.                         {
  2928.                             showHeaderClick();
  2929.                         }
  2930.                     else
  2931.                         {
  2932.                             hideHeaderClick();
  2933.                         }
  2934.                 }
  2935.             else
  2936.                 {
  2937.                     sourcecol = m_columnIndex[column];
  2938.  
  2939.                     /* make the x and y coordinates local to the cell. */
  2940.                     x -= rect.x;
  2941.                     y -= rect.y;
  2942.  
  2943.                     if (sourcecol == m_pipeColumn && !only_if_not_selected && row >= 0)
  2944.                         {
  2945.                             int depth;
  2946.                             XP_Bool expandable;
  2947.                             int flippy_offset = 0;
  2948.  
  2949.                             m_flippyfunc_data->row = row;
  2950.                             m_flippyfunc_data->do_selection = FALSE;
  2951.           
  2952.                             m_DataRow = row;
  2953.                             m_outlinable->acquireLineData(m_DataRow);
  2954.                             m_outlinable->getTreeInfo(&expandable, NULL, &depth, NULL);
  2955.                             m_outlinable->releaseLineData();
  2956.  
  2957.                             if (m_descendantSelectAllowed)
  2958.                                 flippy_offset += PIPEIMAGESIZE; // XXX
  2959.  
  2960.                             flippy_offset += depth * PIPEIMAGESIZE;
  2961.  
  2962.                             if (expandable)
  2963.                                 if (x >= flippy_offset && x <= flippy_offset + PIPEIMAGESIZE)
  2964.                                     {
  2965.                                         if (numclicks == 1) 
  2966.                                             {
  2967.                                                 m_outlinable->Flippyfunc(m_flippyfunc_data);
  2968.                                             }
  2969.                                         
  2970.                                         return;
  2971.                                     }
  2972.                                 else if (m_descendantSelectAllowed && x > 0 && x < flippy_offset)
  2973.                                     {
  2974.                                         if (numclicks == 1)
  2975.                                             {
  2976.                                                 m_flippyfunc_data->do_selection = TRUE;
  2977.                                                 m_outlinable->Flippyfunc(m_flippyfunc_data);
  2978.                                             }
  2979.  
  2980.                                         return;
  2981.                                     }
  2982.                             // else we drop out and hit the buttonfunc stuff.
  2983.                         }
  2984.       
  2985.                     m_buttonfunc_data->x = x;
  2986.                     m_buttonfunc_data->y = y;
  2987.                     m_buttonfunc_data->row = row;
  2988.                     m_buttonfunc_data->column = sourcecol;
  2989.                     m_buttonfunc_data->clicks = numclicks;
  2990.                     m_buttonfunc_data->shift = ((state & ShiftMask) != 0);
  2991.                     m_buttonfunc_data->ctrl = ((state & ControlMask) != 0);
  2992.                     m_buttonfunc_data->button = button;
  2993.                     // alt?  how are we supposed to do that?
  2994.  
  2995.                     if (m_selBlocked)
  2996.                         XBell(XtDisplay(m_widget), 100);
  2997.                     else
  2998.                         m_outlinable->Buttonfunc(m_buttonfunc_data);
  2999.  
  3000.                 }
  3001.         }
  3002. }
  3003.  
  3004. void
  3005. XFE_Outliner::buttonEvent(XEvent *event, Boolean *c)
  3006. {
  3007.     int x = event->xbutton.x;
  3008.     int y = event->xbutton.y;
  3009.     unsigned char rowtype;
  3010.     unsigned char coltype;
  3011.  
  3012.     /* Fix UMR && 83752
  3013.      */
  3014.     int row = 0;
  3015.     int column = 0;
  3016.  
  3017.     m_ignoreevents = False;
  3018.  
  3019.     switch (event->type)
  3020.         {
  3021.         case ButtonPress:
  3022.             /* Always ignore btn3. Btn3 is for popups. - dp */
  3023.             if (event->xbutton.button == 3) break;
  3024.  
  3025.             if (XmLGridXYToRowColumn(m_widget, x, y,
  3026.                                      &rowtype, &row, &coltype, &column) >= 0) 
  3027.                 {
  3028.                     if (rowtype == XmHEADING) 
  3029.                         {
  3030.  
  3031.                             if (XmLGridPosIsResize(m_widget, x, y)) 
  3032.                                 {
  3033.                                     break;
  3034.                                 }
  3035.                         }
  3036.                     m_activity |= ButtonPressMask;
  3037.                     m_ignoreevents = True;
  3038. #if !defined(USE_MOTIF_DND)
  3039.                     m_dragcolumn = column;
  3040. #endif /* USE_MOTIF_DND */
  3041.                 }
  3042.  
  3043. #if !defined(USE_MOTIF_DND)
  3044.             m_lastmotionx = x;
  3045.             m_lastmotiony = y;
  3046.  
  3047.             // Save this position off so we can create the drag widget
  3048.             // in the right place if we're going to drag.  Subtract the
  3049.             // (row, col) offset first.
  3050.             {
  3051.                 XRectangle hotRect;
  3052.                 int sourceDepth = 0;  // Source icon indented this many times.
  3053.                 XmLGridRowColumnToXY(m_widget, 
  3054.                                      rowtype, row,
  3055.                                      coltype, column, 
  3056.                                      False, &hotRect);
  3057.     
  3058.                 // Calculate the outline-indent offset.
  3059.                 m_DataRow = row;
  3060.                 m_outlinable->acquireLineData(row);
  3061.                 m_outlinable->getTreeInfo(NULL, NULL, &sourceDepth, NULL);
  3062.                 m_outlinable->releaseLineData();
  3063.  
  3064.                 D(printf("sourceDepth = %d\n", sourceDepth);)
  3065.       
  3066.                     // Remember to add one for the flippy.
  3067.                     m_hotSpot_x = x - hotRect.x - ((sourceDepth+1)*PIPEIMAGESIZE);
  3068.                     m_hotSpot_y = y - hotRect.y;
  3069.             } 
  3070.  
  3071. #endif /* USE_MOTIF_DND */
  3072.             m_lastdowntime = event->xbutton.time;
  3073.             break;
  3074.  
  3075.         case ButtonRelease:
  3076.             if (m_activity & ButtonPressMask)
  3077. #if defined(USE_MOTIF_DND)
  3078.               sendClick(event, FALSE);
  3079. #else
  3080.                 {
  3081.                     if (m_activity & PointerMotionMask)
  3082.                         {
  3083.                             /* handle the drop */
  3084.                             fe_dnd_DoDrag(&_xfe_dragsource, event, FE_DND_DROP);
  3085.                             fe_dnd_DoDrag(&_xfe_dragsource, event, FE_DND_END);
  3086.           
  3087.                             destroyDragWidget();
  3088.                         }
  3089.                     else
  3090.                         {
  3091.                             sendClick(event, FALSE);
  3092.                         }
  3093.                 }
  3094.  
  3095. #endif /* USE_MOTIF_DND */
  3096.             
  3097.             m_lastuptime = event->xbutton.time;
  3098.             m_activity = 0;
  3099.  
  3100.             break;
  3101.  
  3102. #if !defined(USE_MOTIF_DND)
  3103. #ifdef NONMOTIF_DND
  3104.         case MotionNotify:
  3105.             XmLGridXYToRowColumn(m_widget, x, y,
  3106.                                  &rowtype, &row, &coltype, &column);
  3107.             
  3108.             if (!(m_activity & PointerMotionMask) &&
  3109.                 (abs(x - m_lastmotionx) < 5 && abs(y - m_lastmotiony) < 5))
  3110.                 {
  3111.                     /* We aren't yet dragging, and the mouse hasn't moved enough for
  3112.                        this to be considered a drag. */
  3113.  
  3114.                     break;
  3115.                 }
  3116.  
  3117.             if (m_activity & ButtonPressMask) 
  3118.                 {
  3119.                     /* The type of stuff we're going to drag. */
  3120.                     fe_dnd_Type drag_type;
  3121.  
  3122.                     /* ok, the pointer moved while a button was held.
  3123.                      * we're gonna drag some stuff.
  3124.                      */
  3125.                     m_ignoreevents = True;
  3126.       
  3127.                     if (!(m_activity & PointerMotionMask)) 
  3128.                         {
  3129.                             if (m_dragtype == FE_DND_NONE)
  3130.                                 {
  3131.                                     /* We don't do drag'n'drop in this context.  Do any any visibility
  3132.                                        scrolling that we may have been putting off til the end of user
  3133.                                        activity. */
  3134.                                     m_activity = 0;
  3135.           
  3136. #ifdef notyet
  3137.                                     if (info->visibleLine >= 0 && info->visibleTimer == NULL) {
  3138.                                         fe_OutlineMakeVisible(info->widget, info->visibleLine);
  3139.                                         info->visibleLine = -1;
  3140.                                     }
  3141. #endif
  3142.                                     break;
  3143.                                 }
  3144.           
  3145.                             /* First time.  If the item we're pointing at isn't
  3146.                                selected, deliver a click message for it (which ought to
  3147.                                select it.) */
  3148.           
  3149.                             if (rowtype == XmCONTENT) 
  3150.                                 {
  3151.                                     /* Hack things so we click where the mouse down was, not where
  3152.                                        the first notify event was.  Bleah.  But, only if the
  3153.                                        item was previously unselected. */
  3154.                                     int actual_row = XYToRow(m_lastmotionx, m_lastmotiony);
  3155.  
  3156.                                     if (!isSelected(actual_row))
  3157.                                         {
  3158.                                             event->xbutton.x = m_lastmotionx;
  3159.                                             event->xbutton.y = m_lastmotiony;
  3160.                                             sendClick(event, TRUE);
  3161.                                         }
  3162.                                     drag_type = m_dragtype;
  3163.                                 }
  3164.                             else // it happened in a column header.
  3165.                                 {
  3166.                                     // don't allow dragging of the show/hide buttons.
  3167.                                     if (m_dragcolumn >= m_numvisible)
  3168.                                         break;
  3169.  
  3170.                                     drag_type = FE_DND_COLUMN;
  3171.                                 }
  3172.  
  3173.           
  3174.                             // Create a drag source.
  3175.                             // We want the mouse-down location, not the last one. 
  3176.                             event->xbutton.x = x;
  3177.                             event->xbutton.y = y;
  3178.                             makeDragWidget(m_hotSpot_x, m_hotSpot_y, drag_type);
  3179.           
  3180.                             fe_dnd_DoDrag(&_xfe_dragsource, event, FE_DND_START);
  3181.           
  3182.                             m_activity |= PointerMotionMask;
  3183.                         }
  3184.       
  3185.                     fe_dnd_DoDrag(&_xfe_dragsource, event, FE_DND_DRAG);
  3186.       
  3187.                     /* Now, force all the additional mouse motion events that are
  3188.                        lingering around on the server to come to us, so that Xt can
  3189.                        compress them away.  Yes, XSync really does improve performance
  3190.                        in this case, not hurt it. */
  3191.                     XSync(XtDisplay(m_widget), False);
  3192.                 }
  3193.       
  3194.             m_lastmotionx = x;
  3195.             m_lastmotiony = y;
  3196.             break;
  3197. #endif /* NONMOTIF_DND */
  3198. #endif /* !USE_MOTIF_DND */
  3199.         }
  3200.     if (m_ignoreevents) 
  3201.         *c = False;
  3202. }
  3203.  
  3204. #if !defined(USE_MOTIF_DND)
  3205. void
  3206. XFE_Outliner::makeDragWidget(int x, int y, fe_dnd_Type dnd_type)
  3207. {
  3208.     Visual *v = 0;
  3209.     Colormap cmap = 0;
  3210.     Cardinal depth = 0;
  3211.     Widget label;
  3212.     //  fe_icon *icon;
  3213.     Widget shell;
  3214.     Pixmap dragPixmap;
  3215.  
  3216.     D(printf("hot (x,y) = (%d,%d)\n", x, y);)
  3217.  
  3218.         if (_xfe_dragsource.widget) return;  
  3219.  
  3220.         shell = m_toplevel->getBaseWidget();
  3221.  
  3222.         XtVaGetValues (shell, XtNvisual, &v, XtNcolormap, &cmap,
  3223.                        XtNdepth, &depth, 0);
  3224.  
  3225.         _xfe_dragsource.type = dnd_type;
  3226.  
  3227. #if 0
  3228.         // This only works if we're dragging from the icon.
  3229.         // Dragging from some random part of the line gives some
  3230.         // really weird offset for the drag.  -mcafee
  3231.         _xfe_dragsource.hotx = x;
  3232.         _xfe_dragsource.hoty = y;
  3233. #else
  3234.         // Trying some fixed offset; offset of zero sucks.
  3235.     _xfe_dragsource.hotx = 8;
  3236.         _xfe_dragsource.hoty = 8;
  3237. #endif
  3238.  
  3239.         _xfe_dragsource.closure = dnd_type == FE_DND_COLUMN ? (void*)this : (void*)m_source;
  3240.         _xfe_dragsource.func = m_sourcedropfunc;
  3241.  
  3242.         XP_ASSERT(m_dragicon);
  3243.         if (m_dragicon == NULL) return;
  3244.  
  3245.         // XXX this needs to be something special when type == FE_DND_COLUMN
  3246.         dragPixmap = m_dragicon->pixmap;
  3247.  
  3248.         _xfe_dragsource.widget = XtVaCreateWidget("drag_win",
  3249.                                                   overrideShellWidgetClass,
  3250.                                                   m_widget,
  3251.                                                   XmNwidth, m_dragicon->width,
  3252.                                                   XmNheight, m_dragicon->height,
  3253.                                                   XmNvisual, v,
  3254.                                                   XmNcolormap, cmap,
  3255.                                                   XmNdepth, depth,
  3256.                                                   XmNborderWidth, 0,
  3257.                                                   NULL);
  3258.   
  3259.         label = XtVaCreateManagedWidget ("label",
  3260.                                          xmLabelWidgetClass,
  3261.                                          _xfe_dragsource.widget,
  3262.                                          XmNlabelType, XmPIXMAP,
  3263.                                          XmNlabelPixmap, dragPixmap,
  3264.                                          NULL);
  3265. }
  3266.  
  3267. void
  3268. XFE_Outliner::destroyDragWidget()
  3269. {
  3270.     if (!_xfe_dragsource.widget) return;
  3271.     XtDestroyWidget (_xfe_dragsource.widget);
  3272.     _xfe_dragsource.widget = NULL;
  3273. }
  3274.  
  3275. void
  3276. XFE_Outliner::handleDragEvent(XEvent *event,
  3277.                               fe_dnd_Event type,
  3278.                               fe_dnd_Source *source)
  3279. {
  3280.     // only handle column drags that originated in this outliner.
  3281.     if (source->type != FE_DND_COLUMN || source->closure != this) return;
  3282.  
  3283.     switch (type)
  3284.         {
  3285.         case FE_DND_DROP:
  3286.             {
  3287.                 unsigned char rowtype;
  3288.                 unsigned char coltype;
  3289.                 int row;
  3290.                 int column;
  3291.                 int x, y;
  3292.  
  3293.                 D( printf ("Dropping column %d into an outliner\n", m_dragcolumn);)
  3294.  
  3295.                     /* first we make sure that the drop happens within a valid row/column
  3296.                        pair. */
  3297.     
  3298.                     translateFromRootCoords(event->xbutton.x_root, event->xbutton.y_root, &x, &y);
  3299.     
  3300.                     D( printf (" Drop position is (%d,%d)\n", x, y); )
  3301.  
  3302.                         if (XmLGridXYToRowColumn(m_widget, x, y,
  3303.                                                  &rowtype, &row, &coltype, &column) < 0)
  3304.                             {
  3305.                                 D( printf ("Not dropping in a valid position\n");)
  3306.                                     return;
  3307.                             }
  3308.  
  3309.                         // don't allow dropping onto the show/hide columns */
  3310.                         if (column >= m_numvisible)
  3311.                           return;
  3312.  
  3313.                         /* we only need to actually do anything if they drop on a different
  3314.                            column than they started with. */
  3315.                         if (column != m_dragcolumn) 
  3316.                             moveColumn(m_dragcolumn, column);
  3317.  
  3318.                         break;
  3319.             }
  3320.         }
  3321. }
  3322. #endif /* USE_MOTIF_DND */
  3323.  
  3324. void 
  3325. XFE_Outliner::celldrawCallback(Widget,
  3326.                                XtPointer clientData,
  3327.                                XtPointer callData)
  3328. {
  3329.     XFE_Outliner *obj = (XFE_Outliner*)clientData;
  3330.  
  3331.     obj->celldraw(callData);
  3332. }
  3333.  
  3334. void
  3335. XFE_Outliner::resizeCallback(Widget,
  3336.                              XtPointer clientData,
  3337.                              XtPointer callData)
  3338. {
  3339.     XFE_Outliner *obj = (XFE_Outliner*)clientData;
  3340.  
  3341.     obj->resize(callData);
  3342. }
  3343.  
  3344. void 
  3345. XFE_Outliner::buttonEventHandler(Widget,
  3346.                                  XtPointer clientData,
  3347.                                  XEvent *event,
  3348.                                  Boolean *cont)
  3349. {
  3350.     XFE_Outliner *obj = (XFE_Outliner*)clientData;
  3351.  
  3352.     obj->buttonEvent(event, cont);
  3353. }
  3354.  
  3355. const char *
  3356. XFE_Outliner::styleToTag(EOutlinerTextStyle style)
  3357. {
  3358.     switch (style) 
  3359.         {
  3360.         case OUTLINER_Italic:
  3361.             return "ITALIC";
  3362.         case OUTLINER_Bold:
  3363.             return "BOLD";
  3364.         case OUTLINER_Default:
  3365.             return XmFONTLIST_DEFAULT_TAG;
  3366.         default:
  3367.             XP_ASSERT(0);
  3368.             return XmFONTLIST_DEFAULT_TAG;
  3369.         }
  3370. }
  3371.  
  3372. void
  3373. XFE_Outliner::change(int first, int length, int newnumrows)
  3374. {
  3375.     if (newnumrows != m_totalLines) 
  3376.         {
  3377.             int old_totalLines = m_totalLines;
  3378.       
  3379.             // update totalLines here, since adding the rows and 
  3380.             // redisplaying them might cause the outlinable to ask 
  3381.             // us how many lines we have, and we should return the 
  3382.             // new number.
  3383.             m_totalLines = newnumrows;
  3384.  
  3385.             if (newnumrows > old_totalLines) 
  3386.                 {
  3387.                     XmLGridAddRows(m_widget, XmCONTENT, -1,
  3388.                                    m_totalLines - old_totalLines);
  3389.                 } 
  3390.             else 
  3391.                 {
  3392.                     XmLGridDeleteRows(m_widget, XmCONTENT, m_totalLines,
  3393.                                       old_totalLines - m_totalLines);
  3394.                 }
  3395.  
  3396.             length = m_totalLines - first;
  3397.         }
  3398.  
  3399.     if (first == 0 && length == m_totalLines)
  3400.         {
  3401.             invalidate();
  3402.         } 
  3403.     else 
  3404.         {
  3405.             invalidateLines(first, length);
  3406.         }
  3407.  
  3408.     XFlush(XtDisplay(m_widget));
  3409. }
  3410.  
  3411. void 
  3412. XFE_Outliner::listChangeStarting(XP_Bool /*asynchronous*/,
  3413.                                  MSG_NOTIFY_CODE notify,
  3414.                                  MSG_ViewIndex /*where*/,
  3415.                                  int32 /*num*/,
  3416.                                  int32 /*totallines*/)
  3417. {
  3418.   /* we need to save off the selected items so they can be restored in
  3419.      listChangeFinished. we only do this once for a given series of nested
  3420.      changes */
  3421.   if (m_listChangeDepth == 0
  3422.       /* don't need to save selection when items change their contents*/
  3423.       && notify != MSG_NotifyChanged)
  3424.     {
  3425.       saveSelection();
  3426.       
  3427.       deselectAllItems();
  3428.     }
  3429.   
  3430.   m_listChangeDepth ++;
  3431. }
  3432.  
  3433. void
  3434. XFE_Outliner::listChangeFinished(XP_Bool /*asynchronous*/,
  3435.                                  MSG_NOTIFY_CODE notify,
  3436.                                  MSG_ViewIndex where,
  3437.                                  int32 num, int32 totallines)
  3438. {
  3439.     m_listChangeDepth--;
  3440.  
  3441.     XP_ASSERT(m_listChangeDepth >= 0); // should _never_ be negative.
  3442.  
  3443.     switch (notify) {
  3444.     case MSG_NotifyChanged:
  3445.         invalidateLines(where, num);
  3446.         return;
  3447.     case MSG_NotifyNone:
  3448. #if 0
  3449.         if (MSG_GetPaneType(pane) == MSG_SEARCHPANE) /* For search dialog */ 
  3450.             if ( CONTEXT_DATA(context)->searchFinishedFunc)
  3451.                 (*(CONTEXT_DATA(context)->searchFinishedFunc))(context);
  3452.         return;
  3453. #endif
  3454.         break;
  3455.     case MSG_NotifyInsertOrDelete: /*  Needed for search */
  3456.         break;
  3457.     case MSG_NotifyScramble:
  3458.     case MSG_NotifyAll:
  3459.         where = 0;
  3460.         num = totallines;
  3461.         break;
  3462.     }
  3463.  
  3464.     change(where, num, totallines);
  3465.  
  3466.     if (m_listChangeDepth == 0)
  3467.         restoreSelection();
  3468. }
  3469.  
  3470. int XFE_Outliner::getListChangeDepth() {
  3471.     return m_listChangeDepth;
  3472. }
  3473.  
  3474. Widget 
  3475. XFE_Outliner::getScroller() 
  3476. {
  3477.   Widget scroller;
  3478.  
  3479.   XtVaGetValues (m_widget, XmNverticalScrollBar, &scroller, 0);
  3480.  
  3481.   return scroller;
  3482. }
  3483.  
  3484.  
  3485. void
  3486. XFE_Outliner::saveSelection()
  3487. {
  3488.     if (!m_selectedItems)
  3489.         {
  3490.             int i;
  3491.       
  3492.             if (m_selectedCount)
  3493.                 {
  3494.                     m_selectedItems = (void**)XP_CALLOC(m_selectedCount,
  3495.                                                         sizeof(void*));
  3496.       
  3497.                     for (i = 0; i < m_selectedCount; i ++)
  3498.                         {
  3499.                           D( printf ("Saving selecting at index: %d\n",
  3500.                                      m_selectedIndices[ i ]); )
  3501.                            m_selectedItems[ i ] =
  3502.                             m_outlinable->ConvFromIndex(m_selectedIndices[i]);
  3503.                         }
  3504.                     
  3505.                     m_selectedItemCount = m_selectedCount;
  3506.                 }
  3507.         }
  3508. }
  3509.  
  3510. void
  3511. XFE_Outliner::restoreSelection()
  3512. {
  3513.     if (m_selectedItems)
  3514.         {
  3515.             int i;
  3516.  
  3517.             for (i = 0; i < m_selectedItemCount; i ++)
  3518.                 {
  3519.                     int index = m_outlinable->ConvToIndex(m_selectedItems[i]);
  3520.  
  3521.                     if (index > -1 && index < m_totalLines)
  3522.                         {
  3523.                             D( printf ("Restoring selecting at index: %d\n",
  3524.                                        index); )
  3525.  
  3526.                             selectItem(index);
  3527.                         }
  3528.                 }
  3529.  
  3530.             XP_FREE(m_selectedItems);
  3531.             m_selectedItemCount = 0;
  3532.             m_selectedItems = NULL;
  3533.         }
  3534. }
  3535.  
  3536. XFE_Outlinable *
  3537. XFE_Outliner::getOutlinable()
  3538. {
  3539.   return m_outlinable;
  3540. }
  3541.