/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ /* HistoryMenu.cpp -- class for doing the dynamic history menus Created: Chris Toshok , 19-Dec-1996. */ #include "HistoryMenu.h" #include "HTMLView.h" #include "felocale.h" #include "intl_csi.h" #include // for XfeDestroyMenuWidgetTree() #include "xpgetstr.h" // for XP_GetString() extern int XFE_UNTITLED; #define MAX_ITEM_WIDTH 40 typedef struct HistoryCons { XFE_HistoryMenu *menu; int entry; } HistoryCons; XFE_HistoryMenu::XFE_HistoryMenu(Widget w, XFE_Frame *frame) { m_cascade = w; m_parentFrame = frame; XtAddCallback(m_cascade, XmNdestroyCallback, destroy_cb, this); XtVaGetValues(m_cascade, XmNsubMenuId, &m_submenu, NULL); XtVaGetValues(m_submenu, XmNnumChildren, &m_firstslot, NULL); XP_ASSERT(m_submenu); m_parentFrame->registerInterest(XFE_HTMLView::newURLLoading, this, (XFE_FunctionNotification)historyHasChanged_cb); // make sure we initially install an update callback historyHasChanged(NULL, NULL, NULL); } XFE_HistoryMenu::~XFE_HistoryMenu() { m_parentFrame->unregisterInterest(XFE_HTMLView::newURLLoading, this, (XFE_FunctionNotification)historyHasChanged_cb); } void XFE_HistoryMenu::generate(Widget cascade, XtPointer /*clientData*/, XFE_Frame *frame) { XFE_HistoryMenu *obj; obj = new XFE_HistoryMenu(cascade, frame); } void XFE_HistoryMenu::activate_cb(Widget, XtPointer cd, XtPointer) { HistoryCons *cons = (HistoryCons*)cd; XFE_HistoryMenu *obj = cons->menu; MWContext *context = obj->m_parentFrame->getContext(); History_entry *h; URL_Struct *url; int index = cons->entry; if (index < 0) return; h = SHIST_GetObjectNum (&context->hist, index); if (! h) return; url = SHIST_CreateURLStructFromHistoryEntry (context, h); if (obj->m_parentFrame->handlesCommand(xfeCmdOpenUrl, (void*)url)) obj->m_parentFrame->doCommand(xfeCmdOpenUrl, (void*)url); } void XFE_HistoryMenu::arm_cb(Widget, XtPointer cd, XtPointer) { HistoryCons *cons = (HistoryCons*)cd; XFE_HistoryMenu *obj = cons->menu; MWContext *context = obj->m_parentFrame->getContext(); History_entry *h; char *address; int index = cons->entry; if (index < 0) return; h = SHIST_GetObjectNum (&context->hist, index); if (! h) return; address = h->address; if (!address) return; obj->m_parentFrame->notifyInterested(XFE_View::statusNeedsUpdatingMidTruncated, (void*)address); } void XFE_HistoryMenu::disarm_cb(Widget widget, XtPointer cd, XtPointer) { HistoryCons *cons = (HistoryCons*)cd; XFE_HistoryMenu *obj = cons->menu; MWContext *context = obj->m_parentFrame->getContext(); History_entry *h; char *address; int index = cons->entry; XtVaGetValues (widget, XmNuserData, &index, 0); if (index < 0) return; h = SHIST_GetObjectNum (&context->hist, index); if (! h) return; address = h->address; if (!address) return; obj->m_parentFrame->notifyInterested(XFE_View::statusNeedsUpdatingMidTruncated, (void*)""); } void XFE_HistoryMenu::update() { MWContext *context = m_parentFrame->getContext(); XP_List *history = SHIST_GetList (context); XP_List *h; History_entry *current; History_entry *e; int i; // int cpos = 0; int length = 0; int menu_length; Widget *kids = 0; Cardinal nkids = 0; Arg av [20]; int ac; int max_length = 30; /* spurious statistics up 15% this year. */ XmFontList font_list; INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context); if (! history) return; length = XP_ListCount (history); history = history->next; /* How stupid!!! */ current = SHIST_GetCurrent (&context->hist); XtUnrealizeWidget (m_submenu); XtVaGetValues (m_submenu, XmNchildren, &kids, XmNnumChildren, &nkids, 0); if (nkids) { kids = &(kids[m_firstslot]); nkids -= m_firstslot; if (nkids) { XtUnmanageChildren (kids, nkids); XfeDestroyMenuWidgetTree(kids, nkids,False); } } if (length > max_length) menu_length = max_length; else menu_length = length; h = history; /* i is the history index and starts at 1. pos is the index in the menu, with 0 being the first (topmost) item. */ for (i = length; i > 0; i--) { int pos = length - i; XmString label; char *title, *url; char name [1024]; Widget button = NULL; e = SHIST_GetObjectNum (&context->hist, i); if (! e) abort (); title = e->title; url = e->address; if (title && !strcmp (title, XP_GetString(XFE_UNTITLED))) title = 0; /* You losers, don't do that to me! */ ac = 0; /* NULL in userData so the menu updating stuff will use XtName for the command string */ XtSetArg (av [ac], XmNuserData, NULL); ac++; /* The pulldown menu */ if (pos == menu_length - 1 && menu_length < length) { button = XmCreateLabelGadget (m_submenu, "historyTruncated", av, ac); } else if (pos < menu_length) { HistoryCons *cons = XP_NEW_ZAP(HistoryCons); cons->menu = this; cons->entry = i; fe_FormatDocTitle (title, url, name, 1024); INTL_MidTruncateString (INTL_GetCSIWinCSID(c), name, name, MAX_ITEM_WIDTH); label = fe_ConvertToXmString ((unsigned char *) name, INTL_GetCSIWinCSID(c), NULL, XmFONT_IS_FONT, &font_list); XtSetArg (av [ac], XmNlabelString, label); ac++; if (e == current) { XtSetArg (av [ac], XmNset, True); ac++; XtSetArg (av [ac], XmNvisibleWhenOff, False); ac++; XtSetArg (av [ac], XmNindicatorType, XmN_OF_MANY); ac++; button = XmCreateToggleButtonGadget(m_submenu, xfeCmdOpenUrl, av, ac); // must be xfeCmdOpenUrl or sensitivity becomes a problem XtAddCallback (button, XmNvalueChangedCallback, activate_cb, cons); XtAddCallback (button, XmNarmCallback, arm_cb, cons); XtAddCallback (button, XmNdisarmCallback, disarm_cb, cons); } else { button = XmCreatePushButtonGadget (m_submenu, xfeCmdOpenUrl, av, ac); XtAddCallback (button, XmNarmCallback, arm_cb, cons); XtAddCallback (button, XmNdisarmCallback, disarm_cb, cons); XtAddCallback (button, XmNactivateCallback, activate_cb, cons); } XtAddCallback(button, XmNdestroyCallback, free_cons_cb, cons); XmStringFree (label); } if (button != NULL) { XtManageChild(button); } // if (e == current) // cpos = length - i + 1; h = h->next; } XtRealizeWidget (m_submenu); XtRemoveCallback(m_cascade, XmNcascadingCallback, update_cb, this); } void XFE_HistoryMenu::update_cb(Widget, XtPointer clientData, XtPointer) { XFE_HistoryMenu *obj = (XFE_HistoryMenu*)clientData; obj->update(); } void XFE_HistoryMenu::destroy_cb(Widget, XtPointer clientData, XtPointer) { XFE_HistoryMenu *obj = (XFE_HistoryMenu*)clientData; delete obj; } void XFE_HistoryMenu::free_cons_cb(Widget, XtPointer clientData, XtPointer) { XP_FREE(clientData); } XFE_CALLBACK_DEFN(XFE_HistoryMenu, historyHasChanged)(XFE_NotificationCenter *, void *, void *) { // This may seem stupid, but it keeps us from having more than // one reference to this particular callback without having // to worry about other cascadingCallbacks. // remove it if it's already there XtRemoveCallback(m_cascade, XmNcascadingCallback, update_cb, this); // and then add it back. XtAddCallback(m_cascade, XmNcascadingCallback, update_cb, this); }