/*
* Copyright (C) 2002 Ricardo Fernández Pascual
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ephy-gobject-misc.h"
#include "ephy-marshal.h"
#include "ephy-tb-button.h"
#include "ephy-gui.h"
#include "ephy-string.h"
#include "ephy-navigation-button.h"
#include "ephy-debug.h"
#include <gtk/gtkstock.h>
#include <string.h>
#include <libgnome/gnome-i18n.h>
/**
* Private data
*/
struct _EphyNavigationButtonPrivate
{
EphyTbButton *widget;
EphyNavigationDirection direction;
gboolean show_arrow;
gboolean sensitive;
};
enum
{
TOOLBAR_ITEM_STYLE_PROP,
TOOLBAR_ITEM_ORIENTATION_PROP,
TOOLBAR_ITEM_WANT_LABEL_PROP
};
/**
* Private functions, only availble from this file
*/
static void ephy_navigation_button_class_init (EphyNavigationButtonClass *klass);
static void ephy_navigation_button_init (EphyNavigationButton *tb);
static void ephy_navigation_button_finalize_impl (GObject *o);
static GtkWidget * ephy_navigation_button_get_widget_impl (EphyTbItem *i);
static GdkPixbuf * ephy_navigation_button_get_icon_impl (EphyTbItem *i);
static gchar * ephy_navigation_button_get_name_human_impl (EphyTbItem *i);
static gchar * ephy_navigation_button_to_string_impl (EphyTbItem *i);
static EphyTbItem * ephy_navigation_button_clone_impl (EphyTbItem *i);
static void ephy_navigation_button_parse_properties_impl (EphyTbItem *i, const gchar *props);
static void ephy_navigation_button_menu_activated_cb (EphyTbButton *w, EphyNavigationButton *b);
static void ephy_navigation_button_clicked_cb (GtkWidget *w, EphyNavigationButton *b);
static gpointer ephy_tb_item_class;
/**
* TbiZoom object
*/
MAKE_GET_TYPE (ephy_navigation_button, "EphyNavigationButton", EphyNavigationButton,
ephy_navigation_button_class_init,
ephy_navigation_button_init, EPHY_TYPE_TBI);
static void
ephy_navigation_button_class_init (EphyNavigationButtonClass *klass)
{
G_OBJECT_CLASS (klass)->finalize = ephy_navigation_button_finalize_impl;
EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_navigation_button_get_widget_impl;
EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_navigation_button_get_icon_impl;
EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_navigation_button_get_name_human_impl;
EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_navigation_button_to_string_impl;
EPHY_TB_ITEM_CLASS (klass)->clone = ephy_navigation_button_clone_impl;
EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_navigation_button_parse_properties_impl;
ephy_tb_item_class = g_type_class_peek_parent (klass);
}
static void
ephy_navigation_button_init (EphyNavigationButton *tbi)
{
EphyNavigationButtonPrivate *p = g_new0 (EphyNavigationButtonPrivate, 1);
tbi->priv = p;
p->direction = EPHY_NAVIGATION_DIRECTION_UP;
p->show_arrow = TRUE;
p->sensitive = TRUE;
}
EphyNavigationButton *
ephy_navigation_button_new (void)
{
EphyNavigationButton *ret = g_object_new (EPHY_TYPE_NAVIGATION_BUTTON, NULL);
return ret;
}
static void
ephy_navigation_button_finalize_impl (GObject *o)
{
EphyNavigationButton *it = EPHY_NAVIGATION_BUTTON (o);
EphyNavigationButtonPrivate *p = it->priv;
if (p->widget)
{
g_object_unref (p->widget);
}
g_free (p);
LOG ("EphyNavigationButton finalized")
G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o);
}
static void
ephy_navigation_button_setup_widget (EphyNavigationButton *b)
{
EphyNavigationButtonPrivate *p = b->priv;
const gchar *label;
const gchar *tip;
gboolean prio;
if (!p->widget)
{
ephy_navigation_button_get_widget_impl (EPHY_TB_ITEM (b));
}
g_assert (EPHY_IS_TB_BUTTON (p->widget));
switch (p->direction)
{
case EPHY_NAVIGATION_DIRECTION_UP:
label = "gtk-go-up";
tip = _("Go up");
prio = FALSE;
break;
case EPHY_NAVIGATION_DIRECTION_BACK:
label = "gtk-go-back";
tip = _("Go back");
prio = TRUE;
break;
case EPHY_NAVIGATION_DIRECTION_FORWARD:
label = "gtk-go-forward";
tip = _("Go forward");
prio = FALSE;
break;
default:
g_assert_not_reached ();
label = NULL;
tip = NULL;
prio = FALSE;
break;
}
ephy_tb_button_set_label (p->widget, label);
ephy_tb_button_set_tooltip_text (p->widget, tip);
ephy_tb_button_set_priority (p->widget, prio);
ephy_tb_button_set_show_arrow (p->widget, p->show_arrow);
ephy_tb_button_set_sensitivity (p->widget, p->sensitive);
}
static GtkWidget *
ephy_navigation_button_get_widget_impl (EphyTbItem *i)
{
EphyNavigationButton *iz = EPHY_NAVIGATION_BUTTON (i);
EphyNavigationButtonPrivate *p = iz->priv;
if (!p->widget)
{
p->widget = ephy_tb_button_new ();
g_object_ref (p->widget);
ephy_tb_button_set_use_stock (p->widget, TRUE);
ephy_tb_button_set_enable_menu (p->widget, TRUE);
ephy_navigation_button_setup_widget (iz);
gtk_widget_show (GTK_WIDGET (p->widget));
g_signal_connect (p->widget, "menu-activated",
G_CALLBACK (ephy_navigation_button_menu_activated_cb), i);
g_signal_connect (ephy_tb_button_get_button (p->widget), "clicked",
G_CALLBACK (ephy_navigation_button_clicked_cb), i);
}
return GTK_WIDGET (p->widget);
}
static GdkPixbuf *
ephy_navigation_button_get_icon_impl (EphyTbItem *i)
{
EphyNavigationButtonPrivate *p = EPHY_NAVIGATION_BUTTON (i)->priv;
static GdkPixbuf *pb_up = NULL;
static GdkPixbuf *pb_back = NULL;
static GdkPixbuf *pb_forward = NULL;
if (!pb_up)
{
/* what's the easier way? */
GtkWidget *b = gtk_button_new ();
pb_up = gtk_widget_render_icon (b,
GTK_STOCK_GO_UP,
GTK_ICON_SIZE_SMALL_TOOLBAR,
NULL);
pb_back = gtk_widget_render_icon (b,
GTK_STOCK_GO_BACK,
GTK_ICON_SIZE_SMALL_TOOLBAR,
NULL);
pb_forward = gtk_widget_render_icon (b,
GTK_STOCK_GO_FORWARD,
GTK_ICON_SIZE_SMALL_TOOLBAR,
NULL);
gtk_widget_destroy (b);
}
switch (p->direction)
{
case EPHY_NAVIGATION_DIRECTION_BACK:
return g_object_ref (pb_back);
break;
case EPHY_NAVIGATION_DIRECTION_FORWARD:
return g_object_ref (pb_forward);
break;
case EPHY_NAVIGATION_DIRECTION_UP:
return g_object_ref (pb_up);
break;
default:
g_assert_not_reached ();
return NULL;
}
}
static gchar *
ephy_navigation_button_get_name_human_impl (EphyTbItem *i)
{
EphyNavigationButtonPrivate *p = EPHY_NAVIGATION_BUTTON (i)->priv;
const gchar *ret;
switch (p->direction)
{
case EPHY_NAVIGATION_DIRECTION_BACK:
ret = p->show_arrow
? _("Back (with menu)")
: _("Back");
break;
case EPHY_NAVIGATION_DIRECTION_FORWARD:
ret = p->show_arrow
? _("Forward (with menu)")
: _("Forward");
break;
case EPHY_NAVIGATION_DIRECTION_UP:
ret = p->show_arrow
? _("Up (with menu)")
: _("Up");
break;
default:
g_assert_not_reached ();
ret = "Error: unexpected direction";
break;
}
return g_strdup (ret);
}
static gchar *
ephy_navigation_button_to_string_impl (EphyTbItem *i)
{
EphyNavigationButtonPrivate *p = EPHY_NAVIGATION_BUTTON (i)->priv;
/* if it had any properties, the string should include them */
const char *sdir;
switch (p->direction)
{
case EPHY_NAVIGATION_DIRECTION_BACK:
sdir = "back";
break;
case EPHY_NAVIGATION_DIRECTION_FORWARD:
sdir = "forward";
break;
case EPHY_NAVIGATION_DIRECTION_UP:
sdir = "up";
break;
default:
g_assert_not_reached ();
sdir = "unknown";
}
return g_strdup_printf ("%s=navigation_button(direction=%s,arrow=%s)",
i->id, sdir, p->show_arrow ? "TRUE" : "FALSE");
}
static EphyTbItem *
ephy_navigation_button_clone_impl (EphyTbItem *i)
{
EphyTbItem *ret = EPHY_TB_ITEM (ephy_navigation_button_new ());
EphyNavigationButtonPrivate *p = EPHY_NAVIGATION_BUTTON (i)->priv;
ephy_tb_item_set_id (ret, i->id);
ephy_navigation_button_set_direction (EPHY_NAVIGATION_BUTTON (ret), p->direction);
ephy_navigation_button_set_show_arrow (EPHY_NAVIGATION_BUTTON (ret), p->show_arrow);
return ret;
}
static void
ephy_navigation_button_parse_properties_impl (EphyTbItem *it, const gchar *props)
{
EphyNavigationButton *b = EPHY_NAVIGATION_BUTTON (it);
/* we have two properties, the direction and the arrow */
const gchar *direc_prop;
const gchar *show_arrow_prop;
direc_prop = strstr (props, "direction=");
if (direc_prop)
{
direc_prop += strlen ("direction=");
if (!strncmp (direc_prop, "back", 4))
{
ephy_navigation_button_set_direction (b, EPHY_NAVIGATION_DIRECTION_BACK);
}
else if (!strncmp (direc_prop, "forward", 4))
{
ephy_navigation_button_set_direction (b, EPHY_NAVIGATION_DIRECTION_FORWARD);
}
else if (!strncmp (direc_prop, "up", 2))
{
ephy_navigation_button_set_direction (b, EPHY_NAVIGATION_DIRECTION_UP);
}
}
show_arrow_prop = strstr (props, "arrow=");
if (show_arrow_prop)
{
show_arrow_prop += strlen ("arrow=");
if (show_arrow_prop[0] == 'T')
{
ephy_navigation_button_set_show_arrow (b, TRUE);
}
else
{
ephy_navigation_button_set_show_arrow (b, FALSE);
}
}
}
void
ephy_navigation_button_set_direction (EphyNavigationButton *b,
EphyNavigationDirection d)
{
EphyNavigationButtonPrivate *p = b->priv;
p->direction = d;
ephy_navigation_button_setup_widget (b);
}
void
ephy_navigation_button_set_show_arrow (EphyNavigationButton *b,
gboolean value)
{
EphyNavigationButtonPrivate *p = b->priv;
p->show_arrow = value;
if (p->widget)
{
ephy_tb_button_set_show_arrow (p->widget, p->show_arrow);
}
else
{
ephy_navigation_button_get_widget_impl (EPHY_TB_ITEM (b));
}
}
EphyNavigationDirection
ephy_navigation_button_get_direction (EphyNavigationButton *b)
{
return b->priv->direction;
}
void
ephy_navigation_button_set_sensitive (EphyNavigationButton *b, gboolean s)
{
EphyNavigationButtonPrivate *p = b->priv;
p->sensitive = s;
if (p->widget)
{
ephy_tb_button_set_sensitivity (p->widget, s);
}
else
{
ephy_navigation_button_get_widget_impl (EPHY_TB_ITEM (b));
}
}
static void
ephy_navigation_button_clicked_cb (GtkWidget *w, EphyNavigationButton *b)
{
EphyNavigationButtonPrivate *p = b->priv;
EphyWindow *window;
EphyEmbed *embed;
window = ephy_tbi_get_window (EPHY_TBI (b));
g_return_if_fail (window != NULL);
embed = ephy_window_get_active_embed (window);
g_return_if_fail (embed != NULL);
switch (p->direction)
{
case EPHY_NAVIGATION_DIRECTION_UP:
ephy_embed_go_up (embed);
break;
case EPHY_NAVIGATION_DIRECTION_BACK:
ephy_embed_go_back (embed);
break;
case EPHY_NAVIGATION_DIRECTION_FORWARD:
ephy_embed_go_forward (embed);
break;
default:
g_assert_not_reached ();
break;
}
}
/* TODO: clean all this, it came from toolbar.c and is messy */
static GtkWidget *
new_history_menu_item (gchar *origtext,
const GdkPixbuf *ico)
{
GtkWidget *item = gtk_image_menu_item_new ();
GtkWidget *hb = gtk_hbox_new (FALSE, 0);
GtkWidget *label = gtk_label_new (origtext);
gtk_box_pack_start (GTK_BOX (hb), label, FALSE, FALSE, 0);
gtk_container_add (GTK_CONTAINER (item), hb);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
gtk_image_new_from_pixbuf ((GdkPixbuf *) ico));
gtk_widget_show_all (item);
return item;
}
static void
activate_back_or_forward_menu_item_cb (GtkWidget *menu, EphyWindow *window)
{
EphyEmbed *embed;
int go_nth;
embed = ephy_window_get_active_embed (window);
g_return_if_fail (embed != NULL);
go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth");
ephy_embed_shistory_go_nth (embed, go_nth);
}
static void
activate_up_menu_item_cb (GtkWidget *menu, EphyWindow *window)
{
EphyEmbed *embed;
int go_nth;
GSList *l;
gchar *url;
embed = ephy_window_get_active_embed (window);
g_return_if_fail (embed != NULL);
go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth");
ephy_embed_get_go_up_list (embed, &l);
url = g_slist_nth_data (l, go_nth);
if (url)
{
ephy_embed_load_url (embed, url);
}
g_slist_foreach (l, (GFunc) g_free, NULL);
g_slist_free (l);
}
static void
setup_back_or_forward_menu (EphyWindow *window, GtkMenuShell *ms, EphyNavigationDirection dir)
{
int pos, count;
EphyEmbed *embed;
int start, end;
embed = ephy_window_get_active_embed (window);
g_return_if_fail (embed != NULL);
ephy_embed_shistory_get_pos (embed, &pos);
ephy_embed_shistory_count (embed, &count);
if (count == 0) return;
if (dir == EPHY_NAVIGATION_DIRECTION_BACK)
{
start = pos - 1;
end = -1;
}
else
{
start = pos + 1;
end = count;
}
while (start != end)
{
char *title, *url;
GtkWidget *item;
ephy_embed_shistory_get_nth (embed, start, FALSE, &url, &title);
item = new_history_menu_item (title ? title : url, NULL);
gtk_menu_shell_append (ms, item);
g_object_set_data (G_OBJECT (item), "go_nth", GINT_TO_POINTER (start));
g_signal_connect (item, "activate",
G_CALLBACK (activate_back_or_forward_menu_item_cb), window);
gtk_widget_show_all (item);
g_free (url);
g_free (title);
if (start < end)
{
start++;
}
else
{
start--;
}
}
}
static void
setup_up_menu (EphyWindow *window, GtkMenuShell *ms)
{
EphyEmbed *embed;
GSList *l;
GSList *li;
int count = 0;
embed = ephy_window_get_active_embed (window);
g_return_if_fail (embed != NULL);
ephy_embed_get_go_up_list (embed, &l);
for (li = l; li; li = li->next)
{
char *url = li->data;
GtkWidget *item;
item = new_history_menu_item (url, NULL);
gtk_menu_shell_append (ms, item);
g_object_set_data (G_OBJECT(item), "go_nth", GINT_TO_POINTER (count));
g_signal_connect (item, "activate",
G_CALLBACK (activate_up_menu_item_cb), window);
gtk_widget_show_all (item);
count ++;
}
g_slist_foreach (l, (GFunc) g_free, NULL);
g_slist_free (l);
}
static void
ephy_navigation_button_menu_activated_cb (EphyTbButton *w, EphyNavigationButton *b)
{
EphyNavigationButtonPrivate *p = b->priv;
GtkMenuShell *ms = ephy_tb_button_get_menu (p->widget);
EphyWindow *win = ephy_tbi_get_window (EPHY_TBI (b));
GList *children;
GList *li;
children = gtk_container_get_children (GTK_CONTAINER (ms));
for (li = children; li; li = li->next)
{
gtk_container_remove (GTK_CONTAINER (ms), li->data);
}
g_list_free (children);
switch (p->direction)
{
case EPHY_NAVIGATION_DIRECTION_UP:
setup_up_menu (win, ms);
break;
case EPHY_NAVIGATION_DIRECTION_FORWARD:
case EPHY_NAVIGATION_DIRECTION_BACK:
setup_back_or_forward_menu (win, ms, p->direction);
break;
default:
g_assert_not_reached ();
break;
}
}