]> www.fi.muni.cz Git - evince.git/commitdiff
Preliminary history implementation
authorNickolay V. Shmyrev <nshmyrev@yandex.ru>
Sun, 19 Nov 2006 00:51:27 +0000 (00:51 +0000)
committerNickolay V. Shmyrev <nshmyrev@src.gnome.org>
Sun, 19 Nov 2006 00:51:27 +0000 (00:51 +0000)
2006-11-19  Nickolay V. Shmyrev  <nshmyrev@yandex.ru>

* 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

18 files changed:
ChangeLog
data/evince-toolbar.xml
po/POTFILES.in
shell/Makefile.am
shell/ev-history.c [new file with mode: 0644]
shell/ev-history.h [new file with mode: 0644]
shell/ev-navigation-action-widget.c [new file with mode: 0644]
shell/ev-navigation-action-widget.h [new file with mode: 0644]
shell/ev-navigation-action.c [new file with mode: 0644]
shell/ev-navigation-action.h [new file with mode: 0644]
shell/ev-page-action-widget.c [new file with mode: 0644]
shell/ev-page-action-widget.h [new file with mode: 0644]
shell/ev-page-action.c
shell/ev-page-action.h
shell/ev-stock-icons.c
shell/ev-stock-icons.h
shell/ev-window.c
shell/main.c

index 958bd5b67ec736235988ed137f65a23874d0b5b3..09618d18e581c016267122a19b2dce988437117e 100644 (file)
--- 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  <nshmyrev@yandex.ru>
 
index ff0099ebef944b094048760caf71c76b75d8d6b3..e0cdedb3529454d6407a88cf15282c92dac4654d 100644 (file)
@@ -20,6 +20,7 @@
     <toolitem name="GoLastPage"/>
     <toolitem name="ViewReload"/>
     <toolitem name="ViewSidebar"/>
+    <toolitem name="Navigation"/>
 </available>
  <toolbar name="DefaultToolBar">
     <toolitem name="GoPreviousPage"/>
index 8df9d37acea5d77839a09b2a16827ae37d9e19ba..e998dffa7eb302035286a6d72d85a05d312d4b37 100644 (file)
@@ -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
index 6c1cdcf7d8bf8b035724ba3657b1bfe76f36c3e8..30dde9ed0219810da0dc67e3b45fd94c76310836 100644 (file)
@@ -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 (file)
index 0000000..2029d3c
--- /dev/null
@@ -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 <glib/gi18n.h>
+
+#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 (file)
index 0000000..a815f93
--- /dev/null
@@ -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 <glib-object.h>
+
+#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 (file)
index 0000000..1de4cf1
--- /dev/null
@@ -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 <glib/gi18n.h>
+#include <string.h>
+
+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 (file)
index 0000000..674b854
--- /dev/null
@@ -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 <gtk/gtk.h>
+
+#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 (file)
index 0000000..4eeda9a
--- /dev/null
@@ -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 <gtk/gtklabel.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkimagemenuitem.h>
+#include <gtk/gtkmenushell.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmenutoolbutton.h>
+#include <glib/gi18n.h>
+
+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 (file)
index 0000000..c801c39
--- /dev/null
@@ -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 <gtk/gtkaction.h>
+
+#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 (file)
index 0000000..5cd1054
--- /dev/null
@@ -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 <glib/gi18n.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtktoolitem.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkhbox.h>
+#include <string.h>
+
+/* 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 (file)
index 0000000..32efd00
--- /dev/null
@@ -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 <gtk/gtk.h>
+
+#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);
index 97abd1a7870a6dfdfc4a39074a11e4d4bb53f2d8..52c74f549e60e6c74eaed987d1cc0fbb16f7652c 100644 (file)
@@ -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 <glib/gi18n.h>
 #include <gtk/gtkhbox.h>
 #include <string.h>
 
-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);
index c8b30ba6d279cfbcb2d18b1ef1d914624ea9d84c..d89a3d90f03950154229a6a10d607f727e05635d 100644 (file)
@@ -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
index b0c9fd8fd0eadd9a839fafc39576d059c6761c87..cda5c53c052ce14504171d855897a50528de5f80 100644 (file)
@@ -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"},
 };
 
 
index a0a0fe119cfc4a4974fb671706366f93c4eb0a94..4064ef09b167f00bde27973b6a791c3d84eb6542 100644 (file)
@@ -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);
 
index 493e28f84bbb53194089c716c4e591e334b4f1f3..7fb90b2ea13bc333e580a594ada7c27c0f01e006 100644 (file)
@@ -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
index 9edb1f534a381251c756796c5e4f86362e58a784..fba38a790359cbe46b4379ca087a9aea958119e0 100644 (file)
@@ -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"