From 8228ff475e7dced57dbaa9550255534d0c275767 Mon Sep 17 00:00:00 2001 From: Nickolay V. Shmyrev Date: Sun, 19 Nov 2006 00:51:27 +0000 Subject: Preliminary history implementation 2006-11-19 Nickolay V. Shmyrev * data/evince-toolbar.xml: * po/POTFILES.in: * shell/Makefile.am: * shell/ev-navigation-action-widget.c: (ev_navigation_action_widget_init), (ev_navigation_action_widget_class_init), (menu_deactivate_cb), (menu_detacher), (ev_navigation_action_widget_set_menu), (menu_position_func), (popup_menu_under_arrow), (ev_navigation_action_widget_toggled), (ev_navigation_action_widget_button_press_event): * shell/ev-navigation-action-widget.h: * shell/ev-navigation-action.c: (ev_navigation_action_set_history), (ev_navigation_action_set_window), (activate_menu_item_cb), (new_history_menu_item), (new_empty_history_menu_item), (build_menu), (menu_activated_cb), (connect_proxy), (create_tool_item), (ev_navigation_action_init), (ev_navigation_action_finalize), (ev_navigation_action_class_init): * shell/ev-navigation-action.h: * shell/ev-page-action-widget.c: (ev_page_action_widget_init), (ev_page_action_widget_set_page_cache), (ev_page_action_widget_finalize), (ev_page_action_widget_class_init), (match_selected_cb), (display_completion_text), (match_completion), (build_new_tree_cb), (get_filter_model_from_model), (ev_page_action_widget_update_model): * shell/ev-page-action-widget.h: * shell/ev-page-action.c: (activate_link_cb), (update_model), (connect_proxy): * shell/ev-page-action.h: * shell/ev-stock-icons.c: * shell/ev-stock-icons.h: * shell/ev-window.c: (ev_window_setup_action_sensitivity), (page_changed_cb), (ev_window_setup_document), (ev_window_dispose), (register_custom_actions): * shell/main.c: Preliminary history implementation --- diff --git a/ChangeLog b/ChangeLog index 958bd5b..09618d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -35,6 +35,8 @@ (page_changed_cb), (ev_window_setup_document), (ev_window_dispose), (register_custom_actions): * shell/main.c: + + Preliminary history implementation 2006-11-16 Nickolay V. Shmyrev diff --git a/data/evince-toolbar.xml b/data/evince-toolbar.xml index ff0099e..e0cdedb 100644 --- a/data/evince-toolbar.xml +++ b/data/evince-toolbar.xml @@ -20,6 +20,7 @@ + diff --git a/po/POTFILES.in b/po/POTFILES.in index 8df9d37..e998dff 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -21,7 +21,10 @@ ps/gsdefaults.c ps/ps-document.c shell/eggfindbar.c shell/ev-application.c +shell/ev-navigation-action.c +shell/ev-navigation-action-widget.c shell/ev-page-action.c +shell/ev-page-action-widget.c shell/ev-password.c shell/ev-password-view.c shell/ev-print-job.c diff --git a/shell/Makefile.am b/shell/Makefile.am index 6c1cdcf..30dde9e 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -31,12 +31,20 @@ evince_SOURCES= \ ev-job-queue.c \ ev-jobs.h \ ev-jobs.c \ + ev-history.c \ + ev-history.h \ ev-marshal.c \ ev-marshal.h \ ev-metadata-manager.c \ ev-metadata-manager.h \ + ev-navigation-action.c \ + ev-navigation-action.h \ + ev-navigation-action-widget.c \ + ev-navigation-action-widget.h \ ev-page-action.c \ ev-page-action.h \ + ev-page-action-widget.c \ + ev-page-action-widget.h \ ev-page-cache.h \ ev-page-cache.c \ ev-password.h \ diff --git a/shell/ev-history.c b/shell/ev-history.c new file mode 100644 index 0000000..2029d3c --- /dev/null +++ b/shell/ev-history.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2005 Marco Pesenti Gritti + * + * 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. + * + */ + +#include "config.h" + +#include + +#include "ev-history.h" + +struct _EvHistoryPrivate +{ + GList *links; + int current_index; +}; + +enum { + PROP_0, + PROP_INDEX +}; + +static void ev_history_init (EvHistory *history); +static void ev_history_class_init (EvHistoryClass *class); + +static GObjectClass *parent_class = NULL; + +G_DEFINE_TYPE (EvHistory, ev_history, G_TYPE_OBJECT) + +#define EV_HISTORY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_HISTORY, EvHistoryPrivate)) + +static void +ev_history_init (EvHistory *history) +{ + history->priv = EV_HISTORY_GET_PRIVATE (history); + + history->priv->links = NULL; + history->priv->current_index = -1; +} + +static void +free_links_list (GList *l) +{ + g_list_foreach (l, (GFunc)g_object_unref, NULL); + g_list_free (l); +} + +static void +ev_history_finalize (GObject *object) +{ + EvHistory *history = EV_HISTORY (object); + + free_links_list (history->priv->links); + + parent_class->finalize (object); +} + +static void +ev_history_get_property (GObject *object, guint prop_id, GValue *value, + GParamSpec *param_spec) +{ + EvHistory *self; + + self = EV_HISTORY (object); + + switch (prop_id) { + case PROP_INDEX: + g_value_set_int (value, self->priv->current_index); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, + prop_id, + param_spec); + break; + } +} + +static void +ev_history_set_property (GObject *object, guint prop_id, const GValue *value, + GParamSpec *param_spec) +{ + EvHistory *self; + + self = EV_HISTORY (object); + + switch (prop_id) { + case PROP_INDEX: + ev_history_set_current_index (self, g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, + prop_id, + param_spec); + break; + } +} + +static void +ev_history_class_init (EvHistoryClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = ev_history_finalize; + object_class->set_property = ev_history_set_property; + object_class->get_property = ev_history_get_property; + + parent_class = g_type_class_peek_parent (class); + + g_object_class_install_property (object_class, + PROP_INDEX, + g_param_spec_int ("index", + "Current Index", + "The current index", + -1, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + + g_type_class_add_private (object_class, sizeof (EvHistoryPrivate)); +} + +void +ev_history_add_link (EvHistory *history, EvLink *link) +{ + int length; + + g_return_if_fail (EV_IS_HISTORY (history)); + g_return_if_fail (EV_IS_LINK (link)); + + length = g_list_length (history->priv->links); + if (history->priv->current_index < length - 1) { + GList *l = g_list_nth (history->priv->links, + history->priv->current_index + 1); + + if (l->prev) { + l->prev->next = NULL; + free_links_list (l); + } else { + free_links_list (history->priv->links); + history->priv->links = NULL; + } + } + + g_object_ref (link); + history->priv->links = g_list_append (history->priv->links, + link); + + length = g_list_length (history->priv->links); + history->priv->current_index = length - 1; +} + +void +ev_history_add_page (EvHistory *history, int page) +{ + EvLink *link; + EvLinkDest *dest; + EvLinkAction *action; + gchar *title; + + g_return_if_fail (EV_IS_HISTORY (history)); + title = g_strdup_printf (_("Page: %d"), page); + + dest = ev_link_dest_new_page (page); + action = ev_link_action_new_dest (dest); + link = ev_link_new (title, action); + g_free (title); + + ev_history_add_link (history, link); +} + +EvLink * +ev_history_get_link_nth (EvHistory *history, int index) +{ + GList *l; + + g_return_val_if_fail (EV_IS_HISTORY (history), NULL); + + l = g_list_nth (history->priv->links, index); + + return EV_LINK (l->data); +} + +int +ev_history_get_n_links (EvHistory *history) +{ + g_return_val_if_fail (EV_IS_HISTORY (history), -1); + + return g_list_length (history->priv->links); +} + +int +ev_history_get_current_index (EvHistory *history) +{ + g_return_val_if_fail (EV_IS_HISTORY (history), -1); + + return history->priv->current_index; +} + +void +ev_history_set_current_index (EvHistory *history, int index) +{ + g_return_if_fail (EV_IS_HISTORY (history)); + + history->priv->current_index = index; + + g_object_notify (G_OBJECT (history), "index"); +} + +EvHistory * +ev_history_new (void) +{ + return EV_HISTORY (g_object_new (EV_TYPE_HISTORY, NULL)); +} diff --git a/shell/ev-history.h b/shell/ev-history.h new file mode 100644 index 0000000..a815f93 --- /dev/null +++ b/shell/ev-history.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2005 Marco Pesenti Gritti + * + * 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. + * + */ + +#ifndef EV_HISTORY_H +#define EV_HISTORY_H + +#include + +#include "ev-link.h" + +G_BEGIN_DECLS + +#define EV_TYPE_HISTORY (ev_history_get_type ()) +#define EV_HISTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_HISTORY, EvHistory)) +#define EV_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_HISTORY, EvHistoryClass)) +#define EV_IS_HISTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_HISTORY)) +#define EV_IS_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EV_TYPE_HISTORY)) +#define EV_HISTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EV_TYPE_HISTORY, EvHistoryClass)) + +typedef struct _EvHistory EvHistory; +typedef struct _EvHistoryPrivate EvHistoryPrivate; +typedef struct _EvHistoryClass EvHistoryClass; + +struct _EvHistory +{ + GObject parent; + + /*< private >*/ + EvHistoryPrivate *priv; +}; + +struct _EvHistoryClass +{ + GObjectClass parent_class; +}; + +GType ev_history_get_type (void); +EvHistory *ev_history_new (void); +void ev_history_add_link (EvHistory *history, + EvLink *linkk); +void ev_history_add_page (EvHistory *history, + int page); +EvLink *ev_history_get_link_nth (EvHistory *history, + int index); +int ev_history_get_n_links (EvHistory *history); +int ev_history_get_current_index (EvHistory *history); +void ev_history_set_current_index (EvHistory *history, + int index); + +G_END_DECLS + +#endif diff --git a/shell/ev-navigation-action-widget.c b/shell/ev-navigation-action-widget.c new file mode 100644 index 0000000..1de4cf1 --- /dev/null +++ b/shell/ev-navigation-action-widget.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2003, 2004 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + */ + +#include "config.h" +#include "ev-navigation-action-widget.h" + +#include +#include + +static void ev_navigation_action_widget_init (EvNavigationActionWidget *action_widget); +static void ev_navigation_action_widget_class_init (EvNavigationActionWidgetClass *action_widget); +static void ev_navigation_action_widget_toggled (GtkToggleToolButton *toggle); +static gboolean ev_navigation_action_widget_button_press_event (GtkWidget *widget, + GdkEventButton *event); + +G_DEFINE_TYPE (EvNavigationActionWidget, ev_navigation_action_widget, GTK_TYPE_TOGGLE_TOOL_BUTTON) + +enum +{ + SHOW_MENU, + LAST_SIGNAL +}; + +static gint signals[LAST_SIGNAL]; + +static void +ev_navigation_action_widget_init (EvNavigationActionWidget *action_widget) +{ + return; +} + +static void +ev_navigation_action_widget_class_init (EvNavigationActionWidgetClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkToggleToolButtonClass *toggle_tool_button_class = GTK_TOGGLE_TOOL_BUTTON_CLASS (klass); + + widget_class->button_press_event = ev_navigation_action_widget_button_press_event; + toggle_tool_button_class->toggled = ev_navigation_action_widget_toggled; + + + signals[SHOW_MENU] = + g_signal_new ("show-menu", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EvNavigationActionWidgetClass, show_menu), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static int +menu_deactivate_cb (GtkMenuShell *menu_shell, + EvNavigationActionWidget *widget) +{ + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (widget), FALSE); + return TRUE; +} + +static void +menu_detacher (GtkWidget *widget, + GtkMenu *menu) +{ + EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (widget); + g_return_if_fail (button->menu == menu); + button->menu = NULL; +} + +void +ev_navigation_action_widget_set_menu(EvNavigationActionWidget *button, GtkWidget *menu) +{ + + if (button->menu == GTK_MENU (menu)) + return; + + if (button->menu && GTK_WIDGET_VISIBLE (button->menu)) + gtk_menu_shell_deactivate (GTK_MENU_SHELL (button->menu)); + + if (button->menu) { + g_signal_handlers_disconnect_by_func (button->menu, + menu_deactivate_cb, + button); + gtk_menu_detach (button->menu); + } + + button->menu = GTK_MENU (menu); + + if (button->menu) { + gtk_menu_attach_to_widget (button->menu, GTK_WIDGET (button), + menu_detacher); + g_signal_connect (button->menu, "deactivate", + G_CALLBACK (menu_deactivate_cb), button); + } +} + +static void +menu_position_func (GtkMenu *menu, + int *x, + int *y, + gboolean *push_in, + EvNavigationActionWidget *button) +{ + GtkWidget *widget = GTK_WIDGET (button); + GtkRequisition menu_req; + GtkTextDirection direction; + GdkRectangle monitor; + gint monitor_num; + GdkScreen *screen; + + gtk_widget_size_request (GTK_WIDGET (button->menu), &menu_req); + direction = gtk_widget_get_direction (widget); + screen = gtk_widget_get_screen (GTK_WIDGET (menu)); + + monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window); + if (monitor_num < 0) + monitor_num = 0; + gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + + gdk_window_get_origin (widget->window, x, y); + *x += widget->allocation.x; + *y += widget->allocation.y; + + if (direction == GTK_TEXT_DIR_LTR) + *x += MAX (widget->allocation.width - menu_req.width, 0); + else if (menu_req.width > widget->allocation.width) + *x -= menu_req.width - widget->allocation.width; + + if ((*y + widget->allocation.height + menu_req.height) <= monitor.y + monitor.height) + *y += widget->allocation.height; + else if ((*y - menu_req.height) >= monitor.y) + *y -= menu_req.height; + else if (monitor.y + monitor.height - (*y + widget->allocation.height) > *y) + *y += widget->allocation.height; + else + *y -= menu_req.height; + + *push_in = FALSE; +} + +static void +popup_menu_under_arrow (EvNavigationActionWidget *button, + GdkEventButton *event) +{ + if (!button->menu) + return; + + g_signal_emit (button, signals[SHOW_MENU], 0); + + gtk_menu_popup (button->menu, NULL, NULL, + (GtkMenuPositionFunc) menu_position_func, + button, + event ? event->button : 0, + event ? event->time : gtk_get_current_event_time ()); +} + +static void +ev_navigation_action_widget_toggled (GtkToggleToolButton *toggle) +{ + EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (toggle); + if (!button->menu) + return; + + if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button)) && + !GTK_WIDGET_VISIBLE (button->menu)) { + /* we get here only when the menu is activated by a key + * press, so that we can select the first menu item */ + popup_menu_under_arrow (button, NULL); + gtk_menu_shell_select_first (GTK_MENU_SHELL (button->menu), FALSE); + } +} + +static gboolean +ev_navigation_action_widget_button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (widget); + if (event->button == 1) { + popup_menu_under_arrow (button, event); + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (button), TRUE); + return TRUE; + } + return FALSE; +} diff --git a/shell/ev-navigation-action-widget.h b/shell/ev-navigation-action-widget.h new file mode 100644 index 0000000..674b854 --- /dev/null +++ b/shell/ev-navigation-action-widget.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2003, 2004 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + */ + +#include + +#define EV_TYPE_NAVIGATION_ACTION_WIDGET (ev_navigation_action_widget_get_type ()) +#define EV_NAVIGATION_ACTION_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_NAVIGATION_ACTION_WIDGET, EvNavigationActionWidget)) + +typedef struct _EvNavigationActionWidget EvNavigationActionWidget; +typedef struct _EvNavigationActionWidgetClass EvNavigationActionWidgetClass; + +struct _EvNavigationActionWidget +{ + GtkToggleToolButton parent; + + GtkMenu *menu; +}; + +struct _EvNavigationActionWidgetClass +{ + GtkToggleToolButtonClass parent_class; + + void (*show_menu) (EvNavigationActionWidget *widget); +}; + +GType ev_navigation_action_widget_get_type (void); + +void +ev_navigation_action_widget_set_menu(EvNavigationActionWidget *widget, GtkWidget *menu); diff --git a/shell/ev-navigation-action.c b/shell/ev-navigation-action.c new file mode 100644 index 0000000..4eeda9a --- /dev/null +++ b/shell/ev-navigation-action.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2003, 2004 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + */ + +#include "config.h" + +#include "ev-navigation-action.h" +#include "ev-navigation-action-widget.h" +#include "ev-window.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +struct _EvNavigationActionPrivate +{ + EvWindow *window; + EvHistory *history; +}; + +static void ev_navigation_action_init (EvNavigationAction *action); +static void ev_navigation_action_class_init (EvNavigationActionClass *class); + +static GObjectClass *parent_class = NULL; + +G_DEFINE_TYPE (EvNavigationAction, ev_navigation_action, GTK_TYPE_ACTION) + +#define MAX_LABEL_LENGTH 48 + +#define EV_NAVIGATION_ACTION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_NAVIGATION_ACTION, EvNavigationActionPrivate)) + +void +ev_navigation_action_set_history (EvNavigationAction *action, + EvHistory *history) +{ + action->priv->history = history; + + g_object_add_weak_pointer (G_OBJECT (action->priv->history), + (gpointer *) &action->priv->history); +} + +void +ev_navigation_action_set_window (EvNavigationAction *action, + EvWindow *window) +{ + action->priv->window = window; +} + +static void +activate_menu_item_cb (GtkWidget *widget, EvNavigationAction *action) +{ + int index; + + g_return_if_fail (EV_IS_HISTORY (action->priv->history)); + + index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "index")); + ev_history_set_current_index (action->priv->history, index); + + if (action->priv->window) { + EvLink *link; + EvLinkAction *link_action; + EvLinkDest *dest; + + link = ev_history_get_link_nth (action->priv->history, index); + link_action = ev_link_get_action (link); + dest = ev_link_action_get_dest (link_action); + + ev_window_goto_dest (action->priv->window, dest); + } +} + +static GtkWidget * +new_history_menu_item (EvNavigationAction *action, + EvLink *link, + int index) +{ + GtkLabel *label; + GtkWidget *item; + const char *title; + + title = ev_link_get_title (link); + item = gtk_image_menu_item_new_with_label (title); + g_object_set_data (G_OBJECT (item), "index", + GINT_TO_POINTER (index)); + + label = GTK_LABEL (GTK_BIN (item)->child); + gtk_label_set_ellipsize (label, PANGO_ELLIPSIZE_END); + gtk_label_set_max_width_chars (label, MAX_LABEL_LENGTH); + + g_signal_connect (item, "activate", + G_CALLBACK (activate_menu_item_cb), + action); + + gtk_widget_show (item); + + return item; +} + +static GtkWidget * +new_empty_history_menu_item (EvNavigationAction *action) +{ + GtkWidget *item; + + item = gtk_image_menu_item_new_with_label (_("Empty")); + gtk_widget_set_sensitive (item, FALSE); + gtk_widget_show (item); + + return item; +} + +static GtkWidget * +build_menu (EvNavigationAction *action) +{ + GtkMenuShell *menu; + GtkWidget *item; + EvLink *link; + EvHistory *history = action->priv->history; + int start, end, i; + + menu = GTK_MENU_SHELL (gtk_menu_new ()); + + if (history == NULL || ev_history_get_n_links (history) <= 0) { + item = new_empty_history_menu_item (action); + gtk_menu_shell_append (menu, item); + return GTK_WIDGET (menu); + } + + start = 0; + end = ev_history_get_n_links (history); + + for (i = start; i < end; i++) { + link = ev_history_get_link_nth (history, i); + item = new_history_menu_item (action, link, i); + gtk_menu_shell_append (menu, item); + } + + return GTK_WIDGET (menu); +} + +static void +menu_activated_cb (EvNavigationActionWidget *button, + EvNavigationAction *action) +{ + GtkWidget *menu; + + menu = build_menu (action); + ev_navigation_action_widget_set_menu (button, menu); +} + +static void +connect_proxy (GtkAction *action, GtkWidget *proxy) +{ + GtkWidget *menu; + + /* set dummy menu so the arrow gets sensitive */ + menu = gtk_menu_new (); + ev_navigation_action_widget_set_menu (EV_NAVIGATION_ACTION_WIDGET (proxy), menu); + + g_signal_connect (proxy, "show-menu", + G_CALLBACK (menu_activated_cb), action); + + GTK_ACTION_CLASS (parent_class)->connect_proxy (action, proxy); +} + +static GtkWidget * +create_tool_item (GtkAction *action) +{ + EvNavigationActionWidget *proxy; + + proxy = g_object_new (EV_TYPE_NAVIGATION_ACTION_WIDGET, NULL); + gtk_widget_show (GTK_WIDGET (proxy)); + + return GTK_WIDGET (proxy); +} + +static void +ev_navigation_action_init (EvNavigationAction *action) +{ + action->priv = EV_NAVIGATION_ACTION_GET_PRIVATE (action); +} + +static void +ev_navigation_action_finalize (GObject *object) +{ + EvNavigationAction *action = EV_NAVIGATION_ACTION (object); + + if (action->priv->history) { + g_object_add_weak_pointer (G_OBJECT (action->priv->history), + (gpointer *) &action->priv->history); + } + + parent_class->finalize (object); +} + +static void +ev_navigation_action_class_init (EvNavigationActionClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkActionClass *action_class = GTK_ACTION_CLASS (class); + + object_class->finalize = ev_navigation_action_finalize; + parent_class = g_type_class_peek_parent (class); + + action_class->toolbar_item_type = GTK_TYPE_TOOL_ITEM; + action_class->create_tool_item = create_tool_item; + action_class->connect_proxy = connect_proxy; + + g_type_class_add_private (object_class, sizeof (EvNavigationActionPrivate)); +} diff --git a/shell/ev-navigation-action.h b/shell/ev-navigation-action.h new file mode 100644 index 0000000..c801c39 --- /dev/null +++ b/shell/ev-navigation-action.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2003, 2004 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + */ + +#ifndef EV_NAVIGATION_ACTION_H +#define EV_NAVIGATION_ACTION_H + +#include + +#include "ev-history.h" +#include "ev-window.h" + +G_BEGIN_DECLS + +#define EV_TYPE_NAVIGATION_ACTION (ev_navigation_action_get_type ()) +#define EV_NAVIGATION_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_NAVIGATION_ACTION, EvNavigationAction)) +#define EV_NAVIGATION_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_NAVIGATION_ACTION, EvNavigationActionClass)) +#define EV_IS_NAVIGATION_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_NAVIGATION_ACTION)) +#define EV_IS_NAVIGATION_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EV_TYPE_NAVIGATION_ACTION)) +#define EV_NAVIGATION_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EV_TYPE_NAVIGATION_ACTION, EvNavigationActionClass)) + +typedef struct _EvNavigationAction EvNavigationAction; +typedef struct _EvNavigationActionPrivate EvNavigationActionPrivate; +typedef struct _EvNavigationActionClass EvNavigationActionClass; + +struct _EvNavigationAction +{ + GtkAction parent; + + /*< private >*/ + EvNavigationActionPrivate *priv; +}; + +struct _EvNavigationActionClass +{ + GtkActionClass parent_class; +}; + +GType ev_navigation_action_get_type (void); +void ev_navigation_action_set_history (EvNavigationAction *action, + EvHistory *history); +void ev_navigation_action_set_window (EvNavigationAction *action, + EvWindow *window); + +G_END_DECLS + +#endif diff --git a/shell/ev-page-action-widget.c b/shell/ev-page-action-widget.c new file mode 100644 index 0000000..5cd1054 --- /dev/null +++ b/shell/ev-page-action-widget.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2003, 2004 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + */ + +#include "config.h" + +#include "ev-page-action.h" +#include "ev-page-cache.h" +#include "ev-window.h" +#include "ev-document-links.h" +#include "ev-page-action-widget.h" +#include "ev-marshal.h" + +#include +#include +#include +#include +#include +#include + +/* Widget we pass back */ +static void ev_page_action_widget_init (EvPageActionWidget *action_widget); +static void ev_page_action_widget_class_init (EvPageActionWidgetClass *action_widget); + +enum +{ + WIDGET_ACTIVATE_LINK, + WIDGET_N_SIGNALS +}; + +static guint widget_signals[WIDGET_N_SIGNALS] = {0, }; + +G_DEFINE_TYPE (EvPageActionWidget, ev_page_action_widget, GTK_TYPE_TOOL_ITEM) + +static void +ev_page_action_widget_init (EvPageActionWidget *action_widget) +{ + return; +} + +void +ev_page_action_widget_set_page_cache (EvPageActionWidget *action_widget, + EvPageCache *page_cache) +{ + if (action_widget->page_cache != NULL) { + g_object_remove_weak_pointer (G_OBJECT (action_widget->page_cache), + (gpointer *)&action_widget->page_cache); + action_widget->page_cache = NULL; + } + + if (page_cache != NULL) { + action_widget->page_cache = page_cache; + g_object_add_weak_pointer (G_OBJECT (page_cache), + (gpointer *)&action_widget->page_cache); + } +} + +static void +ev_page_action_widget_finalize (GObject *object) +{ + EvPageActionWidget *action_widget = EV_PAGE_ACTION_WIDGET (object); + + ev_page_action_widget_set_page_cache (action_widget, NULL); +} + +static void +ev_page_action_widget_class_init (EvPageActionWidgetClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = ev_page_action_widget_finalize; + + widget_signals[WIDGET_ACTIVATE_LINK] = g_signal_new ("activate_link", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvPageActionClass, activate_link), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); + +} + +static gboolean +match_selected_cb (GtkEntryCompletion *completion, + GtkTreeModel *filter_model, + GtkTreeIter *filter_iter, + EvPageActionWidget *proxy) +{ + EvLink *link; + GtkTreeIter *iter; + + gtk_tree_model_get (filter_model, filter_iter, + 0, &iter, + -1); + gtk_tree_model_get (proxy->model, iter, + EV_DOCUMENT_LINKS_COLUMN_LINK, &link, + -1); + + g_signal_emit (proxy, widget_signals[WIDGET_ACTIVATE_LINK], 0, link); + + if (link) + g_object_unref (link); + + gtk_tree_iter_free (iter); + + return TRUE; +} + + +static void +display_completion_text (GtkCellLayout *cell_layout, + GtkCellRenderer *renderer, + GtkTreeModel *filter_model, + GtkTreeIter *filter_iter, + EvPageActionWidget *proxy) +{ + EvLink *link; + GtkTreeIter *iter; + + gtk_tree_model_get (filter_model, filter_iter, + 0, &iter, + -1); + gtk_tree_model_get (proxy->model, iter, + EV_DOCUMENT_LINKS_COLUMN_LINK, &link, + -1); + + g_object_set (renderer, "text", ev_link_get_title (link), NULL); + + if (link) + g_object_unref (link); + + gtk_tree_iter_free (iter); +} + +static gboolean +match_completion (GtkEntryCompletion *completion, + const gchar *key, + GtkTreeIter *filter_iter, + EvPageActionWidget *proxy) +{ + EvLink *link; + GtkTreeIter *iter; + const gchar *text = NULL; + + gtk_tree_model_get (gtk_entry_completion_get_model (completion), + filter_iter, + 0, &iter, + -1); + gtk_tree_model_get (proxy->model, iter, + EV_DOCUMENT_LINKS_COLUMN_LINK, &link, + -1); + + + if (link) { + text = ev_link_get_title (link); + g_object_unref (link); + } + + gtk_tree_iter_free (iter); + + if (text && key) { + gchar *normalized_text; + gchar *normalized_key; + gchar *case_normalized_text; + gchar *case_normalized_key; + gboolean retval = FALSE; + + normalized_text = g_utf8_normalize (text, -1, G_NORMALIZE_ALL); + normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL); + case_normalized_text = g_utf8_casefold (normalized_text, -1); + case_normalized_key = g_utf8_casefold (normalized_key, -1); + + if (strstr (case_normalized_text, case_normalized_key)) + retval = TRUE; + + g_free (normalized_text); + g_free (normalized_key); + g_free (case_normalized_text); + g_free (case_normalized_key); + + return retval; + } + + return FALSE; +} + +/* user data to set on the widget. */ +#define EPA_FILTER_MODEL_DATA "epa-filter-model" + +static gboolean +build_new_tree_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GtkTreeModel *filter_model = GTK_TREE_MODEL (data); + EvLink *link; + EvLinkAction *action; + EvLinkActionType type; + + gtk_tree_model_get (model, iter, + EV_DOCUMENT_LINKS_COLUMN_LINK, &link, + -1); + + if (!link) + return FALSE; + + action = ev_link_get_action (link); + if (!action) { + g_object_unref (link); + return FALSE; + } + + type = ev_link_action_get_action_type (action); + + if (type == EV_LINK_ACTION_TYPE_GOTO_DEST) { + GtkTreeIter filter_iter; + + gtk_list_store_append (GTK_LIST_STORE (filter_model), &filter_iter); + gtk_list_store_set (GTK_LIST_STORE (filter_model), &filter_iter, + 0, iter, + -1); + } + + g_object_unref (link); + + return FALSE; +} + +static GtkTreeModel * +get_filter_model_from_model (GtkTreeModel *model) +{ + GtkTreeModel *filter_model; + + filter_model = + (GtkTreeModel *) g_object_get_data (G_OBJECT (model), EPA_FILTER_MODEL_DATA); + if (filter_model == NULL) { + filter_model = (GtkTreeModel *) gtk_list_store_new (1, GTK_TYPE_TREE_ITER); + + gtk_tree_model_foreach (model, + build_new_tree_cb, + filter_model); + g_object_set_data_full (G_OBJECT (model), EPA_FILTER_MODEL_DATA, filter_model, g_object_unref); + } + + return filter_model; +} + + +void +ev_page_action_widget_update_model (EvPageActionWidget *proxy, GtkTreeModel *model) +{ + GtkTreeModel *filter_model; + + if (model != NULL) { + /* Magik */ + GtkEntryCompletion *completion; + GtkCellRenderer *renderer; + + proxy->model = model; + filter_model = get_filter_model_from_model (model); + + completion = gtk_entry_completion_new (); + + g_object_set (G_OBJECT (completion), + "popup-set-width", FALSE, + "model", filter_model, + NULL); + + g_signal_connect (completion, "match-selected", G_CALLBACK (match_selected_cb), proxy); + gtk_entry_completion_set_match_func (completion, + (GtkEntryCompletionMatchFunc) match_completion, + proxy, NULL); + + /* Set up the layout */ + renderer = (GtkCellRenderer *) + g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, + "ellipsize", PANGO_ELLIPSIZE_END, + "width_chars", 30, + NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), + renderer, + (GtkCellLayoutDataFunc) display_completion_text, + proxy, NULL); + gtk_entry_set_completion (GTK_ENTRY (proxy->entry), completion); + + g_object_unref (completion); + g_object_unref (model); + } +} diff --git a/shell/ev-page-action-widget.h b/shell/ev-page-action-widget.h new file mode 100644 index 0000000..32efd00 --- /dev/null +++ b/shell/ev-page-action-widget.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2003, 2004 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + */ + +#include "ev-page-cache.h" + +#include + +#define EV_TYPE_PAGE_ACTION_WIDGET (ev_page_action_widget_get_type ()) +#define EV_PAGE_ACTION_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_ACTION_WIDGET, EvPageActionWidget)) + +typedef struct _EvPageActionWidget EvPageActionWidget; +typedef struct _EvPageActionWidgetClass EvPageActionWidgetClass; + +struct _EvPageActionWidget +{ + GtkToolItem parent; + + GtkWidget *entry; + GtkWidget *label; + EvPageCache *page_cache; + guint signal_id; + GtkTreeModel *filter_model; + GtkTreeModel *model; +}; + +struct _EvPageActionWidgetClass +{ + GtkToolItemClass parent_class; + + void (* activate_link) (EvPageActionWidget *page_action, + EvLink *link); +}; + +GType ev_page_action_widget_get_type (void); + +void +ev_page_action_widget_update_model (EvPageActionWidget *proxy, GtkTreeModel *model); + +void +ev_page_action_widget_set_page_cache (EvPageActionWidget *action_widget, + EvPageCache *page_cache); diff --git a/shell/ev-page-action.c b/shell/ev-page-action.c index 97abd1a..52c74f5 100644 --- a/shell/ev-page-action.c +++ b/shell/ev-page-action.c @@ -16,7 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * $Id$ */ #include "config.h" @@ -25,6 +24,7 @@ #include "ev-page-cache.h" #include "ev-window.h" #include "ev-document-links.h" +#include "ev-page-action-widget.h" #include "ev-marshal.h" #include @@ -34,28 +34,6 @@ #include #include -typedef struct _EvPageActionWidget EvPageActionWidget; -typedef struct _EvPageActionWidgetClass EvPageActionWidgetClass; -struct _EvPageActionWidget -{ - GtkToolItem parent; - - GtkWidget *entry; - GtkWidget *label; - EvPageCache *page_cache; - guint signal_id; - GtkTreeModel *filter_model; - GtkTreeModel *model; -}; - -struct _EvPageActionWidgetClass -{ - GtkToolItemClass parent_class; - - void (* activate_link) (EvPageActionWidget *page_action, - EvLink *link); -}; - struct _EvPageActionPrivate { EvPageCache *page_cache; @@ -63,73 +41,6 @@ struct _EvPageActionPrivate }; -/* Widget we pass back */ -static GType ev_page_action_widget_get_type (void); -static void ev_page_action_widget_init (EvPageActionWidget *action_widget); -static void ev_page_action_widget_class_init (EvPageActionWidgetClass *action_widget); - -#define EV_TYPE_PAGE_ACTION_WIDGET (ev_page_action_widget_get_type ()) -#define EV_PAGE_ACTION_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_ACTION_WIDGET, EvPageActionWidget)) - -enum -{ - WIDGET_ACTIVATE_LINK, - WIDGET_N_SIGNALS -}; - -static guint widget_signals[WIDGET_N_SIGNALS] = {0, }; - -G_DEFINE_TYPE (EvPageActionWidget, ev_page_action_widget, GTK_TYPE_TOOL_ITEM) - -static void -ev_page_action_widget_init (EvPageActionWidget *action_widget) -{ - -} - -static void -ev_page_action_widget_set_page_cache (EvPageActionWidget *action_widget, - EvPageCache *page_cache) -{ - if (action_widget->page_cache != NULL) { - g_object_remove_weak_pointer (G_OBJECT (action_widget->page_cache), - (gpointer *)&action_widget->page_cache); - action_widget->page_cache = NULL; - } - - if (page_cache != NULL) { - action_widget->page_cache = page_cache; - g_object_add_weak_pointer (G_OBJECT (page_cache), - (gpointer *)&action_widget->page_cache); - } -} - -static void -ev_page_action_widget_finalize (GObject *object) -{ - EvPageActionWidget *action_widget = EV_PAGE_ACTION_WIDGET (object); - - ev_page_action_widget_set_page_cache (action_widget, NULL); -} - -static void -ev_page_action_widget_class_init (EvPageActionWidgetClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - - object_class->finalize = ev_page_action_widget_finalize; - - widget_signals[WIDGET_ACTIVATE_LINK] = g_signal_new ("activate_link", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (EvPageActionClass, activate_link), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - G_TYPE_OBJECT); - -} - static void ev_page_action_init (EvPageAction *action); static void ev_page_action_class_init (EvPageActionClass *class); @@ -152,9 +63,6 @@ enum { PROP_MODEL, }; -/* user data to set on the widget. */ -#define EPA_FILTER_MODEL_DATA "epa-filter-model" - static void update_pages_label (EvPageActionWidget *proxy, gint page, @@ -285,222 +193,22 @@ update_page_cache (EvPageAction *page, GParamSpec *pspec, EvPageActionWidget *pr proxy->signal_id = signal_id; } -static gboolean -build_new_tree_cb (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data) -{ - GtkTreeModel *filter_model = GTK_TREE_MODEL (data); - EvLink *link; - EvLinkAction *action; - EvLinkActionType type; - - gtk_tree_model_get (model, iter, - EV_DOCUMENT_LINKS_COLUMN_LINK, &link, - -1); - - if (!link) - return FALSE; - - action = ev_link_get_action (link); - if (!action) { - g_object_unref (link); - return FALSE; - } - - type = ev_link_action_get_action_type (action); - - if (type == EV_LINK_ACTION_TYPE_GOTO_DEST) { - GtkTreeIter filter_iter; - - gtk_list_store_append (GTK_LIST_STORE (filter_model), &filter_iter); - gtk_list_store_set (GTK_LIST_STORE (filter_model), &filter_iter, - 0, iter, - -1); - } - - g_object_unref (link); - - return FALSE; -} - -static GtkTreeModel * -get_filter_model_from_model (GtkTreeModel *model) -{ - GtkTreeModel *filter_model; - - filter_model = - (GtkTreeModel *) g_object_get_data (G_OBJECT (model), EPA_FILTER_MODEL_DATA); - if (filter_model == NULL) { - filter_model = (GtkTreeModel *) gtk_list_store_new (1, GTK_TYPE_TREE_ITER); - - gtk_tree_model_foreach (model, - build_new_tree_cb, - filter_model); - g_object_set_data_full (G_OBJECT (model), EPA_FILTER_MODEL_DATA, filter_model, g_object_unref); - } - - return filter_model; -} - -static gboolean -match_selected_cb (GtkEntryCompletion *completion, - GtkTreeModel *filter_model, - GtkTreeIter *filter_iter, - EvPageActionWidget *proxy) -{ - EvLink *link; - GtkTreeIter *iter; - - gtk_tree_model_get (filter_model, filter_iter, - 0, &iter, - -1); - gtk_tree_model_get (proxy->model, iter, - EV_DOCUMENT_LINKS_COLUMN_LINK, &link, - -1); - - g_signal_emit (proxy, widget_signals[WIDGET_ACTIVATE_LINK], 0, link); - - if (link) - g_object_unref (link); - - gtk_tree_iter_free (iter); - - return TRUE; -} - - static void -display_completion_text (GtkCellLayout *cell_layout, - GtkCellRenderer *renderer, - GtkTreeModel *filter_model, - GtkTreeIter *filter_iter, - EvPageActionWidget *proxy) -{ - EvLink *link; - GtkTreeIter *iter; - - gtk_tree_model_get (filter_model, filter_iter, - 0, &iter, - -1); - gtk_tree_model_get (proxy->model, iter, - EV_DOCUMENT_LINKS_COLUMN_LINK, &link, - -1); - - g_object_set (renderer, "text", ev_link_get_title (link), NULL); - - if (link) - g_object_unref (link); - - gtk_tree_iter_free (iter); -} - -static gboolean -match_completion (GtkEntryCompletion *completion, - const gchar *key, - GtkTreeIter *filter_iter, - EvPageActionWidget *proxy) +activate_link_cb (EvPageActionWidget *proxy, EvLink *link, EvPageAction *action) { - EvLink *link; - GtkTreeIter *iter; - const gchar *text = NULL; - - gtk_tree_model_get (gtk_entry_completion_get_model (completion), - filter_iter, - 0, &iter, - -1); - gtk_tree_model_get (proxy->model, iter, - EV_DOCUMENT_LINKS_COLUMN_LINK, &link, - -1); - - - if (link) { - text = ev_link_get_title (link); - g_object_unref (link); - } - - gtk_tree_iter_free (iter); - - if (text && key) { - gchar *normalized_text; - gchar *normalized_key; - gchar *case_normalized_text; - gchar *case_normalized_key; - gboolean retval = FALSE; - - normalized_text = g_utf8_normalize (text, -1, G_NORMALIZE_ALL); - normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL); - case_normalized_text = g_utf8_casefold (normalized_text, -1); - case_normalized_key = g_utf8_casefold (normalized_key, -1); - - if (strstr (case_normalized_text, case_normalized_key)) - retval = TRUE; - - g_free (normalized_text); - g_free (normalized_key); - g_free (case_normalized_text); - g_free (case_normalized_key); - - return retval; - } - - return FALSE; + g_signal_emit (action, signals[ACTIVATE_LINK], 0, link); } - static void update_model (EvPageAction *page, GParamSpec *pspec, EvPageActionWidget *proxy) -{ +{ GtkTreeModel *model; - GtkTreeModel *filter_model; g_object_get (G_OBJECT (page), "model", &model, NULL); - if (model != NULL) { - /* Magik */ - GtkEntryCompletion *completion; - GtkCellRenderer *renderer; - - proxy->model = model; - filter_model = get_filter_model_from_model (model); - - completion = gtk_entry_completion_new (); - - /* popup-set-width is 2.7.0 only */ - g_object_set (G_OBJECT (completion), - "popup-set-width", FALSE, - "model", filter_model, - NULL); - - g_signal_connect (completion, "match-selected", G_CALLBACK (match_selected_cb), proxy); - gtk_entry_completion_set_match_func (completion, - (GtkEntryCompletionMatchFunc) match_completion, - proxy, NULL); - - /* Set up the layout */ - renderer = (GtkCellRenderer *) - g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, - "ellipsize", PANGO_ELLIPSIZE_END, - "width_chars", 30, - NULL); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE); - gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), - renderer, - (GtkCellLayoutDataFunc) display_completion_text, - proxy, NULL); - gtk_entry_set_completion (GTK_ENTRY (proxy->entry), completion); - - g_object_unref (completion); - g_object_unref (model); - } -} -static void -activate_link_cb (EvPageActionWidget *proxy, EvLink *link, EvPageAction *action) -{ - g_signal_emit (action, signals[ACTIVATE_LINK], 0, link); + ev_page_action_widget_update_model (proxy, model); } static void @@ -515,14 +223,9 @@ connect_proxy (GtkAction *action, GtkWidget *proxy) action); update_page_cache (EV_PAGE_ACTION (action), NULL, EV_PAGE_ACTION_WIDGET (proxy)); - /* We only go through this whole rigmarole if we can set - * GtkEntryCompletion::popup-set-width, which appeared in - * GTK+-2.7.0 */ - if (gtk_check_version (2, 7, 0) == NULL) { - g_signal_connect_object (action, "notify::model", - G_CALLBACK (update_model), - proxy, 0); - } + g_signal_connect_object (action, "notify::model", + G_CALLBACK (update_model), + proxy, 0); } GTK_ACTION_CLASS (ev_page_action_parent_class)->connect_proxy (action, proxy); diff --git a/shell/ev-page-action.h b/shell/ev-page-action.h index c8b30ba..d89a3d9 100644 --- a/shell/ev-page-action.h +++ b/shell/ev-page-action.h @@ -16,7 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * $Id$ */ #ifndef EV_PAGE_ACTION_H diff --git a/shell/ev-stock-icons.c b/shell/ev-stock-icons.c index b0c9fd8..cda5c53 100644 --- a/shell/ev-stock-icons.c +++ b/shell/ev-stock-icons.c @@ -40,7 +40,9 @@ static const EvStockIcon stock_icons [] = { { EV_STOCK_ZOOM_WIDTH, "stock_zoom-page-width" }, { EV_STOCK_LEAVE_FULLSCREEN, "stock_leave-fullscreen" }, { EV_STOCK_VIEW_DUAL, "stock_preview-two-pages" }, - { EV_STOCK_VIEW_CONTINUOUS, "stock_new-master-document" } + { EV_STOCK_VIEW_CONTINUOUS, "stock_new-master-document" }, + { EV_STOCK_ROTATE_LEFT, "object-rotate-left"}, + { EV_STOCK_ROTATE_RIGHT, "object-rotate-right"}, }; diff --git a/shell/ev-stock-icons.h b/shell/ev-stock-icons.h index a0a0fe1..4064ef0 100644 --- a/shell/ev-stock-icons.h +++ b/shell/ev-stock-icons.h @@ -34,6 +34,8 @@ G_BEGIN_DECLS #define EV_STOCK_LEAVE_FULLSCREEN "stock_leave-fullscreen" #define EV_STOCK_VIEW_DUAL "stock_view-dual-page" #define EV_STOCK_VIEW_CONTINUOUS "stock_view-continuous" +#define EV_STOCK_ROTATE_LEFT "object-rotate-left" +#define EV_STOCK_ROTATE_RIGHT "object-rotate-right" void ev_stock_icons_init (void); diff --git a/shell/ev-window.c b/shell/ev-window.c index 493e28f..7fb90b2 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -30,6 +30,7 @@ #include "ev-window.h" #include "ev-window-title.h" +#include "ev-navigation-action.h" #include "ev-page-action.h" #include "ev-sidebar.h" #include "ev-sidebar-links.h" @@ -68,6 +69,7 @@ #include "ev-file-helpers.h" #include "ev-utils.h" #include "ev-debug.h" +#include "ev-history.h" #ifdef WITH_GNOME_PRINT #include "ev-print-job.h" @@ -162,7 +164,7 @@ struct _EvWindowPrivate { gboolean unlink_temp_file; EvDocument *document; - + EvHistory *history; EvPageCache *page_cache; EvWindowPageMode page_mode; EvWindowTitle *title; @@ -194,6 +196,7 @@ static const GtkTargetEntry ev_drop_types[] = { #define PAGE_SELECTOR_ACTION "PageSelector" #define ZOOM_CONTROL_ACTION "ViewZoom" +#define NAVIGATION_ACTION "Navigation" #define GCONF_OVERRIDE_RESTRICTIONS "/apps/evince/override_restrictions" #define GCONF_LOCKDOWN_SAVE "/desktop/gnome/lockdown/disable_save_to_disk" @@ -367,6 +370,7 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) /* Toolbar-specific actions: */ ev_window_set_action_sensitive (ev_window, PAGE_SELECTOR_ACTION, has_pages); ev_window_set_action_sensitive (ev_window, ZOOM_CONTROL_ACTION, has_pages); + ev_window_set_action_sensitive (ev_window, NAVIGATION_ACTION, has_pages); ev_window_update_actions (ev_window); } @@ -614,6 +618,9 @@ page_changed_cb (EvPageCache *page_cache, EvWindow *ev_window) { ev_window_update_actions (ev_window); + + if (ev_window->priv->history) + ev_history_add_page (ev_window->priv->history, page); if (!ev_window_is_empty (ev_window)) ev_metadata_manager_set_int (ev_window->priv->uri, "page", page); @@ -883,6 +890,13 @@ ev_window_setup_document (EvWindow *ev_window) ev_page_action_set_document (EV_PAGE_ACTION (action), document); ev_window_setup_action_sensitivity (ev_window); + if (ev_window->priv->history) + g_object_unref (ev_window->priv->history); + ev_window->priv->history = ev_history_new (); + action = gtk_action_group_get_action (ev_window->priv->action_group, NAVIGATION_ACTION); + ev_navigation_action_set_history (EV_NAVIGATION_ACTION (action), ev_window->priv->history); + ev_navigation_action_set_window (EV_NAVIGATION_ACTION (action), ev_window); + if (ev_window->priv->properties) { ev_properties_dialog_set_document (EV_PROPERTIES_DIALOG (ev_window->priv->properties), ev_window->priv->document); @@ -3570,6 +3584,11 @@ ev_window_dispose (GObject *object) priv->dest = NULL; } + if (priv->history) { + g_object_unref (priv->history); + priv->history = NULL; + } + if (priv->fullscreen_timeout_id) { g_source_remove (priv->fullscreen_timeout_id); priv->fullscreen_timeout_id = 0; @@ -3638,9 +3657,9 @@ static const GtkActionEntry entries[] = { G_CALLBACK (ev_window_cmd_edit_find_previous) }, { "EditToolbar", NULL, N_("T_oolbar"), NULL, NULL, G_CALLBACK (ev_window_cmd_edit_toolbar) }, - { "EditRotateLeft", "object-rotate-left", N_("Rotate _Left"), NULL, NULL, + { "EditRotateLeft", EV_STOCK_ROTATE_LEFT, N_("Rotate _Left"), NULL, NULL, G_CALLBACK (ev_window_cmd_edit_rotate_left) }, - { "EditRotateRight", "object-rotate-right", N_("Rotate _Right"), NULL, NULL, + { "EditRotateRight", EV_STOCK_ROTATE_RIGHT, N_("Rotate _Right"), NULL, NULL, G_CALLBACK (ev_window_cmd_edit_rotate_right) }, /* View menu */ @@ -3850,6 +3869,17 @@ register_custom_actions (EvWindow *window, GtkActionGroup *group) G_CALLBACK (zoom_control_changed_cb), window); gtk_action_group_add_action (group, action); g_object_unref (action); + + action = g_object_new (EV_TYPE_NAVIGATION_ACTION, + "name", NAVIGATION_ACTION, + "label", _("Navigation"), + "is_important", TRUE, + "short_label", _("Back"), + "stock_id", GTK_STOCK_GO_DOWN, + "tooltip", _("Move across visited pages"), + NULL); + gtk_action_group_add_action (group, action); + g_object_unref (action); } static void diff --git a/shell/main.c b/shell/main.c index 9edb1f5..fba38a7 100644 --- a/shell/main.c +++ b/shell/main.c @@ -15,7 +15,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * $Id$ */ #include "config.h" -- cgit v0.9.1