home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / src / BookmarkBase.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  52.9 KB  |  1,972 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. /*                                                                        */
  20. /* Name:        BookmarkBase.cpp                                        */
  21. /* Description:    XFE_BookmarkBase class source.                            */
  22. /*                Base class for components dealing with bookmarks.        */
  23. /* Author:        Ramiro Estrugo <ramiro@netscape.com>                    */
  24. /* Date:        Tue Mar  4 03:45:16 PST 1997                            */
  25.  
  26.  
  27. /*                                                                        */
  28. /*----------------------------------------------------------------------*/
  29.  
  30. #include "BookmarkBase.h"
  31. #include "MozillaApp.h"
  32. #include "IconGroup.h"
  33. #include "View.h"
  34. #include "ToolbarDrop.h"
  35. #include "PersonalToolbar.h"
  36.  
  37. #include "bkmks.h"
  38. #include "felocale.h"
  39. #include "intl_csi.h"
  40.  
  41. #include <Xfe/XfeAll.h>
  42.  
  43. #include <Xm/CascadeB.h>
  44. #include <Xm/PushB.h>
  45. #include <Xm/Separator.h>
  46.  
  47. #define MORE_BUTTON_NAME            "bookmarkMoreButton"
  48. #define MORE_PULLDOWN_NAME            "bookmarkPulldown"
  49. #define MENU_PANE_SEPARATOR_NAME    "menuPaneSeparator"
  50. #define TOOL_BAR_SEPARATOR_NAME        "toolBarSeparator"
  51.  
  52. //////////////////////////////////////////////////////////////////////////
  53. //
  54. // Used to pass data to the callbacks
  55. //
  56. //////////////////////////////////////////////////////////////////////////
  57. typedef struct _BookmarkCallbackStruct
  58. {
  59.     XFE_BookmarkBase *    object;        // The object
  60.     BM_Entry *            entry;        // The bookmark entry
  61. } BookmarkCallbackStruct;
  62. //////////////////////////////////////////////////////////////////////////
  63.  
  64.  
  65.  
  66. //////////////////////////////////////////////////////////////////////////
  67. XFE_BookmarkBase::XFE_BookmarkBase(MWContext *    bookmarkContext,
  68.                                    XFE_Frame *    frame,
  69.                                    XP_Bool        onlyHeaders,
  70.                                    XP_Bool        fancyItems) :
  71.     _bookmarkContext(bookmarkContext),
  72.     _frame(frame),
  73.     _onlyHeaders(onlyHeaders),
  74.     _fancyItems(fancyItems),
  75.     _charSetInfo(LO_GetDocumentCharacterSetInfo(_bookmarkContext)),
  76.     _dropAddressBuffer(NULL),
  77.     _dropTitleBuffer(NULL),
  78.     _dropLastAccess(0)
  79. {
  80.     XP_ASSERT( _frame != NULL );
  81.  
  82.     // Ask MozillaApp to let us know when the bookmarks change
  83.     XFE_MozillaApp::theApp()->registerInterest(
  84.         XFE_MozillaApp::bookmarksHaveChanged,
  85.         this,
  86.         (XFE_FunctionNotification) bookmarksChanged_cb,
  87.         this);
  88.  
  89.     XFE_MozillaApp::theApp()->registerInterest(
  90.         XFE_MozillaApp::updateToolbarAppearance,
  91.         this,
  92.         (XFE_FunctionNotification)updateIconAppearance_cb);
  93.  
  94.     // the personal toolbar folder
  95.     XFE_MozillaApp::theApp()->registerInterest(
  96.         XFE_MozillaApp::personalToolbarFolderChanged,
  97.         this,
  98.         (XFE_FunctionNotification)updatePersonalToolbarFolderName_cb);
  99.  
  100.     createPixmaps();
  101. }
  102. //////////////////////////////////////////////////////////////////////////
  103. /* virtual */
  104. XFE_BookmarkBase::~XFE_BookmarkBase()
  105. {
  106.     XFE_MozillaApp::theApp()->unregisterInterest(
  107.         XFE_MozillaApp::bookmarksHaveChanged,
  108.         this,
  109.         (XFE_FunctionNotification) bookmarksChanged_cb,
  110.         this);
  111.  
  112.     XFE_MozillaApp::theApp()->unregisterInterest(
  113.         XFE_MozillaApp::updateToolbarAppearance,
  114.         this,
  115.         (XFE_FunctionNotification)updateIconAppearance_cb);
  116.  
  117.     // the personal toolbar folder
  118.     XFE_MozillaApp::theApp()->unregisterInterest(
  119.         XFE_MozillaApp::personalToolbarFolderChanged,
  120.         this,
  121.         (XFE_FunctionNotification)updatePersonalToolbarFolderName_cb);
  122.  
  123.     if (_dropAddressBuffer)
  124.     {
  125.         XtFree(_dropAddressBuffer);
  126.     }
  127.  
  128.     if (_dropTitleBuffer)
  129.     {
  130.         XtFree(_dropTitleBuffer);
  131.     }
  132. }
  133. //////////////////////////////////////////////////////////////////////////
  134.  
  135. Pixmap XFE_BookmarkBase::_bookmarkPixmap = XmUNSPECIFIED_PIXMAP;
  136. Pixmap XFE_BookmarkBase::_bookmarkMask = XmUNSPECIFIED_PIXMAP;
  137.  
  138. Pixmap XFE_BookmarkBase::_bookmarkChangedPixmap = XmUNSPECIFIED_PIXMAP;
  139. Pixmap XFE_BookmarkBase::_bookmarkChangedMask = XmUNSPECIFIED_PIXMAP;
  140.  
  141. Pixmap XFE_BookmarkBase::_mailBookmarkPixmap = XmUNSPECIFIED_PIXMAP;
  142. Pixmap XFE_BookmarkBase::_mailBookmarkMask = XmUNSPECIFIED_PIXMAP;
  143.  
  144. Pixmap XFE_BookmarkBase::_newsBookmarkPixmap = XmUNSPECIFIED_PIXMAP;
  145. Pixmap XFE_BookmarkBase::_newsBookmarkMask = XmUNSPECIFIED_PIXMAP;
  146.  
  147. Pixmap XFE_BookmarkBase::_folderArmedPixmap = XmUNSPECIFIED_PIXMAP;
  148. Pixmap XFE_BookmarkBase::_folderArmedMask = XmUNSPECIFIED_PIXMAP;
  149. Pixmap XFE_BookmarkBase::_folderPixmap = XmUNSPECIFIED_PIXMAP;
  150. Pixmap XFE_BookmarkBase::_folderMask = XmUNSPECIFIED_PIXMAP;
  151.  
  152. Pixmap XFE_BookmarkBase::_personalFolderArmedMask = XmUNSPECIFIED_PIXMAP;
  153. Pixmap XFE_BookmarkBase::_personalFolderArmedPixmap = XmUNSPECIFIED_PIXMAP;
  154. Pixmap XFE_BookmarkBase::_personalFolderMask = XmUNSPECIFIED_PIXMAP;
  155. Pixmap XFE_BookmarkBase::_personalFolderPixmap = XmUNSPECIFIED_PIXMAP;
  156.  
  157. Pixmap XFE_BookmarkBase::_newFolderArmedMask = XmUNSPECIFIED_PIXMAP;
  158. Pixmap XFE_BookmarkBase::_newFolderArmedPixmap = XmUNSPECIFIED_PIXMAP;
  159. Pixmap XFE_BookmarkBase::_newFolderMask = XmUNSPECIFIED_PIXMAP;
  160. Pixmap XFE_BookmarkBase::_newFolderPixmap = XmUNSPECIFIED_PIXMAP;
  161.  
  162. Pixmap XFE_BookmarkBase::_menuFolderArmedMask = XmUNSPECIFIED_PIXMAP;
  163. Pixmap XFE_BookmarkBase::_menuFolderArmedPixmap = XmUNSPECIFIED_PIXMAP;
  164. Pixmap XFE_BookmarkBase::_menuFolderMask = XmUNSPECIFIED_PIXMAP;
  165. Pixmap XFE_BookmarkBase::_menuFolderPixmap = XmUNSPECIFIED_PIXMAP;
  166.  
  167. Pixmap XFE_BookmarkBase::_newMenuFolderArmedMask = XmUNSPECIFIED_PIXMAP;
  168. Pixmap XFE_BookmarkBase::_newMenuFolderArmedPixmap = XmUNSPECIFIED_PIXMAP;
  169. Pixmap XFE_BookmarkBase::_newMenuFolderMask = XmUNSPECIFIED_PIXMAP;
  170. Pixmap XFE_BookmarkBase::_newMenuFolderPixmap = XmUNSPECIFIED_PIXMAP;
  171.  
  172. Pixmap XFE_BookmarkBase::_newPersonalFolderArmedMask = XmUNSPECIFIED_PIXMAP;
  173. Pixmap XFE_BookmarkBase::_newPersonalFolderArmedPixmap = XmUNSPECIFIED_PIXMAP;
  174. Pixmap XFE_BookmarkBase::_newPersonalFolderMask = XmUNSPECIFIED_PIXMAP;
  175. Pixmap XFE_BookmarkBase::_newPersonalFolderPixmap = XmUNSPECIFIED_PIXMAP;
  176.  
  177. Pixmap XFE_BookmarkBase::_newPersonalMenuFolderArmedMask = XmUNSPECIFIED_PIXMAP;
  178. Pixmap XFE_BookmarkBase::_newPersonalMenuFolderArmedPixmap = XmUNSPECIFIED_PIXMAP;
  179. Pixmap XFE_BookmarkBase::_newPersonalMenuFolderMask = XmUNSPECIFIED_PIXMAP;
  180. Pixmap XFE_BookmarkBase::_newPersonalMenuFolderPixmap = XmUNSPECIFIED_PIXMAP;
  181.  
  182. //////////////////////////////////////////////////////////////////////////
  183. void
  184. XFE_BookmarkBase::createPixmaps()
  185. {
  186.     // Create icons
  187.      Pixel fg = XfeForeground(_frame->getBaseWidget());
  188.      Pixel bg = XfeBackground(_frame->getBaseWidget());
  189.  
  190.     if (!XfePixmapGood(XFE_BookmarkBase::_bookmarkPixmap))
  191.     {
  192.         IconGroup_createAllIcons(&BM_Bookmark_group,
  193.                                  _frame->getBaseWidget(),
  194.                                  fg,bg);
  195.  
  196.         _bookmarkPixmap = BM_Bookmark_group.pixmap_icon.pixmap;
  197.         _bookmarkMask = BM_Bookmark_group.pixmap_icon.mask;
  198.     }
  199.  
  200.     if (!XfePixmapGood(XFE_BookmarkBase::_bookmarkChangedPixmap))
  201.     {
  202.         IconGroup_createAllIcons(&BM_Change_group,
  203.                                  _frame->getBaseWidget(),
  204.                                  fg,bg);
  205.  
  206.         _bookmarkChangedPixmap = BM_Change_group.pixmap_icon.pixmap;
  207.         _bookmarkChangedMask = BM_Change_group.pixmap_icon.mask;
  208.     }
  209.  
  210.     if (!XfePixmapGood(XFE_BookmarkBase::_mailBookmarkPixmap))
  211.     {
  212.         IconGroup_createAllIcons(&BM_MailBookmark_group,
  213.                                  _frame->getBaseWidget(),
  214.                                  fg,bg);
  215.  
  216.         _mailBookmarkPixmap = BM_MailBookmark_group.pixmap_icon.pixmap;
  217.         _mailBookmarkMask = BM_MailBookmark_group.pixmap_icon.mask;
  218.     }
  219.  
  220.     if (!XfePixmapGood(XFE_BookmarkBase::_newsBookmarkPixmap))
  221.     {
  222.         IconGroup_createAllIcons(&BM_NewsBookmark_group,
  223.                                  _frame->getBaseWidget(),
  224.                                  fg,bg);
  225.  
  226.         _newsBookmarkPixmap = BM_NewsBookmark_group.pixmap_icon.pixmap;
  227.         _newsBookmarkMask = BM_NewsBookmark_group.pixmap_icon.mask;
  228.     }
  229.  
  230.     if (!XfePixmapGood(XFE_BookmarkBase::_folderPixmap))
  231.     {
  232.         IconGroup_createAllIcons(&BM_Folder_group,
  233.                                  _frame->getBaseWidget(),
  234.                                  fg,bg);
  235.  
  236.         _folderPixmap = BM_Folder_group.pixmap_icon.pixmap;
  237.         _folderMask = BM_Folder_group.pixmap_icon.mask;
  238.     }
  239.  
  240.     if (!XfePixmapGood(XFE_BookmarkBase::_folderArmedPixmap))
  241.     {
  242.         IconGroup_createAllIcons(&BM_FolderO_group,
  243.                                  _frame->getBaseWidget(),
  244.                                  fg,bg);
  245.  
  246.         _folderArmedPixmap = BM_FolderO_group.pixmap_icon.pixmap;
  247.         _folderArmedMask = BM_FolderO_group.pixmap_icon.mask;
  248.     }
  249.  
  250.     if (!XfePixmapGood(XFE_BookmarkBase::_personalFolderPixmap))
  251.     {
  252.         IconGroup_createAllIcons(&BM_PersonalFolder_group,
  253.                                  _frame->getBaseWidget(),
  254.                                  fg,bg);
  255.  
  256.         _personalFolderPixmap = BM_PersonalFolder_group.pixmap_icon.pixmap;
  257.         _personalFolderMask = BM_PersonalFolder_group.pixmap_icon.mask;
  258.     }
  259.  
  260.     if (!XfePixmapGood(XFE_BookmarkBase::_personalFolderArmedPixmap))
  261.     {
  262.         IconGroup_createAllIcons(&BM_PersonalFolderO_group,
  263.                                  _frame->getBaseWidget(),
  264.                                  fg,bg);
  265.  
  266.         _personalFolderArmedPixmap = BM_PersonalFolderO_group.pixmap_icon.pixmap;
  267.         _personalFolderArmedMask = BM_PersonalFolderO_group.pixmap_icon.mask;
  268.     }
  269.  
  270.     if (!XfePixmapGood(XFE_BookmarkBase::_newFolderPixmap))
  271.     {
  272.         IconGroup_createAllIcons(&BM_NewFolder_group,
  273.                                  _frame->getBaseWidget(),
  274.                                  fg,bg);
  275.  
  276.         _newFolderPixmap = BM_NewFolder_group.pixmap_icon.pixmap;
  277.         _newFolderMask = BM_NewFolder_group.pixmap_icon.mask;
  278.     }
  279.  
  280.     if (!XfePixmapGood(XFE_BookmarkBase::_newFolderArmedPixmap))
  281.     {
  282.         IconGroup_createAllIcons(&BM_NewFolderO_group,
  283.                                  _frame->getBaseWidget(),
  284.                                  fg,bg);
  285.  
  286.         _newFolderArmedPixmap = BM_NewFolderO_group.pixmap_icon.pixmap;
  287.         _newFolderArmedMask = BM_NewFolderO_group.pixmap_icon.mask;
  288.     }
  289.  
  290.     if (!XfePixmapGood(XFE_BookmarkBase::_menuFolderPixmap))
  291.     {
  292.         IconGroup_createAllIcons(&BM_MenuFolder_group,
  293.                                  _frame->getBaseWidget(),
  294.                                  fg,bg);
  295.  
  296.         _menuFolderPixmap = BM_MenuFolder_group.pixmap_icon.pixmap;
  297.         _menuFolderMask = BM_MenuFolder_group.pixmap_icon.mask;
  298.     }
  299.  
  300.     if (!XfePixmapGood(XFE_BookmarkBase::_menuFolderArmedPixmap))
  301.     {
  302.         IconGroup_createAllIcons(&BM_MenuFolderO_group,
  303.                                  _frame->getBaseWidget(),
  304.                                  fg,bg);
  305.  
  306.         _menuFolderArmedPixmap = BM_MenuFolderO_group.pixmap_icon.pixmap;
  307.         _menuFolderArmedMask = BM_MenuFolderO_group.pixmap_icon.mask;
  308.     }
  309.  
  310.     if (!XfePixmapGood(XFE_BookmarkBase::_newMenuFolderPixmap))
  311.     {
  312.         IconGroup_createAllIcons(&BM_NewAndMenuFolder_group,
  313.                                  _frame->getBaseWidget(),
  314.                                  fg,bg);
  315.  
  316.         _newMenuFolderPixmap = BM_NewAndMenuFolder_group.pixmap_icon.pixmap;
  317.         _newMenuFolderMask = BM_NewAndMenuFolder_group.pixmap_icon.mask;
  318.     }
  319.  
  320.     if (!XfePixmapGood(XFE_BookmarkBase::_newMenuFolderArmedPixmap))
  321.     {
  322.         IconGroup_createAllIcons(&BM_NewAndMenuFolderO_group,
  323.                                  _frame->getBaseWidget(),
  324.                                  fg,bg);
  325.  
  326.         _newMenuFolderArmedPixmap = BM_NewAndMenuFolderO_group.pixmap_icon.pixmap;
  327.         _newMenuFolderArmedMask = BM_NewAndMenuFolderO_group.pixmap_icon.mask;
  328.     }
  329.  
  330.     if (!XfePixmapGood(XFE_BookmarkBase::_newPersonalFolderPixmap))
  331.     {
  332.         IconGroup_createAllIcons(&BM_NewPersonalFolder_group,
  333.                                  _frame->getBaseWidget(),
  334.                                  fg,bg);
  335.  
  336.         _newPersonalFolderPixmap = BM_NewPersonalFolder_group.pixmap_icon.pixmap;
  337.         _newPersonalFolderMask = BM_NewPersonalFolder_group.pixmap_icon.mask;
  338.     }
  339.  
  340.     if (!XfePixmapGood(XFE_BookmarkBase::_newPersonalFolderArmedPixmap))
  341.     {
  342.         IconGroup_createAllIcons(&BM_NewPersonalFolderO_group,
  343.                                  _frame->getBaseWidget(),
  344.                                  fg,bg);
  345.  
  346.         _newPersonalFolderArmedPixmap = BM_NewPersonalFolderO_group.pixmap_icon.pixmap;
  347.         _newPersonalFolderArmedMask = BM_NewPersonalFolderO_group.pixmap_icon.mask;
  348.     }
  349.  
  350.     if (!XfePixmapGood(XFE_BookmarkBase::_newPersonalMenuFolderPixmap))
  351.     {
  352.         IconGroup_createAllIcons(&BM_NewPersonalMenu_group,
  353.                                  _frame->getBaseWidget(),
  354.                                  fg,bg);
  355.  
  356.         _newPersonalMenuFolderPixmap = BM_NewPersonalMenu_group.pixmap_icon.pixmap;
  357.         _newPersonalMenuFolderMask = BM_NewPersonalMenu_group.pixmap_icon.mask;
  358.     }
  359.  
  360.     if (!XfePixmapGood(XFE_BookmarkBase::_newPersonalMenuFolderArmedPixmap))
  361.     {
  362.         IconGroup_createAllIcons(&BM_NewPersonalMenuO_group,
  363.                                  _frame->getBaseWidget(),
  364.                                  fg,bg);
  365.  
  366.         _newPersonalMenuFolderArmedPixmap = BM_NewPersonalMenuO_group.pixmap_icon.pixmap;
  367.         _newPersonalMenuFolderArmedMask = BM_NewPersonalMenuO_group.pixmap_icon.mask;
  368.     }
  369. }
  370. //////////////////////////////////////////////////////////////////////////
  371.  
  372. /* static */ void
  373. XFE_BookmarkBase::item_armed_cb(Widget        w,
  374.                                 XtPointer    clientData,
  375.                                 XtPointer    /* call_data */)
  376. {
  377.     BookmarkCallbackStruct *    data = (BookmarkCallbackStruct *) clientData;
  378.     XFE_BookmarkBase *            object = data->object;
  379.     BM_Entry *                    entry = data->entry;
  380.  
  381.     object->entryArmed(w,entry);
  382. }
  383. //////////////////////////////////////////////////////////////////////////
  384. /* static */ void
  385. XFE_BookmarkBase::item_enter_cb(Widget        w,
  386.                                 XtPointer    clientData,
  387.                                 XtPointer    /* call_data */)
  388. {
  389.     BookmarkCallbackStruct *    data = (BookmarkCallbackStruct *) clientData;
  390.     XFE_BookmarkBase *            object = data->object;
  391.     BM_Entry *                    entry = data->entry;
  392.  
  393.     object->entryEnter(w,entry);
  394. }
  395. //////////////////////////////////////////////////////////////////////////
  396. /* static */ void
  397. XFE_BookmarkBase::item_leave_cb(Widget    w,
  398.                                   XtPointer    clientData,
  399.                                   XtPointer    /* call_data */)
  400. {
  401.     BookmarkCallbackStruct *    data = (BookmarkCallbackStruct *) clientData;
  402.     XFE_BookmarkBase *            object = data->object;
  403.     BM_Entry *                    entry = data->entry;
  404.  
  405.     object->entryLeave(w,entry);
  406. }
  407. //////////////////////////////////////////////////////////////////////////
  408. /* static */ void
  409. XFE_BookmarkBase::item_disarmed_cb(Widget        w,
  410.                                    XtPointer    clientData,
  411.                                    XtPointer    /* call_data */)
  412. {
  413.     BookmarkCallbackStruct *    data = (BookmarkCallbackStruct *) clientData;
  414.     XFE_BookmarkBase *            object = data->object;
  415.     BM_Entry *                    entry = data->entry;
  416.  
  417.     object->entryDisarmed(w,entry);
  418. }
  419. //////////////////////////////////////////////////////////////////////////
  420. /* static */ void
  421. XFE_BookmarkBase::item_activated_cb(Widget        w,
  422.                                     XtPointer    clientData,
  423.                                     XtPointer    /* call_data */)
  424. {
  425.     BookmarkCallbackStruct *    data = (BookmarkCallbackStruct *) clientData;
  426.     XFE_BookmarkBase *            object = data->object;
  427.     BM_Entry *                    entry = data->entry;
  428.  
  429.     if (XfeBmAccentIsEnabled() && (XfeIsBmButton(w) || XfeIsBmCascade(w)))
  430.     {
  431.         unsigned char accent_type;
  432.         
  433.         XtVaGetValues(w,XmNaccentType,&accent_type,NULL);
  434.  
  435.         // Add the new entry above the activated bookmark item
  436.         if (accent_type == XmACCENT_TOP)
  437.         {
  438.             object->addEntryBefore(object->getDropAddress(),
  439.                                    object->getDropTitle(),
  440.                                    object->getDropLastAccess(),
  441.                                    entry);
  442.         }
  443.         // Add the new entry below the activated bookmark item
  444.         else if (accent_type == XmACCENT_BOTTOM)
  445.         {
  446.             object->addEntryAfter(object->getDropAddress(),
  447.                                   object->getDropTitle(),
  448.                                   object->getDropLastAccess(),
  449.                                   entry);
  450.         }
  451.         // Add the new entry into the activated bookmark folder
  452.         else if (accent_type == XmACCENT_ALL)
  453.         {
  454.             object->addEntryToFolder(object->getDropAddress(),
  455.                                      object->getDropTitle(),
  456.                                      object->getDropLastAccess(),
  457.                                      entry);
  458.         }
  459.         
  460.         // Now disable dropping
  461.         object->disableDropping();
  462.     }
  463.     // A fancy cascade button was activated
  464.     else if (XmIsCascadeButton(w) && entry && BM_IsHeader(entry))
  465.     {
  466.         XFE_Frame *        frame = object->getFrame();
  467.         MWContext *        context = frame->getContext();
  468.         History_entry * he = SHIST_GetCurrent(&context->hist);
  469.  
  470.         char *            address;
  471.         char *            title;
  472.         BM_Date            lastAccess;
  473.  
  474.         XP_ASSERT( frame != NULL );
  475.         XP_ASSERT( context != NULL );
  476.         XP_ASSERT( he != NULL );
  477.  
  478.         address = he->address;
  479.         
  480.         title = (he->title && *he->title) ? he->title : address;
  481.  
  482.         lastAccess = he->last_access;
  483.  
  484.         object->addEntryToFolder(address,title,lastAccess,entry);
  485.     }
  486.     // A push button was activated
  487.     else
  488.     {
  489.         object->entryActivated(w,entry);
  490.     }
  491. }
  492. //////////////////////////////////////////////////////////////////////////
  493. /* static */ void
  494. XFE_BookmarkBase::item_cascading_cb(Widget        cascade,
  495.                                     XtPointer    clientData,
  496.                                     XtPointer    /* call_data */)
  497. {
  498.     BookmarkCallbackStruct *    data = (BookmarkCallbackStruct *) clientData;
  499.     XFE_BookmarkBase *            object = data->object;
  500.     BM_Entry *                    entry = data->entry;
  501.     Widget                        submenu = NULL;
  502.  
  503.     XtVaGetValues(cascade,XmNsubMenuId,&submenu,NULL);
  504.  
  505.     if (entry && submenu) 
  506.     {
  507.         XP_ASSERT(BM_IsHeader(entry));
  508.  
  509.         // Add the first it in a "File Bookmark" hierarchy.  This should
  510.         // only happen if _onlyHeaders is true and the current bookmark
  511.         // header has at least one item that is also a header.
  512.         if (object->_onlyHeaders)
  513.         {
  514.             Widget file_here = object->createCascadeButton(submenu,entry,True);
  515.             Widget sep = object->createSeparator(submenu);
  516.  
  517.             XtManageChild(file_here);
  518.             XtManageChild(sep);
  519.         }
  520.  
  521.         object->createItemTree(submenu,BM_GetChildren(entry));
  522.     }
  523.  
  524.     XtRemoveCallback(cascade,
  525.                      XmNcascadingCallback,
  526.                      &XFE_BookmarkBase::item_cascading_cb,
  527.                      (XtPointer) data);
  528.  
  529.     object->entryCascading(cascade,entry);
  530. }
  531. //////////////////////////////////////////////////////////////////////////
  532. /* static */ void
  533. XFE_BookmarkBase::item_free_data_cb(Widget        /* item */,
  534.                                     XtPointer    clientData,
  535.                                     XtPointer    /* call_data */)
  536. {
  537.     BookmarkCallbackStruct *    data = (BookmarkCallbackStruct *) clientData;
  538.  
  539.     XP_FREE(data);
  540. }
  541. //////////////////////////////////////////////////////////////////////////
  542. /* static */ void
  543. XFE_BookmarkBase::pane_mapping_eh(Widget        submenu,
  544.                                   XtPointer        clientData,
  545.                                   XEvent *        event,
  546.                                   Boolean *        cont)
  547. {
  548.      XFE_BookmarkBase * object = (XFE_BookmarkBase *) clientData;
  549.  
  550.     // Make sure the widget is alive and this is an unmap event
  551.     if (!XfeIsAlive(submenu) || !event || (event->type != UnmapNotify))
  552.     {
  553.         return;
  554.     }
  555.  
  556.     // Look for the cascade ancestor
  557.     Widget cascade = 
  558.         XfeAncestorFindByClass(submenu,xfeCascadeWidgetClass,XfeFIND_ANY);
  559.                
  560.     if (cascade)
  561.     {
  562.         Boolean armed;
  563.  
  564.         // Determine if the cascade is armed
  565.         XtVaGetValues(cascade,XmNarmed,&armed,NULL);
  566.  
  567.         // If it is armed, then it means the menu hierarchy is still 
  568.         // visible and a shared submenu as the one that caused this 
  569.         // event.  Those motif shared sumenu shells are very complicated.
  570.  
  571.         if (armed)
  572.         {
  573.             return;
  574.         }
  575.  
  576.         object->disableDropping();
  577.     }
  578.  
  579.     *cont = True;
  580. }
  581. //////////////////////////////////////////////////////////////////////////
  582. XFE_CALLBACK_DEFN(XFE_BookmarkBase, bookmarksChanged)
  583.     (XFE_NotificationCenter *    /* obj */,
  584.      void *                        /* clientData */,
  585.      void *                        /* call_data */)
  586. {
  587.     // Update the bookmarks since they have changed
  588.     prepareToUpdateRoot();
  589. }
  590. //////////////////////////////////////////////////////////////////////////
  591. XFE_CALLBACK_DEFN(XFE_BookmarkBase,updateIconAppearance)
  592.     (XFE_NotificationCenter *    /*obj*/, 
  593.      void *                        /*clientData*/, 
  594.      void *                        /*callData*/)
  595. {
  596.     // Update the appearance
  597.     updateAppearance();
  598. }
  599. //////////////////////////////////////////////////////////////////////////
  600. XFE_CALLBACK_DEFN(XFE_BookmarkBase,updatePersonalToolbarFolderName)
  601.     (XFE_NotificationCenter *    /* obj */, 
  602.      void *                        /* clientData */, 
  603.      void *                        /* callData */)
  604. {
  605.     updateToolbarFolderName();
  606. }
  607. //////////////////////////////////////////////////////////////////////////
  608. XFE_Frame *
  609. XFE_BookmarkBase::getFrame()
  610. {
  611.     return _frame;
  612. }
  613. //////////////////////////////////////////////////////////////////////////
  614. void
  615. XFE_BookmarkBase::getPixmapsForEntry(BM_Entry *    entry,
  616.                                      Pixmap *    pixmapOut,
  617.                                      Pixmap *    maskOut,
  618.                                      Pixmap *    armedPixmapOut,
  619.                                      Pixmap *    armedMaskOut)
  620. {
  621.     Pixmap pixmap        = _bookmarkPixmap;
  622.     Pixmap mask            = _bookmarkMask;
  623.     Pixmap armedPixmap    = XmUNSPECIFIED_PIXMAP;
  624.     Pixmap armedMask    = XmUNSPECIFIED_PIXMAP;
  625.  
  626.     // Right now the only way an entry can be NULL os for the 
  627.     // bookmarkMoreButton which kinda looks and acts like a folder so
  628.     // we use folder pixmaps for it
  629.     if (!entry)
  630.     {
  631.         pixmap        = _folderPixmap;
  632.         mask        = _folderMask;
  633.         armedPixmap    = _folderArmedPixmap;
  634.         armedMask    = _folderArmedMask;
  635.     }
  636.     else
  637.     {
  638.         if (BM_IsHeader(entry))
  639.         {
  640.             XP_Bool is_tool = (entry == XFE_PersonalToolbar::getToolbarFolder());
  641.             XP_Bool is_menu = (entry == getMenuFolder());
  642.             XP_Bool is_add = (entry == getAddFolder());
  643.             
  644.             if (is_add && is_menu && is_tool)
  645.             {
  646.                 pixmap        = _newPersonalMenuFolderPixmap;
  647.                 mask        = _newPersonalMenuFolderMask;
  648.                 armedPixmap    = _newPersonalMenuFolderArmedPixmap;
  649.                 armedMask    = _newPersonalMenuFolderArmedMask;
  650.             }
  651.             else if (is_add && is_tool)
  652.             {
  653.                 pixmap        = _newPersonalFolderPixmap;
  654.                 mask        = _newPersonalFolderMask;
  655.                 armedPixmap    = _newPersonalFolderArmedPixmap;
  656.                 armedMask    = _newPersonalFolderArmedMask;
  657.             }
  658.             else if (is_add && is_menu)
  659.             {
  660.                 pixmap        = _newMenuFolderPixmap;
  661.                 mask        = _newMenuFolderMask;
  662.                 armedPixmap    = _newMenuFolderArmedPixmap;
  663.                 armedMask    = _newMenuFolderArmedMask;
  664.             }
  665.             else if (is_add)
  666.             {
  667.                 pixmap        = _newFolderPixmap;
  668.                 mask        = _newFolderMask;
  669.                 armedPixmap    = _newFolderArmedPixmap;
  670.                 armedMask    = _newFolderArmedMask;
  671.             }
  672.             else if (is_menu)
  673.             {
  674.                 pixmap        = _menuFolderPixmap;
  675.                 mask        = _menuFolderMask;
  676.                 armedPixmap    = _menuFolderArmedPixmap;
  677.                 armedMask    = _menuFolderArmedMask;
  678.             }
  679.             else if (is_tool)
  680.             {
  681.                 pixmap        = _personalFolderPixmap;
  682.                 mask        = _personalFolderMask;
  683.                 armedPixmap    = _personalFolderArmedPixmap;
  684.                 armedMask    = _personalFolderArmedMask;
  685.             }
  686.             else
  687.             {
  688.                 pixmap        = _folderPixmap;
  689.                 mask        = _folderMask;
  690.                 armedPixmap    = _folderArmedPixmap;
  691.                 armedMask    = _folderArmedMask;
  692.             }
  693.         }
  694.         else
  695.         {
  696.             int url_type = NET_URL_Type(BM_GetAddress(entry));
  697.             
  698.             switch (url_type)
  699.             {
  700.             case IMAP_TYPE_URL:
  701.             case MAILBOX_TYPE_URL:
  702.                 
  703.                 pixmap    = _mailBookmarkPixmap;
  704.                 mask    = _mailBookmarkMask;
  705.                 
  706.                 break;
  707.                 
  708.             case NEWS_TYPE_URL:
  709.                 
  710.                 pixmap    = _newsBookmarkPixmap;
  711.                 mask    = _newsBookmarkMask;
  712.                 
  713.                 break;
  714.                 
  715.             default:
  716.  
  717.                 if( BM_GetChangedState(entry) == BM_CHANGED_YES )
  718.                 {
  719.                     pixmap  = _bookmarkChangedPixmap;
  720.                     mask    = _bookmarkChangedMask;
  721.                 }            
  722.                 break;
  723.             }
  724.         }
  725.     }
  726.  
  727.     if (pixmapOut)
  728.     {
  729.         *pixmapOut = pixmap;
  730.     }
  731.  
  732.     if (maskOut)
  733.     {
  734.         *maskOut = mask;
  735.     }
  736.  
  737.     if (armedPixmapOut)
  738.     {
  739.         *armedPixmapOut = armedPixmap;
  740.     }
  741.  
  742.     if (armedMaskOut)
  743.     {
  744.         *armedMaskOut = armedMask;
  745.     }
  746.  
  747. }
  748. //////////////////////////////////////////////////////////////////////////
  749. BM_Entry *
  750. XFE_BookmarkBase::getFirstEntry()
  751. {
  752.     // Access the root header
  753.     BM_Entry * root = BM_GetMenuHeader(_bookmarkContext);
  754.  
  755.     // Ignore the root header (ie, "Joe's Bookmarks")
  756.     if (root && BM_IsHeader(root))
  757.     {
  758.         root = BM_GetChildren(root);
  759.     }
  760.  
  761.     return root;
  762. }
  763. //////////////////////////////////////////////////////////////////////////
  764. BM_Entry *
  765. XFE_BookmarkBase::getTopLevelFolder(const char * name)
  766. {
  767.     BM_Entry * result = NULL;
  768.  
  769.     // Access the root header
  770.     BM_Entry * root = getRootFolder();
  771.  
  772.     // Ignore the root header (ie, "Joe's Bookmarks")
  773.     if (root && BM_IsHeader(root))
  774.     {
  775.         BM_Entry * entry = BM_GetChildren(root);
  776.  
  777.         while (entry && !result)
  778.         {
  779.             if (BM_IsHeader(entry))
  780.             {
  781.                 if (XP_STRCMP(name,BM_GetName(entry)) == 0)
  782.                 {
  783.                     result = entry;
  784.                 }
  785.             }
  786.  
  787.             entry = BM_GetNext(entry);
  788.         }
  789.     }
  790.  
  791.     return result;
  792. }
  793. //////////////////////////////////////////////////////////////////////////
  794. void
  795. XFE_BookmarkBase::trackSubmenuMapping(Widget submenu)
  796. {
  797.     XP_ASSERT( XfeIsAlive(submenu) );
  798.     XP_ASSERT( XmIsRowColumn(submenu) );
  799.  
  800.     Widget shell = XtParent(submenu);
  801.  
  802.     XP_ASSERT( shell );
  803.  
  804.     XtAddEventHandler(shell,
  805.                       StructureNotifyMask,
  806.                       True,
  807.                       &XFE_BookmarkBase::pane_mapping_eh,
  808.                       (XtPointer) this);
  809. }
  810. //////////////////////////////////////////////////////////////////////////
  811. void
  812. XFE_BookmarkBase::createItemTree(Widget menu,BM_Entry * entry)
  813. {
  814.     while (entry)
  815.     {
  816.         Widget item = NULL;
  817.  
  818.         if (BM_IsHeader(entry))
  819.         {
  820.             item = createCascadeButton(menu,entry,False);
  821.         }
  822.         else if (!_onlyHeaders)
  823.         {
  824.             if (BM_IsSeparator(entry))
  825.             {
  826.                 item = createSeparator(menu);
  827.             }
  828.             else
  829.             {
  830.                 item = createPushButton(menu,entry);
  831.             }
  832.         }
  833.  
  834.         if (item)
  835.         {
  836.             XP_ASSERT( XfeIsAlive(item) );
  837.  
  838.             XtManageChild(item);
  839.         }
  840.  
  841.         entry = BM_GetNext(entry);
  842.     }
  843. }
  844. //////////////////////////////////////////////////////////////////////////
  845. /* virtual */ void
  846. XFE_BookmarkBase::prepareToUpdateRoot()
  847. {
  848. }
  849. //////////////////////////////////////////////////////////////////////////
  850. /* virtual */ void
  851. XFE_BookmarkBase::reallyUpdateRoot()
  852. {
  853. }
  854. //////////////////////////////////////////////////////////////////////////
  855. /* virtual */ void
  856. XFE_BookmarkBase::updateAppearance()
  857. {
  858. }
  859. //////////////////////////////////////////////////////////////////////////
  860. /* virtual */ void
  861. XFE_BookmarkBase::updateToolbarFolderName()
  862. {
  863. }
  864. //////////////////////////////////////////////////////////////////////////
  865. /* virtual */ void
  866. XFE_BookmarkBase::entryArmed(Widget /* button */,BM_Entry * entry)
  867. {
  868.     char * address;
  869.  
  870.     if (!entry || !(BM_IsAlias(entry) || BM_IsUrl(entry)))
  871.     {
  872.         return;
  873.     }
  874.     
  875.     address = BM_GetAddress(entry);
  876.     
  877.     _frame->notifyInterested(XFE_View::statusNeedsUpdatingMidTruncated,
  878.                              (void*) address);
  879. }
  880. //////////////////////////////////////////////////////////////////////////
  881. /* virtual */ void
  882. XFE_BookmarkBase::entryEnter(Widget button,BM_Entry * entry)
  883. {
  884.     // Same thing as armed
  885.     entryArmed(button,entry);
  886. }
  887. //////////////////////////////////////////////////////////////////////////
  888. /* virtual */ void
  889. XFE_BookmarkBase::entryLeave(Widget button,BM_Entry * entry)
  890. {
  891.     // Same thing as disarmed
  892.     entryDisarmed(button,entry);
  893. }
  894. //////////////////////////////////////////////////////////////////////////
  895. /* virtual */ void
  896. XFE_BookmarkBase::entryDisarmed(Widget /* button */,BM_Entry * entry)
  897. {
  898.     if (!entry || !(BM_IsAlias(entry) || BM_IsUrl(entry)))
  899.     {
  900.         return;
  901.     }
  902.     
  903.     _frame->notifyInterested(XFE_View::statusNeedsUpdatingMidTruncated,
  904.                              (void*) "");
  905. }
  906. //////////////////////////////////////////////////////////////////////////
  907. /* virtual */ void
  908. XFE_BookmarkBase::entryActivated(Widget /*item*/,BM_Entry * entry)
  909. {
  910.     LO_AnchorData anchor_data;
  911.     
  912.     if (!entry || !(BM_IsAlias(entry) || BM_IsUrl(entry)))
  913.     {
  914.         return;
  915.     }
  916.  
  917.     anchor_data.anchor = (PA_Block)BM_GetAddress(entry);
  918.     anchor_data.target = (PA_Block)BM_GetTarget(entry, TRUE);
  919.  
  920.     // Have the frame do the command if it supports it
  921.     if (_frame->handlesCommand(xfeCmdOpenTargetUrl,(void *) &anchor_data))
  922.     {
  923.         _frame->doCommand(xfeCmdOpenTargetUrl,(void*) &anchor_data);
  924.     }
  925. }
  926. //////////////////////////////////////////////////////////////////////////
  927. /* virtual */ void
  928. XFE_BookmarkBase::entryCascading(Widget /* cascade */,BM_Entry * /* entry */)
  929. {
  930. }
  931. //////////////////////////////////////////////////////////////////////////
  932. /* virtual */ void
  933. XFE_BookmarkBase::enableDropping()
  934. {
  935.     // Enable the drawing of accents on the menu hierarchy
  936.     XfeBmAccentSetFileMode(XmACCENT_FILE_ANYWHERE);
  937.     XfeBmAccentEnable();
  938. }
  939. //////////////////////////////////////////////////////////////////////////
  940. /* virtual */ void
  941. XFE_BookmarkBase::disableDropping()
  942. {
  943.     // Disable the drawing of accents on the menu hierarchy
  944.     XfeBmAccentDisable();
  945. }
  946. //////////////////////////////////////////////////////////////////////////
  947. /* virtual */ XP_Bool
  948. XFE_BookmarkBase::isDroppingEnabled()
  949. {
  950.     return XfeBmAccentIsEnabled();
  951. }
  952. //////////////////////////////////////////////////////////////////////////
  953.  
  954. //////////////////////////////////////////////////////////////////////////
  955. //
  956. // Menu component creation functions
  957. //
  958. //////////////////////////////////////////////////////////////////////////
  959. Widget 
  960. XFE_BookmarkBase::createCascadeButton(Widget        menu,
  961.                                       BM_Entry *    entry,
  962.                                       XP_Bool        ignore_children)
  963. {
  964.     XP_ASSERT( XfeIsAlive(menu) );
  965.     XP_ASSERT( XmIsRowColumn(menu) );
  966.  
  967.     Widget                        non_full_menu;
  968.     Widget                        cascade;
  969.     Widget                        submenu = NULL;
  970.     Arg                            av[20];
  971.     Cardinal                    ac;
  972.     XmString                    xmname;
  973.     BookmarkCallbackStruct *    data = NULL;
  974.     XP_Bool                        has_header_children;
  975.  
  976.     xmname = XFE_BookmarkBase::entryToXmString(_bookmarkContext,
  977.                                                entry,
  978.                                                _charSetInfo);
  979.  
  980.     non_full_menu = getLastMoreMenu(menu);
  981.  
  982.     XP_ASSERT( XfeIsAlive(non_full_menu) );
  983.  
  984.     // Determne if we have at least one header child
  985.     has_header_children = XFE_BookmarkBase::BM_EntryHasHeaderChildren(entry);
  986.  
  987.     // Create sub menu only if needed (children exits and not only eaders)
  988.     if (BM_GetChildren(entry) && 
  989.         !(_onlyHeaders && !has_header_children) &&
  990.         !ignore_children)
  991.     {
  992.         Visual *    visual = XfeVisual(non_full_menu);
  993.         Colormap    cmap = XfeColormap(non_full_menu);
  994.         Cardinal    depth = XfeDepth(non_full_menu);
  995.         
  996.         ac = 0;
  997.         XtSetArg(av[ac],XmNvisual,        visual);    ac++;
  998.         XtSetArg(av[ac],XmNdepth,        depth);        ac++;
  999.         XtSetArg(av[ac],XmNcolormap,    cmap);        ac++;
  1000.  
  1001.           submenu = XmCreatePulldownMenu(non_full_menu,"bookmarkPulldown",av,ac);
  1002.     }
  1003.  
  1004.     ac = 0;
  1005.     XtSetArg(av[ac],XmNlabelString,    xmname);    ac++;
  1006.  
  1007.     if (XfeIsAlive(submenu))
  1008.     {
  1009.         XtSetArg(av[ac],XmNsubMenuId,    submenu);    ac++;
  1010.     }
  1011.  
  1012.     if (_fancyItems)
  1013.     {
  1014.          cascade = XfeCreateBmCascade(non_full_menu,"bookmarkCascadeButton",av,ac);
  1015.  
  1016.         configureXfeBmCascade(cascade,entry);
  1017.     }
  1018.     else
  1019.     {
  1020.         cascade = XmCreateCascadeButton(non_full_menu,"bookmarkCascadeButton",av,ac);
  1021.  
  1022.         configureCascade(cascade,entry);
  1023.     }
  1024.  
  1025.     // Create a new bookmark data structure for the callbacks
  1026.     data = XP_NEW_ZAP(BookmarkCallbackStruct);
  1027.  
  1028.     data->object    = this;
  1029.     data->entry        = entry;
  1030.  
  1031.     XtAddCallback(cascade,
  1032.                   XmNcascadingCallback,
  1033.                   &XFE_BookmarkBase::item_cascading_cb,
  1034.                   (XtPointer) data);
  1035.  
  1036.     XtAddCallback(cascade,
  1037.                   XmNactivateCallback,
  1038.                   &XFE_BookmarkBase::item_activated_cb,
  1039.                   (XtPointer) data);
  1040.  
  1041.     XtAddCallback(cascade,
  1042.                   XmNdestroyCallback,
  1043.                   &XFE_BookmarkBase::item_free_data_cb,
  1044.                   (XtPointer) data);
  1045.  
  1046.     if (xmname)
  1047.     {
  1048.         XmStringFree(xmname);
  1049.     }
  1050.  
  1051.     return cascade;
  1052. }
  1053. //////////////////////////////////////////////////////////////////////////
  1054. Widget 
  1055. XFE_BookmarkBase::createMoreButton(Widget menu)
  1056. {
  1057.     XP_ASSERT( XfeIsAlive(menu) );
  1058.     XP_ASSERT( XmIsRowColumn(menu) );
  1059.  
  1060.     Widget        cascade;
  1061.     Widget        submenu = NULL;
  1062.     Arg            av[20];
  1063.     Cardinal    ac = 0;
  1064.  
  1065.     ac = 0;
  1066.     XtSetArg(av[ac],XmNvisual,        XfeVisual(menu));    ac++;
  1067.     XtSetArg(av[ac],XmNdepth,        XfeDepth(menu));    ac++;
  1068.     XtSetArg(av[ac],XmNcolormap,    XfeColormap(menu));    ac++;
  1069.     
  1070.     submenu = XmCreatePulldownMenu(menu,MORE_PULLDOWN_NAME,av,ac);
  1071.  
  1072.     ac = 0;
  1073.     XtSetArg(av[ac],XmNsubMenuId,    submenu);    ac++;
  1074.  
  1075.     if (_fancyItems)
  1076.     {
  1077.          cascade = XfeCreateBmCascade(menu,MORE_BUTTON_NAME,av,ac);
  1078.  
  1079.         configureXfeBmCascade(cascade,NULL);
  1080.     }
  1081.     else
  1082.     {
  1083.         cascade = XmCreateCascadeButton(menu,MORE_BUTTON_NAME,av,ac);
  1084.  
  1085.         configureCascade(cascade,NULL);
  1086.     }
  1087.  
  1088.     return cascade;
  1089. }
  1090. //////////////////////////////////////////////////////////////////////////
  1091. Widget 
  1092. XFE_BookmarkBase::createPushButton(Widget menu,BM_Entry * entry)
  1093. {
  1094.     XP_ASSERT( XfeIsAlive(menu) );
  1095.     XP_ASSERT( XmIsRowColumn(menu) );
  1096.  
  1097.     Widget                        non_full_menu;
  1098.     Widget                        button;
  1099.     Arg                            av[20];
  1100.     Cardinal                    ac;
  1101.     XmString                    xmname;
  1102.     BookmarkCallbackStruct *    data = NULL;
  1103.  
  1104.     xmname = XFE_BookmarkBase::entryToXmString(_bookmarkContext,
  1105.                                                entry,
  1106.                                                _charSetInfo);
  1107.  
  1108.     ac = 0;
  1109.     XtSetArg(av[ac], XmNlabelString,    xmname);    ac++;
  1110.  
  1111.     non_full_menu = getLastMoreMenu(menu);
  1112.  
  1113.     XP_ASSERT( XfeIsAlive(non_full_menu) );
  1114.  
  1115.     // must be xfeCmdOpenTargetUrl or sensitivity becomes a problem
  1116.     if (_fancyItems)
  1117.     {
  1118.         button = XfeCreateBmButton(non_full_menu,xfeCmdOpenTargetUrl,av,ac);
  1119.  
  1120.         configureXfeBmButton(button,entry);
  1121.     }
  1122.     else
  1123.     {
  1124.         button = XmCreatePushButton(non_full_menu,xfeCmdOpenTargetUrl,av,ac);
  1125.  
  1126.         configureButton(button,entry);
  1127.     }
  1128.  
  1129.     // Create a new bookmark data structure for the callbacks
  1130.     data = XP_NEW_ZAP(BookmarkCallbackStruct);
  1131.  
  1132.     data->object    = this;
  1133.     data->entry        = entry;
  1134.     
  1135.     XtAddCallback(button,
  1136.                   XmNactivateCallback,
  1137.                   &XFE_BookmarkBase::item_activated_cb,
  1138.                   (XtPointer) data);
  1139.  
  1140.     XtAddCallback(button,
  1141.                   XmNarmCallback,
  1142.                   &XFE_BookmarkBase::item_armed_cb,
  1143.                   (XtPointer) data);
  1144.  
  1145.     XtAddCallback(button,
  1146.                   XmNdisarmCallback,
  1147.                   &XFE_BookmarkBase::item_disarmed_cb,
  1148.                   (XtPointer) data);
  1149.  
  1150.     XtAddCallback(button,
  1151.                   XmNdestroyCallback,
  1152.                   &XFE_BookmarkBase::item_free_data_cb,
  1153.                   (XtPointer) data);
  1154.  
  1155.     if (xmname)
  1156.     {
  1157.         XmStringFree(xmname);
  1158.     }
  1159.  
  1160.     return button;
  1161. }
  1162. //////////////////////////////////////////////////////////////////////////
  1163. Widget 
  1164. XFE_BookmarkBase::getLastMoreMenu(Widget menu)
  1165. {
  1166.     XP_ASSERT( XfeIsAlive(menu) );
  1167.     XP_ASSERT( XmIsRowColumn(menu) );
  1168.  
  1169.     // Find the last more... menu
  1170.     Widget last_more_menu = XfeMenuFindLastMoreMenu(menu,MORE_BUTTON_NAME);
  1171.  
  1172.     XP_ASSERT( XfeIsAlive(last_more_menu) );
  1173.  
  1174.     // Check if the last menu is full
  1175.     if (XfeMenuIsFull(last_more_menu))
  1176.     {
  1177.         // Look for the More... button for the last menu
  1178.         Widget more_button = XfeMenuGetMoreButton(last_more_menu,
  1179.                                                   MORE_BUTTON_NAME);
  1180.  
  1181.         // If no more button, create one plus a submenu
  1182.         if (!more_button)
  1183.         {
  1184.             more_button = createMoreButton(last_more_menu);
  1185.  
  1186.             XtManageChild(more_button);
  1187.  
  1188.         }
  1189.  
  1190.         // Set the last more menu to the submenu of the new more button
  1191.         last_more_menu = XfeCascadeGetSubMenu(more_button);
  1192.     }
  1193.  
  1194.     return last_more_menu;
  1195. }
  1196. //////////////////////////////////////////////////////////////////////////
  1197. Widget 
  1198. XFE_BookmarkBase::createSeparator(Widget menu)
  1199. {
  1200.     XP_ASSERT( XfeIsAlive(menu) );
  1201.  
  1202.     Widget        parent;        
  1203.     Widget        separator;
  1204.     String        name;
  1205.  
  1206.     if (XmIsRowColumn(menu))
  1207.     {
  1208.         parent = getLastMoreMenu(menu);
  1209.  
  1210.         name = MENU_PANE_SEPARATOR_NAME;
  1211.     }
  1212.     else
  1213.     {
  1214.         parent = menu;
  1215.  
  1216.         name = TOOL_BAR_SEPARATOR_NAME;
  1217.     }
  1218.  
  1219.     XP_ASSERT( XfeIsAlive(parent) );
  1220.  
  1221.     separator = XmCreateSeparator(parent,name,NULL,0);
  1222.  
  1223.     configureSeparator(separator,NULL);
  1224.  
  1225.     XtManageChild(separator);
  1226.     
  1227.     return separator;
  1228. }
  1229. //////////////////////////////////////////////////////////////////////////
  1230. Widget 
  1231. XFE_BookmarkBase::createXfeCascade(Widget parent,BM_Entry * entry)
  1232. {
  1233.     XP_ASSERT( XfeIsAlive(parent) );
  1234.  
  1235.     Widget                        cascade;
  1236.     Widget                        submenu;
  1237.     Arg                            av[20];
  1238.     Cardinal                    ac;
  1239.     XmString                    xmname;
  1240.     BookmarkCallbackStruct *    data = NULL;
  1241.  
  1242.     xmname = XFE_BookmarkBase::entryToXmString(_bookmarkContext,
  1243.                                                entry,
  1244.                                                _charSetInfo);
  1245.  
  1246.     // No submenu needed if the entry has no children
  1247. //     if (!BM_GetChildren(entry))
  1248. //     {
  1249. //         // fix me
  1250. //     }
  1251.  
  1252.     ac = 0;
  1253.     XtSetArg(av[ac],XmNlabelString,        xmname);                ac++;
  1254.     XtSetArg(av[ac],XmNuserData,        entry);                    ac++;
  1255.  
  1256.     cascade = XfeCreateCascade(parent,"bookmarkCascade",av,ac);
  1257.  
  1258.     configureXfeCascade(cascade,entry);
  1259.  
  1260.     // Create a new bookmark data structure for the callbacks
  1261.     data = XP_NEW_ZAP(BookmarkCallbackStruct);
  1262.  
  1263.     data->object    = this;
  1264.     data->entry        = entry;
  1265.  
  1266.     XtAddCallback(cascade,
  1267.                   XmNcascadingCallback,
  1268.                   &XFE_BookmarkBase::item_cascading_cb,
  1269.                   (XtPointer) data);
  1270.  
  1271.     XtAddCallback(cascade,
  1272.                   XmNdestroyCallback,
  1273.                   &XFE_BookmarkBase::item_free_data_cb,
  1274.                   (XtPointer) data);
  1275.  
  1276.     if (xmname)
  1277.     {
  1278.         XmStringFree(xmname);
  1279.     }
  1280.  
  1281.     // Obtain the cascade's submenu
  1282.     XtVaGetValues(cascade,XmNsubMenuId,&submenu,NULL);
  1283.  
  1284.     // Keep track of the submenu mapping
  1285.     trackSubmenuMapping(submenu);
  1286.  
  1287.     return cascade;
  1288. }
  1289. //////////////////////////////////////////////////////////////////////////
  1290. Widget 
  1291. XFE_BookmarkBase::createXfeButton(Widget parent,BM_Entry * entry)
  1292. {
  1293.     XP_ASSERT( XfeIsAlive(parent) );
  1294.  
  1295.     Widget                        button;
  1296.     Arg                            av[20];
  1297.     Cardinal                    ac;
  1298.     XmString                    xmname;
  1299.     BookmarkCallbackStruct *    data = NULL;
  1300.  
  1301.     xmname = XFE_BookmarkBase::entryToXmString(_bookmarkContext,
  1302.                                                entry,
  1303.                                                _charSetInfo);
  1304.  
  1305.     ac = 0;
  1306.     XtSetArg(av[ac],XmNlabelString,        xmname);                    ac++;
  1307.     XtSetArg(av[ac],XmNuserData,        entry);                        ac++;
  1308.  
  1309.     button = XfeCreateButton(parent,"bookmarkButton",av,ac);
  1310.  
  1311.     configureXfeButton(button,entry);
  1312.  
  1313.     // Create a new bookmark data structure for the callbacks
  1314.     data = XP_NEW_ZAP(BookmarkCallbackStruct);
  1315.  
  1316.     data->object    = this;
  1317.     data->entry        = entry;
  1318.  
  1319.     XtAddCallback(button,
  1320.                   XmNactivateCallback,
  1321.                   &XFE_BookmarkBase::item_activated_cb,
  1322.                   (XtPointer) data);
  1323.  
  1324.     XtAddCallback(button,
  1325.                   XmNarmCallback,
  1326.                   &XFE_BookmarkBase::item_armed_cb,
  1327.                   (XtPointer) data);
  1328.  
  1329.     XtAddCallback(button,
  1330.                   XmNdisarmCallback,
  1331.                   &XFE_BookmarkBase::item_disarmed_cb,
  1332.                   (XtPointer) data);
  1333.  
  1334.     XtAddCallback(button,
  1335.                   XmNenterCallback,
  1336.                   &XFE_BookmarkBase::item_enter_cb,
  1337.                   (XtPointer) data);
  1338.  
  1339.     XtAddCallback(button,
  1340.                   XmNleaveCallback,
  1341.                   &XFE_BookmarkBase::item_leave_cb,
  1342.                   (XtPointer) data);
  1343.  
  1344.     XtAddCallback(button,
  1345.                   XmNdestroyCallback,
  1346.                   &XFE_BookmarkBase::item_free_data_cb,
  1347.                   (XtPointer) data);
  1348.  
  1349.     if (xmname)
  1350.     {
  1351.         XmStringFree(xmname);
  1352.     }
  1353.  
  1354.     return button;
  1355. }
  1356. //////////////////////////////////////////////////////////////////////////
  1357. /* virtual */ void
  1358. XFE_BookmarkBase::configureXfeCascade(Widget /*item*/,BM_Entry * /*entry*/)
  1359. {
  1360. }
  1361. //////////////////////////////////////////////////////////////////////////
  1362. /* virtual */ void
  1363. XFE_BookmarkBase::configureXfeButton(Widget /*item*/,BM_Entry * /*entry*/)
  1364. {
  1365. }
  1366. //////////////////////////////////////////////////////////////////////////
  1367. /* virtual */ void
  1368. XFE_BookmarkBase::configureXfeBmButton(Widget item,BM_Entry * entry)
  1369. {
  1370.     if (fe_globalPrefs.toolbar_style == BROWSER_TOOLBAR_TEXT_ONLY)
  1371.     {
  1372.         XtVaSetValues(item,
  1373.                       XmNlabelPixmap,        XmUNSPECIFIED_PIXMAP,
  1374.                       XmNlabelPixmapMask,    XmUNSPECIFIED_PIXMAP,
  1375.                       NULL);
  1376.  
  1377.         return;
  1378.     }
  1379.  
  1380.     Pixmap pixmap;
  1381.     Pixmap mask;
  1382.  
  1383.     getPixmapsForEntry(entry,&pixmap,&mask,NULL,NULL);
  1384.  
  1385.     XtVaSetValues(item,
  1386.                   XmNlabelPixmap,        pixmap,
  1387.                   XmNlabelPixmapMask,    mask,
  1388.                   NULL);
  1389. }
  1390. //////////////////////////////////////////////////////////////////////////
  1391. /* virtual */ void
  1392. XFE_BookmarkBase::configureXfeBmCascade(Widget item,BM_Entry * entry)
  1393. {
  1394.     if (fe_globalPrefs.toolbar_style == BROWSER_TOOLBAR_TEXT_ONLY)
  1395.     {
  1396.         XtVaSetValues(item,
  1397.                       XmNlabelPixmap,        XmUNSPECIFIED_PIXMAP,
  1398.                       XmNlabelPixmapMask,    XmUNSPECIFIED_PIXMAP,
  1399.                       XmNarmPixmap,            XmUNSPECIFIED_PIXMAP,
  1400.                       XmNarmPixmapMask,        XmUNSPECIFIED_PIXMAP,
  1401.                       NULL);
  1402.  
  1403.         return;
  1404.     }
  1405.  
  1406.     Pixmap pixmap;
  1407.     Pixmap mask;
  1408.     Pixmap armedPixmap;
  1409.     Pixmap armedMask;
  1410.  
  1411.     getPixmapsForEntry(entry,&pixmap,&mask,&armedPixmap,&armedMask);
  1412.  
  1413.     Arg            av[4];
  1414.     Cardinal    ac = 0;
  1415.  
  1416.     XtSetArg(av[ac],XmNlabelPixmap,        pixmap); ac++;
  1417.     XtSetArg(av[ac],XmNlabelPixmapMask,    mask); ac++;
  1418.  
  1419.     // Only show the aremd pixmap/mask if this entry has children
  1420.     if (XfeIsAlive(XfeCascadeGetSubMenu(item)))
  1421.     {
  1422.         XtSetArg(av[ac],XmNarmPixmap,        armedPixmap); ac++;
  1423.         XtSetArg(av[ac],XmNarmPixmapMask,    armedMask); ac++;
  1424.     }
  1425.  
  1426.     XtSetValues(item,av,ac);
  1427. }
  1428. //////////////////////////////////////////////////////////////////////////
  1429. /* virtual */ void
  1430. XFE_BookmarkBase::configureButton(Widget /*item*/,BM_Entry * /*entry*/)
  1431. {
  1432. }
  1433. //////////////////////////////////////////////////////////////////////////
  1434. /* virtual */ void
  1435. XFE_BookmarkBase::configureCascade(Widget /*item*/,BM_Entry * /*entry*/)
  1436. {
  1437. }
  1438. //////////////////////////////////////////////////////////////////////////
  1439. /* virtual */ void
  1440. XFE_BookmarkBase::configureSeparator(Widget /*item*/,BM_Entry * /*entry*/)
  1441. {
  1442. }
  1443. //////////////////////////////////////////////////////////////////////////
  1444. MWContext *
  1445. XFE_BookmarkBase::getBookmarkContext()
  1446. {
  1447.     return _bookmarkContext;
  1448. }
  1449. //////////////////////////////////////////////////////////////////////////
  1450. BM_Entry *
  1451. XFE_BookmarkBase::getRootFolder()
  1452. {
  1453.     return BM_GetRoot(getBookmarkContext());
  1454. //    return BM_GetAddHeader(getBookmarkContext());
  1455. }
  1456. //////////////////////////////////////////////////////////////////////////
  1457. BM_Entry *
  1458. XFE_BookmarkBase::getAddFolder()
  1459. {
  1460.     return BM_GetAddHeader(getBookmarkContext());
  1461. }
  1462. //////////////////////////////////////////////////////////////////////////
  1463. BM_Entry *
  1464. XFE_BookmarkBase::getMenuFolder()
  1465. {
  1466.     return BM_GetMenuHeader(getBookmarkContext());
  1467. }
  1468. //////////////////////////////////////////////////////////////////////////
  1469. /* static */ BM_Entry *
  1470. XFE_BookmarkBase::BM_FindFolderByName(BM_Entry * root,char * folder_name)
  1471. {
  1472.     if (!root || !folder_name)
  1473.     {
  1474.         return NULL;
  1475.     }
  1476.  
  1477.     BM_Entry * header;
  1478.  
  1479.     char * header_name = BM_GetName(root);
  1480.  
  1481.     if(XP_STRCMP(header_name,folder_name) == 0)
  1482.     {
  1483.         return root;
  1484.     }
  1485.  
  1486.     for (BM_Entry * bm = BM_GetChildren(root); 
  1487.          bm != NULL; 
  1488.          bm = BM_GetNext(bm))
  1489.     {
  1490.         if (BM_IsHeader(bm))
  1491.         {
  1492.             header = BM_FindFolderByName(bm,folder_name);
  1493.  
  1494.             if(header != NULL)
  1495.             {
  1496.                 return header;
  1497.             }
  1498.         }
  1499.     }
  1500.  
  1501.     return NULL;
  1502. }
  1503. //////////////////////////////////////////////////////////////////////////
  1504. /* static */ BM_Entry *
  1505. XFE_BookmarkBase::BM_FindEntryByAddress(BM_Entry *        root,
  1506.                                         const char *    target_address)
  1507. {
  1508.     if (!root || !target_address)
  1509.     {
  1510.         return NULL;
  1511.     }
  1512.  
  1513.     char * entry_address = BM_GetAddress(root);
  1514.  
  1515.     if (entry_address && (XP_STRCMP(target_address,entry_address) == 0))
  1516.     {
  1517.         return root;
  1518.     }
  1519.  
  1520.     if (BM_IsHeader(root))
  1521.     {
  1522.         BM_Entry * entry;
  1523.  
  1524.         for (entry = BM_GetChildren(root); entry; entry = BM_GetNext(entry))
  1525.         {
  1526.             BM_Entry * test_entry;
  1527.  
  1528.             test_entry = 
  1529.                 XFE_BookmarkBase::BM_FindEntryByAddress(entry,target_address);
  1530.             
  1531.             if (test_entry)
  1532.             {
  1533.                 return test_entry;
  1534.             }
  1535.         }
  1536.     }
  1537.  
  1538.     return NULL;
  1539. }
  1540. //////////////////////////////////////////////////////////////////////////
  1541. /* static */ BM_Entry *
  1542. XFE_BookmarkBase::BM_FindNextEntry(BM_Entry * current)
  1543. {
  1544.     if (current)
  1545.     {
  1546.         return BM_GetNext(current);
  1547.      }
  1548.     
  1549.      return NULL;
  1550. }
  1551. //////////////////////////////////////////////////////////////////////////
  1552. /* static */ BM_Entry *
  1553. XFE_BookmarkBase::BM_FindPreviousEntry(BM_Entry * current)
  1554. {
  1555.  
  1556.     if (current)
  1557.     {
  1558.         BM_Entry * parent = BM_GetParent(current);
  1559.  
  1560.         if (parent && BM_IsHeader(parent))
  1561.         {
  1562.             BM_Entry * entry;
  1563.             BM_Entry * prev = NULL;
  1564.  
  1565.             for (entry = BM_GetChildren(parent); 
  1566.                  entry;
  1567.                  entry = BM_GetNext(entry))
  1568.             {
  1569.                 if (entry == current)
  1570.                 {
  1571.                     return prev;
  1572.                 }
  1573.  
  1574.                 prev = entry;
  1575.             }
  1576.         }
  1577.     }
  1578.  
  1579.     return NULL;
  1580. }
  1581. //////////////////////////////////////////////////////////////////////////
  1582. /* static */ XP_Bool
  1583. XFE_BookmarkBase::BM_EntryHasHeaderChildren(BM_Entry * header)
  1584. {
  1585.     XP_ASSERT( header != NULL );
  1586.     XP_ASSERT( BM_IsHeader(header) );
  1587.  
  1588.     BM_Entry * entry = BM_GetChildren(header);
  1589.  
  1590.     // Traverse until we find a header entry
  1591.     while (entry)
  1592.     {
  1593.         if (BM_IsHeader(entry))
  1594.         {
  1595.             return True;
  1596.         }
  1597.  
  1598.         entry = BM_GetNext(entry);
  1599.     }
  1600.  
  1601.     return False;
  1602. }
  1603. //////////////////////////////////////////////////////////////////////////
  1604. void
  1605. XFE_BookmarkBase::addEntryAfter(const char *    address,
  1606.                                 const char *    title,
  1607.                                 BM_Date            lastAccess,
  1608.                                 BM_Entry *        entryAfter)
  1609. {
  1610.     XP_ASSERT( entryAfter != NULL );
  1611.  
  1612.     // Create the new entry
  1613.     BM_Entry * entry = BM_NewUrl(title,address,NULL,lastAccess);
  1614.  
  1615.     // Add it after the given entry
  1616.     BM_InsertItemAfter(getBookmarkContext(),entryAfter,entry);
  1617. }
  1618. //////////////////////////////////////////////////////////////////////////
  1619. void
  1620. XFE_BookmarkBase::addEntryBefore(const char *    address,
  1621.                                  const char *    title,
  1622.                                  BM_Date        lastAccess,
  1623.                                  BM_Entry *        entryBefore)
  1624. {
  1625.     XP_ASSERT( entryBefore != NULL );
  1626.  
  1627.     // In order to add a bookmark before and entry, we try to add it after
  1628.     // the previous entry if it exists or prepend it to the parent header
  1629.     // if it does not.  The latter case will occur ehtn entryBefore is the
  1630.     // first entry in a list.
  1631.     BM_Entry * prev = XFE_BookmarkBase::BM_FindPreviousEntry(entryBefore);
  1632.  
  1633.     // Create the new entry
  1634.     BM_Entry * entry = BM_NewUrl(title,address,NULL,lastAccess);
  1635.  
  1636.     if (prev)
  1637.     {
  1638.         // Add it after the previous entry
  1639.         BM_InsertItemAfter(getBookmarkContext(),prev,entry);
  1640.     }
  1641.     else
  1642.     {
  1643.         // Try to access the parent
  1644.         BM_Entry * parent = BM_GetParent(entryBefore);
  1645.  
  1646.         // Use the root entry if no parent is found
  1647.         if (!parent)
  1648.         {
  1649.             parent = getRootFolder();
  1650.         }
  1651.  
  1652.         // Add the entry to the head of the list
  1653.         BM_PrependChildToHeader(getBookmarkContext(),parent,entry);
  1654.     }
  1655. }
  1656. //////////////////////////////////////////////////////////////////////////
  1657. void
  1658. XFE_BookmarkBase::addEntryToFolder(const char *        address,
  1659.                                    const char *        title,
  1660.                                    BM_Date            lastAccess,
  1661.                                    BM_Entry *        header)
  1662. {
  1663.     XP_ASSERT( header != NULL );
  1664.     XP_ASSERT( BM_IsHeader(header) );
  1665.  
  1666.     BM_Entry * entry = BM_NewUrl(title,address,NULL,lastAccess);
  1667.  
  1668.     BM_AppendToHeader(getBookmarkContext(),header,entry);
  1669. }
  1670. //////////////////////////////////////////////////////////////////////////
  1671. void
  1672. XFE_BookmarkBase::setDropAddress(const char * address)
  1673. {
  1674.     if (_dropAddressBuffer)
  1675.     {
  1676.         XtFree(_dropAddressBuffer);
  1677.     }
  1678.  
  1679.     _dropAddressBuffer = NULL;
  1680.  
  1681.     if (address)
  1682.     {
  1683.         _dropAddressBuffer = (char *) XtNewString(address);
  1684.     }
  1685. }
  1686. //////////////////////////////////////////////////////////////////////////
  1687. void
  1688. XFE_BookmarkBase::setDropTitle(const char * title)
  1689. {
  1690.     if (_dropTitleBuffer)
  1691.     {
  1692.         XtFree(_dropTitleBuffer);
  1693.     }
  1694.  
  1695.     _dropTitleBuffer = NULL;
  1696.  
  1697.     if (title)
  1698.     {
  1699.         _dropTitleBuffer = (char *) XtNewString(title);
  1700.     }
  1701. }
  1702. //////////////////////////////////////////////////////////////////////////
  1703. void
  1704. XFE_BookmarkBase::setDropLastAccess(BM_Date lastAccess)
  1705. {
  1706.     _dropLastAccess = lastAccess;
  1707. }
  1708. //////////////////////////////////////////////////////////////////////////
  1709. const char *
  1710. XFE_BookmarkBase::getDropAddress()
  1711. {
  1712.     return _dropAddressBuffer;
  1713. }
  1714. //////////////////////////////////////////////////////////////////////////
  1715. const char *
  1716. XFE_BookmarkBase::getDropTitle()
  1717. {
  1718.     return _dropTitleBuffer;
  1719. }
  1720. //////////////////////////////////////////////////////////////////////////
  1721. BM_Date
  1722. XFE_BookmarkBase::getDropLastAccess()
  1723. {
  1724.     return _dropLastAccess;
  1725. }
  1726. //////////////////////////////////////////////////////////////////////////
  1727. /* static */ void
  1728. XFE_BookmarkBase::guessTitle(XFE_Frame *    frame,
  1729.                              MWContext *    bookmarkContext,
  1730.                              const char *    address,
  1731.                              XP_Bool        sameShell,
  1732.                              char **        guessedTitleOut,
  1733.                              BM_Date *        guessedLastDateOut)
  1734. {
  1735.     XP_ASSERT( frame != NULL );
  1736.     XP_ASSERT( bookmarkContext != NULL );
  1737.     XP_ASSERT( address != NULL );
  1738.     XP_ASSERT( guessedTitleOut != NULL );
  1739.     XP_ASSERT( guessedLastDateOut != NULL );
  1740.     
  1741.     // Initialize the results to begin with
  1742.     *guessedLastDateOut    = 0;
  1743.     *guessedTitleOut        = NULL;
  1744.  
  1745.     // Obtain the frame's context
  1746.     MWContext *    frame_context = frame->getContext();
  1747.  
  1748.     // If the operation occurs in the same shell, look in the history.
  1749.     if (sameShell)
  1750.     {
  1751.         // Obtain the current history entry
  1752.         History_entry * hist_entry = SHIST_GetCurrent(&frame_context->hist);
  1753.  
  1754.         // Make sure the history entry matches the given address, or else
  1755.         // the caller used a the same shell with a link that is not the 
  1756.         // the proxy icon (ie, in the html area).
  1757.         if (hist_entry && (XP_STRCMP(hist_entry->address,address) == 0))
  1758.         {
  1759.             *guessedTitleOut = hist_entry->title;
  1760.             *guessedLastDateOut = hist_entry->last_access;
  1761.         }
  1762.     }
  1763.  
  1764.     // Look in the bookmarks for a dup
  1765.     if (!*guessedTitleOut)
  1766.     {
  1767.         BM_Entry * test_entry = NULL;
  1768.         BM_Entry * root_entry = BM_GetRoot(bookmarkContext);
  1769.  
  1770.         if (root_entry)
  1771.         {
  1772.             test_entry = XFE_BookmarkBase::BM_FindEntryByAddress(root_entry,
  1773.                                                                  address);
  1774.         }
  1775.  
  1776.         if (test_entry)
  1777.         {
  1778.             *guessedTitleOut = BM_GetName(test_entry);
  1779.         }
  1780.     }
  1781.  
  1782.     // As a last resort use the address itself as a title
  1783.     if (!*guessedTitleOut)
  1784.     {
  1785.         *guessedTitleOut = (char *) address;
  1786.     }
  1787.  
  1788.     // Strip the leading http:// from the title
  1789.     if (XP_STRLEN(*guessedTitleOut) > 7)
  1790.     {
  1791.         if ((XP_STRNCMP(*guessedTitleOut,"http://",7) == 0) ||
  1792.             (XP_STRNCMP(*guessedTitleOut,"file://",7) == 0))
  1793.         {
  1794.             (*guessedTitleOut) += 7;
  1795.         }
  1796.     }
  1797. }
  1798. //////////////////////////////////////////////////////////////////////////
  1799.  
  1800. /* static */ XmString
  1801. XFE_BookmarkBase::entryToXmString(MWContext *        bookmarkContext,
  1802.                                   BM_Entry *        entry,
  1803.                                   INTL_CharSetInfo    char_set_info)
  1804. {
  1805.     XP_ASSERT( entry != NULL );
  1806.     XP_ASSERT( bookmarkContext != NULL );
  1807.  
  1808.     XmString            result = NULL;
  1809.     XmString            tmp;
  1810.     char *                psz;
  1811.  
  1812.     tmp = XFE_BookmarkBase::formatItem(bookmarkContext,
  1813.                                        entry,
  1814.                                        True,
  1815.                                        INTL_DefaultWinCharSetID(NULL));
  1816.     
  1817.     // Mid truncate the name
  1818.     if (XmStringGetLtoR(tmp,XmSTRING_DEFAULT_CHARSET,&psz))
  1819.     {
  1820.  
  1821.         XmStringFree(tmp);
  1822.  
  1823.         INTL_MidTruncateString(INTL_GetCSIWinCSID(char_set_info),psz,psz,40);
  1824.  
  1825.         result = XmStringCreateLtoR(psz,XmSTRING_DEFAULT_CHARSET);
  1826.  
  1827.         if (psz)
  1828.         {
  1829.             XtFree(psz);
  1830.         }
  1831.     }
  1832.     else
  1833.     {
  1834.         result = tmp;
  1835.     }
  1836.  
  1837.     return result;
  1838. }
  1839. //////////////////////////////////////////////////////////////////////////
  1840. /* static */ XmString
  1841. XFE_BookmarkBase::formatItem(MWContext *    bookmarkContext, 
  1842.                              BM_Entry *        entry, 
  1843.                              Boolean        no_indent,
  1844.                              int16            charset)
  1845. {
  1846.   XmString xmhead, xmtail, xmcombo;
  1847.   int depth = (no_indent ? 0 : BM_GetDepth(bookmarkContext, entry));
  1848.   char head [255];
  1849.   char buf [1024];
  1850.   int j = 0;
  1851.   char *title = BM_GetName(entry);
  1852.   char *url = BM_GetAddress(entry);
  1853.   int indent = 2;
  1854.   int left_offset = 2;
  1855.   XmFontList font_list;
  1856.  
  1857.   if (! no_indent)
  1858.     {
  1859.       head [j++] = (BM_IsHeader(entry)
  1860.             ? (BM_IsFolded(entry) ? '+' : '-') :
  1861.             BM_IsSeparator(entry) ? ' ' :
  1862.             /* ### item->last_visit == 0*/ 0 ? '?' : ' ');
  1863.       while (j < ((depth * indent) + left_offset))
  1864.     head [j++] = ' ';
  1865.     }
  1866.   head [j] = 0;
  1867.  
  1868.   if (BM_IsSeparator(entry))
  1869.     {
  1870.       strcpy (buf, "-------------------------");
  1871.     }
  1872.   else if (title || url)
  1873.     {
  1874.       fe_FormatDocTitle (title, url, buf, 1024);
  1875.     }
  1876.   else if (BM_IsUrl(entry))
  1877.     {
  1878. #if 0
  1879.       strcpy (buf, XP_GetString( XFE_GG_EMPTY_LL ) );
  1880. #endif
  1881.     }
  1882.  
  1883.   if (!*head)
  1884.     xmhead = 0;
  1885.   else
  1886.     xmhead = XmStringSegmentCreate (head, "ICON", XmSTRING_DIRECTION_L_TO_R,
  1887.                     False);
  1888.  
  1889.   if (!*buf)
  1890.     xmtail = 0;
  1891.   else if (BM_IsUrl(entry))
  1892.     xmtail = fe_ConvertToXmString ((unsigned char *) buf, charset, 
  1893.                                         NULL, XmFONT_IS_FONT, &font_list);
  1894.   else
  1895.     {
  1896.       char *loc;
  1897.  
  1898.       loc = (char *) fe_ConvertToLocaleEncoding (charset,
  1899.                             (unsigned char *) buf);
  1900.       xmtail = XmStringSegmentCreate (loc, "HEADING",
  1901.                     XmSTRING_DIRECTION_L_TO_R, False);
  1902.       if (loc != buf)
  1903.     {
  1904.       XP_FREE(loc);
  1905.     }
  1906.     }
  1907.  
  1908.   if (xmhead && xmtail)
  1909.     {
  1910.       int size = XmStringLength (xmtail);
  1911.  
  1912.       /*
  1913.      There is a bug down under XmStringNConcat() where, in the process of
  1914.      appending the two strings, it will read up to four bytes past the end
  1915.      of the second string.  It doesn't do anything with the data it reads
  1916.      from there, but people have been regularly crashing as a result of it,
  1917.      because sometimes these strings end up at the end of the page!!
  1918.  
  1919.      I tried making the second string a bit longer (by adding some spaces
  1920.      to the end of `buf') and passing in a correspondingly smaller length
  1921.      to XmStringNConcat(), but that causes it not to append *any* of the
  1922.      characters in the second string.  So XmStringNConcat() would seem to
  1923.      simply not work at all when the length isn't exactly the same as the
  1924.      length of the second string.
  1925.  
  1926.      Plan B is to simply realloc() the XmString to make it a bit larger,
  1927.      so that we know that it's safe to go off the end.
  1928.  
  1929.      The NULLs at the beginning of the data we append probably aren't
  1930.      necessary, but they are read and parsed as a length, even though the
  1931.      data is not used (with the current structure of the XmStringNConcat()
  1932.      code.)  (The initialization of this memory is only necessary at all
  1933.      to keep Purify from (rightly) squawking about it.)
  1934.  
  1935.      And oh, by the way, the strncpy() down there, which I have verified
  1936.      is doing strncpy( <the-right-place> , <the-string-below>, 15 )
  1937.      actually writes 15 \000 bytes instead of four \000 bytes plus the
  1938.      random text below.  So I seem to have stumbled across a bug in
  1939.      strncpy() as well, even though it doesn't hose me.  THIS TIME. -- jwz
  1940.        */
  1941. #define MOTIF_BUG_BUFFER "\000\000\000\000 MOTIF BUG"
  1942. #ifdef MOTIF_BUG_BUFFER
  1943.       xmtail = (XmString) realloc ((void *) xmtail,
  1944.                    size + sizeof (MOTIF_BUG_BUFFER));
  1945.       strncpy (((char *) xmtail) + size, MOTIF_BUG_BUFFER,
  1946.            sizeof (MOTIF_BUG_BUFFER));
  1947. # undef MOTIF_BUG_BUFFER
  1948. #endif /* MOTIF_BUG_BUFFER */
  1949.  
  1950.       xmcombo = XmStringNConcat (xmhead, xmtail, size);
  1951.     }
  1952.   else if (xmhead)
  1953.     {
  1954.       xmcombo = xmhead;
  1955.       xmhead = 0;
  1956.     }
  1957.   else if (xmtail)
  1958.     {
  1959.       xmcombo = xmtail;
  1960.       xmtail = 0;
  1961.     }
  1962.   else
  1963.     {
  1964.       xmcombo = XmStringCreateLtoR ("", XmFONTLIST_DEFAULT_TAG);
  1965.     }
  1966.  
  1967.   if (xmhead) XmStringFree (xmhead);
  1968.   if (xmtail) XmStringFree (xmtail);
  1969.   return (xmcombo);
  1970. }
  1971. //////////////////////////////////////////////////////////////////////////
  1972.