netscape-revival
cmd/xfe/history.c
/* -*- Mode: C; tab-width: 8 -*-
history.c --- UI routines called by the history module.
Copyright © 1995 Netscape Communications Corporation, all rights reserved.
Created: Jamie Zawinski <jwz@netscape.com>, 23-Jun-94.
*/
#include "mozilla.h"
#include "xfe.h"
#include "felocale.h"
/* Enable the "Back" button and menu item.
*/
int
FE_EnableBackButton (MWContext *context)
{
Widget w = CONTEXT_DATA (context)->back_button;
if (CONTEXT_DATA (context)->show_toolbar_p && w)
XtVaSetValues (w, XmNsensitive, True, 0);
w = CONTEXT_DATA (context)->back_menuitem;
if (w)
XtVaSetValues (w, XmNsensitive, True, 0);
return 0;
}
/* Disable the "Back" button and menu item.
*/
int
FE_DisableBackButton (MWContext *context)
{
Widget w = CONTEXT_DATA (context)->back_button;
if (CONTEXT_DATA (context)->show_toolbar_p && w)
XtVaSetValues (w, XmNsensitive, False, 0);
w = CONTEXT_DATA (context)->back_menuitem;
if (w)
XtVaSetValues (w, XmNsensitive, False, 0);
return 0;
}
/* Enable the "Forward" button and menu item.
*/
int
FE_EnableForwardButton (MWContext *context)
{
Widget w = CONTEXT_DATA (context)->forward_button;
if (CONTEXT_DATA (context)->show_toolbar_p && w)
XtVaSetValues (w, XmNsensitive, True, 0);
w = CONTEXT_DATA (context)->forward_menuitem;
if (w)
XtVaSetValues (w, XmNsensitive, True, 0);
return 0;
}
/* Disable the "Forward" button and menu item.
*/
int
FE_DisableForwardButton (MWContext *context)
{
Widget w = CONTEXT_DATA (context)->forward_button;
if (CONTEXT_DATA (context)->show_toolbar_p && w)
XtVaSetValues (w, XmNsensitive, False, 0);
w = CONTEXT_DATA (context)->forward_menuitem;
if (w)
XtVaSetValues (w, XmNsensitive, False, 0);
return 0;
}
/* History popup
*/
static void
fe_update_history_time (MWContext *context, History_entry *entry,
XP_List *hist)
{
entry->last_access = time ((time_t *) 0);
/* Flush this time into any bookmark entries that have the same URL. */
if (hist)
while ((hist = hist->next))
{
BookmarkStruct *h = hist->object;
if (h->type == HOT_URLType &&
h->address && entry->address &&
!strcmp (h->address, entry->address))
{
h->last_visit = entry->last_access;
fe_BookmarkAccessTimeChanged (context, h);
}
else if (h->type == HOT_HeaderType && h->children)
{
fe_update_history_time (context, entry, h->children);
}
}
}
static void
fe_history_menu_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
MWContext *context = (MWContext *) closure;
int index = -1;
History_entry *h;
URL_Struct *url;
XtVaGetValues (widget, XmNuserData, &index, 0);
if (index < 0) return;
h = SHIST_GetObjectNum (&context->hist, index);
if (! h) return;
url = SHIST_CreateURLStructFromHistoryEntry (context, h);
fe_update_history_time (context, h, HOT_GetBookmarkList ());
fe_GetURL (context, url, FALSE);
}
static void
fe_fill_history_selector (MWContext *context)
{
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;
XmString *items = 0;
Dimension width = 0, height = 0;
Widget *kids = 0;
Cardinal nkids = 0;
Arg av [20];
int ac;
Widget menu;
#if defined(EDITOR) && defined(EDITOR_UI)
int fast_and_loose = 7; /* Gold has browse publish location + separator */
#else
int fast_and_loose = 5; /* this is, uh, the top N items not to fuck with. */
#endif
int max_length = 30; /* spurious statistics up 15% this year. */
if (! history) return;
length = XP_ListCount (history);
history = history->next; /* How stupid!!! */
current = SHIST_GetCurrent (&context->hist);
menu = CONTEXT_DATA (context)->history_menu;
if (!menu) return;
/* Kill off the old history stuff in the menu: skip past the first
two items if they exist, otherwise create them.
*/
XtVaGetValues (menu, XmNchildren, &kids, XmNnumChildren, &nkids, 0);
XtUnrealizeWidget (menu);
/* if (nkids > fast_and_loose)
XtUnmanageChildren (kids + fast_and_loose, nkids - fast_and_loose);*/
if (nkids > fast_and_loose) {
fe_DestroyWidgetTree(&kids[fast_and_loose], nkids-fast_and_loose);
nkids = fast_and_loose;
}
if (nkids < fast_and_loose)
abort ();
if (length > max_length)
menu_length = max_length;
else
menu_length = length;
if (CONTEXT_DATA (context)->history_dialog)
items = (XmString *) malloc (sizeof (XmString) * length);
else
items = 0;
if (menu_length)
while (nkids > 0)
/* Force fucking Motif to recompute the width of the menu!! */
XtVaSetValues (kids[--nkids], XmNwidth, 10, 0);
if (menu_length)
kids = malloc (sizeof (Widget) * menu_length);
else
kids = 0;
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;
/* int pos = i - 1 - (length - menu_length);*/
XmString label;
char *title, *url;
char name [1024];
e = SHIST_GetObjectNum (&context->hist, i);
if (! e) abort ();
title = e->title;
url = e->address;
if (title && !strcmp (title, "Untitled"))
title = 0; /* You losers, don't do that to me! */
/* The dialog box */
if (items)
{
PR_snprintf (name, sizeof (name), "%-35.35s %.900s",
(title && *title ? title : "Untitled"),
(url ? url : "???"));
items [length - i] = fe_ConvertToXmString (context->win_csid,
(unsigned char *) name);
}
/* The pulldown menu */
if (pos == menu_length - 1 && menu_length < length)
{
kids [pos] = XmCreateLabelGadget (menu, "historyTruncated", 0, 0);
}
else if (pos < menu_length)
{
char buf [255];
fe_FormatDocTitle (title, url, name, 1024);
fe_MidTruncateString (name, name, 35);
label = fe_ConvertToXmString (context->win_csid,
(unsigned char *) name);
ac = 0;
XtSetArg (av [ac], XmNlabelString, label); ac++;
XtSetArg (av [ac], XmNuserData, i); ac++;
PR_snprintf (buf, sizeof (buf), "historyItem%d", pos + 1);
if (e == current)
{
XtSetArg (av [ac], XmNset, True); ac++;
XtSetArg (av [ac], XmNvisibleWhenOff, False); ac++;
XtSetArg (av [ac], XmNindicatorType, XmN_OF_MANY); ac++;
kids[pos] = XmCreateToggleButtonGadget(menu, buf, av, ac);
XtAddCallback (kids[pos], XmNvalueChangedCallback,
fe_history_menu_cb, context);
}
else
{
kids[pos] = XmCreatePushButtonGadget (menu, buf, av, ac);
XtAddCallback (kids[pos], XmNactivateCallback,fe_history_menu_cb,
context);
}
XmStringFree (label);
}
if (e == current)
cpos = length - i + 1;
h = h->next;
}
if (menu_length)
XtManageChildren (kids, menu_length);
if (kids) free (kids);
if (CONTEXT_DATA (context)->history_dialog)
{
XtVaGetValues (CONTEXT_DATA (context)->history_dialog,
XmNwidth, &width, XmNheight, &height, 0);
XtVaSetValues (CONTEXT_DATA (context)->history_dialog,
XmNlistItemCount, length,
XmNlistItems, items,
XmNwidth, width,
XmNheight, height,
0);
/* Update the current item. */
if (cpos)
{
Widget list = XtNameToWidget (CONTEXT_DATA (context)->history_dialog,
"*ItemsList");
int top_pos, vis;
XmListSelectPos (list, cpos, False);
/* Scroll the list if necessary. */
XtVaGetValues (list,
XmNtopItemPosition, &top_pos,
XmNvisibleItemCount, &vis, 0);
if (cpos >= top_pos + vis)
XmListSetBottomPos (list, cpos);
}
for (i = 0; i < length; i++)
XmStringFree (items [i]);
free (items);
}
XtRealizeWidget (menu);
}
void
fe_HistoryItemAction (Widget widget, XEvent *event, String *av, Cardinal *ac)
{
int n;
char dummy;
if (*ac < 1)
fprintf (stderr, "%s: too few args (%d) to HistoryItem()\n",
fe_progname, *ac);
else if (*ac > 2)
fprintf (stderr, "%s: too many args (%d) to HistoryItem()\n",
fe_progname, *ac);
else if (1 == sscanf (av[0], " %d %c", &n, &dummy))
{
Boolean done = False;
MWContext *context = fe_WidgetToMWContext (widget);
Widget menu;
Widget *kids = 0;
Cardinal nkids = 0;
char buf [255];
int i;
Boolean is_remote = False;
XP_ASSERT (context);
if (!context) return;
context = fe_GridToTopContext (context);
/* Check if this command is invoked from -remote*/
if ( !strcmp(av[*ac-1], "remote" ) )
{
is_remote = True;
}
/* History Action can come from remote therefore browser is required.
Need to find the Browser context in order for history to work
If there is a browser, then apply the history action */
if ( context->type != MWContextBrowser )
context = XP_FindContextOfType(context,MWContextBrowser );
if (!context) return;
menu = CONTEXT_DATA (context)->history_menu;
fe_UserActivity (context);
if (!menu) return;
PR_snprintf (buf, sizeof (buf), "historyItem%d", n);
XtVaGetValues (menu, XmNchildren, &kids, XmNnumChildren, &nkids, 0);
for (i = 0; i < nkids; i++)
if (!strcmp (buf, XtName (kids [i])))
{
XtCallCallbacks (kids [i],
(XmIsToggleButtonGadget (kids [i])
? XmNvalueChangedCallback
: XmNactivateCallback),
0);
done = True;
break;
}
if (! done)
XBell (XtDisplay (widget), 0);
/* If the command is from "-remote", make the browser window
to be at the front */
if ( is_remote )
{
XMapRaised(XtDisplay(CONTEXT_WIDGET(context)),
XtWindow(CONTEXT_WIDGET(context)));
}
}
else
fprintf (stderr, "%s: unknown parameter (%s) to HistoryItem()\n",
fe_progname, av[0]);
}
static void
fe_history_confirm_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
MWContext *context = (MWContext *) closure;
XmSelectionBoxCallbackStruct *cb = (XmSelectionBoxCallbackStruct *)call_data;
History_entry *h = 0;
int count;
int lower_p = 0;
int hot_p = 0;
XtVaGetValues (CONTEXT_DATA (context)->history_dialog,
XmNlistItemCount, &count, 0);
switch (cb->reason)
{
case XmCR_APPLY:
hot_p = 1;
/* fall through */
case XmCR_OK:
{
XP_List *history = (SHIST_GetList (context))->next; /* How stupid!! */
int *positions = 0;
int npositions = 0;
int pos = 0;
int count = 0;
Boolean free_p = False;
Widget list = XtNameToWidget (CONTEXT_DATA (context)->history_dialog,
"*ItemsList");
int i;
if (! list) abort ();
XtVaGetValues (list, XmNitemCount, &count, 0);
if (count <= 0)
break;
free_p = XmListGetSelectedPos (list, &positions, &npositions);
if (npositions > 0)
pos = *positions;
if (free_p && positions)
free (positions);
if (pos <= 0)
break;
for (i = count; (i > pos && history); i--)
history = history->next;
if (! history)
break;
h = history->object;
break;
}
case XmCR_CANCEL:
lower_p = 1;
break;
default:
abort ();
break;
}
if (lower_p)
XtUnmanageChild (CONTEXT_DATA (context)->history_dialog);
if (h)
{
URL_Struct *url = SHIST_CreateURLStructFromHistoryEntry (context, h);
if (! url) return;
if (hot_p)
{
fe_AddToBookmark (context, h->title, url, h->last_access);
}
else
{
fe_update_history_time (context, h, HOT_GetBookmarkList ());
fe_GetURL (context, url, FALSE);
}
}
}
static void
fe_make_history_dialog (MWContext *context)
{
Widget mainw = CONTEXT_WIDGET (context);
Arg av [20];
int ac;
Widget shell;
Visual *v = 0;
Colormap cmap = 0;
Cardinal depth = 0;
XtVaGetValues (mainw, XtNvisual, &v, XtNcolormap, &cmap,
XtNdepth, &depth, 0);
ac = 0;
XtSetArg (av[ac], XmNvisual, v); ac++;
XtSetArg (av[ac], XmNcolormap, cmap); ac++;
XtSetArg (av[ac], XmNdepth, depth); ac++;
XtSetArg (av[ac], XmNtransientFor, mainw); ac++;
XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_MODELESS); ac++;
XtSetArg (av[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
shell = XmCreateSelectionDialog (mainw, "history", av, ac);
XtVaSetValues (XtParent (shell), XmNallowShellResize, False, 0);
CONTEXT_DATA (context)->history_dialog = shell;
XtAddCallback (shell, XmNokCallback, fe_history_confirm_cb, context);
XtAddCallback (shell, XmNcancelCallback, fe_history_confirm_cb, context);
XtAddCallback (shell, XmNapplyCallback, fe_history_confirm_cb, context);
XtUnmanageChild (XmSelectionBoxGetChild (shell, XmDIALOG_SEPARATOR));
XtUnmanageChild (XmSelectionBoxGetChild (shell, XmDIALOG_TEXT));
XtUnmanageChild (XmSelectionBoxGetChild (shell, XmDIALOG_SELECTION_LABEL));
XtUnmanageChild (XmSelectionBoxGetChild (shell, XmDIALOG_LIST_LABEL));
#ifdef NO_HELP
XtUnmanageChild (XmSelectionBoxGetChild (shell, XmDIALOG_HELP_BUTTON));
#endif
fe_NukeBackingStore (shell);
XtManageChild (shell);
}
void
fe_HistoryDialog (MWContext *context)
{
if (!CONTEXT_DATA (context)->history_dialog)
fe_make_history_dialog (context);
fe_fill_history_selector (context);
XtManageChild (CONTEXT_DATA (context)->history_dialog);
}
/* If url is 0, don't actually add anything to the history, but do
update the history window if necessary.
*/
void
fe_AddHistory (MWContext *context, URL_Struct *url, const char *doc_title)
{
if (! doc_title) doc_title = "";
if (url)
SHIST_AddDocument (context,
SHIST_CreateHistoryEntry (url, (char *) doc_title));
fe_fill_history_selector (context);
}
void
fe_RegenerateHistoryMenu (MWContext *context)
{
fe_fill_history_selector (context);
}