summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am7
-rw-r--r--src/ev-page-action-widget.c495
-rw-r--r--src/ev-page-action-widget.h46
-rw-r--r--src/ev-page-action.c239
-rw-r--r--src/ev-page-action.h68
-rw-r--r--src/evbp-viewer.c30
-rw-r--r--test/Makefile.am7
7 files changed, 887 insertions, 5 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 1353106..07b58b5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,5 +4,8 @@ plugindir = $(libdir)/mozilla/plugins
plugin_LTLIBRARIES = libevbp.la
libevbp_la_LDFLAGS = -avoid-version -module
libevbp_la_LIBADD = $(EVINCE_LIBS)
-libevbp_la_SOURCES = evbp.c evbp-viewer.h evbp-viewer.c evbp-mime.h \
- evbp-mime.c
+libevbp_la_SOURCES = evbp.c \
+ evbp-viewer.h evbp-viewer.c \
+ evbp-mime.h evbp-mime.c \
+ ev-page-action.h ev-page-action.c \
+ ev-page-action-widget.h ev-page-action-widget.c
diff --git a/src/ev-page-action-widget.c b/src/ev-page-action-widget.c
new file mode 100644
index 0000000..2bc74e6
--- /dev/null
+++ b/src/ev-page-action-widget.c
@@ -0,0 +1,495 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <evince-document.h>
+#include "ev-page-action.h"
+#include "ev-page-action-widget.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
+};
+
+struct _EvPageActionWidget
+{
+ GtkToolItem parent;
+
+ EvDocument *document;
+ EvDocumentModel *doc_model;
+
+ GtkWidget *entry;
+ GtkWidget *label;
+ guint signal_id;
+ GtkTreeModel *filter_model;
+ GtkTreeModel *model;
+};
+
+static guint widget_signals[WIDGET_N_SIGNALS] = {0, };
+
+G_DEFINE_TYPE (EvPageActionWidget, ev_page_action_widget, GTK_TYPE_TOOL_ITEM)
+
+static void
+update_pages_label (EvPageActionWidget *action_widget,
+ gint page)
+{
+ char *label_text;
+ gint n_pages;
+
+ n_pages = ev_document_get_n_pages (action_widget->document);
+ if (ev_document_has_text_page_labels (action_widget->document)) {
+ label_text = g_strdup_printf (_("(%d of %d)"), page + 1, n_pages);
+ } else {
+ label_text = g_strdup_printf (_("of %d"), n_pages);
+ }
+ gtk_label_set_text (GTK_LABEL (action_widget->label), label_text);
+ g_free (label_text);
+}
+
+static void
+ev_page_action_widget_set_current_page (EvPageActionWidget *action_widget,
+ gint page)
+{
+ if (page >= 0) {
+ gchar *page_label;
+
+ gtk_entry_set_width_chars (GTK_ENTRY (action_widget->entry),
+ CLAMP (ev_document_get_max_label_len (action_widget->document),
+ 6, 12));
+
+ page_label = ev_document_get_page_label (action_widget->document, page);
+ gtk_entry_set_text (GTK_ENTRY (action_widget->entry), page_label);
+ gtk_editable_set_position (GTK_EDITABLE (action_widget->entry), -1);
+ g_free (page_label);
+
+ } else {
+ gtk_entry_set_text (GTK_ENTRY (action_widget->entry), "");
+ }
+
+ update_pages_label (action_widget, page);
+}
+
+static void
+page_changed_cb (EvDocumentModel *model,
+ gint old_page,
+ gint new_page,
+ EvPageActionWidget *action_widget)
+{
+ ev_page_action_widget_set_current_page (action_widget, new_page);
+}
+
+static gboolean
+page_scroll_cb (EvPageActionWidget *action_widget, GdkEventScroll *event)
+{
+ EvDocumentModel *model = action_widget->doc_model;
+ gint pageno;
+
+ pageno = ev_document_model_get_page (model);
+ if ((event->direction == GDK_SCROLL_DOWN) &&
+ (pageno < ev_document_get_n_pages (action_widget->document) - 1))
+ pageno++;
+ if ((event->direction == GDK_SCROLL_UP) && (pageno > 0))
+ pageno--;
+ ev_document_model_set_page (model, pageno);
+
+ return TRUE;
+}
+
+static void
+activate_cb (EvPageActionWidget *action_widget)
+{
+ EvDocumentModel *model;
+ const char *text;
+ EvLinkDest *link_dest;
+ EvLinkAction *link_action;
+ EvLink *link;
+ gchar *link_text;
+ gint current_page;
+
+ model = action_widget->doc_model;
+ current_page = ev_document_model_get_page (model);
+
+ text = gtk_entry_get_text (GTK_ENTRY (action_widget->entry));
+
+ link_dest = ev_link_dest_new_page_label (text);
+ link_action = ev_link_action_new_dest (link_dest);
+ link_text = g_strdup_printf ("Page: %s", text);
+ link = ev_link_new (link_text, link_action);
+
+ g_signal_emit (action_widget, widget_signals[WIDGET_ACTIVATE_LINK], 0, link);
+
+ g_object_unref (link);
+ g_free (link_text);
+
+ if (current_page == ev_document_model_get_page (model))
+ ev_page_action_widget_set_current_page (action_widget, current_page);
+}
+
+static void
+ev_page_action_widget_init (EvPageActionWidget *action_widget)
+{
+ GtkWidget *hbox;
+ AtkObject *obj;
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_set_spacing (GTK_BOX (hbox), 6);
+
+ action_widget->entry = gtk_entry_new ();
+ gtk_widget_add_events (action_widget->entry,
+ GDK_BUTTON_MOTION_MASK);
+ gtk_entry_set_width_chars (GTK_ENTRY (action_widget->entry), 5);
+ gtk_entry_set_text (GTK_ENTRY (action_widget->entry), "");
+ g_signal_connect_swapped (action_widget->entry, "scroll-event",
+ G_CALLBACK (page_scroll_cb),
+ action_widget);
+ g_signal_connect_swapped (action_widget->entry, "activate",
+ G_CALLBACK (activate_cb),
+ action_widget);
+
+ obj = gtk_widget_get_accessible (action_widget->entry);
+ atk_object_set_name (obj, "page-label-entry");
+
+ gtk_box_pack_start (GTK_BOX (hbox), action_widget->entry,
+ FALSE, FALSE, 0);
+ gtk_widget_show (action_widget->entry);
+
+ action_widget->label = gtk_label_new (NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), action_widget->label,
+ FALSE, FALSE, 0);
+ gtk_widget_show (action_widget->label);
+
+ gtk_container_set_border_width (GTK_CONTAINER (action_widget), 6);
+ gtk_container_add (GTK_CONTAINER (action_widget), hbox);
+ gtk_widget_show (hbox);
+
+ gtk_widget_show (GTK_WIDGET (action_widget));
+}
+
+static void
+ev_page_action_widget_document_changed_cb (EvDocumentModel *model,
+ GParamSpec *pspec,
+ EvPageActionWidget *action_widget)
+{
+ EvDocument *document = ev_document_model_get_document (model);
+
+ g_object_ref (document);
+ if (action_widget->document)
+ g_object_unref (action_widget->document);
+ action_widget->document = document;
+
+ if (action_widget->signal_id > 0) {
+ g_signal_handler_disconnect (action_widget->doc_model,
+ action_widget->signal_id);
+ action_widget->signal_id = 0;
+ }
+ action_widget->signal_id =
+ g_signal_connect_object (action_widget->doc_model,
+ "page-changed",
+ G_CALLBACK (page_changed_cb),
+ action_widget, 0);
+
+ ev_page_action_widget_set_current_page (action_widget,
+ ev_document_model_get_page (model));
+}
+
+void
+ev_page_action_widget_set_model (EvPageActionWidget *action_widget,
+ EvDocumentModel *model)
+{
+ if (action_widget->doc_model) {
+ g_object_remove_weak_pointer (G_OBJECT (action_widget->doc_model),
+ (gpointer)&action_widget->doc_model);
+ }
+ action_widget->doc_model = model;
+ g_object_add_weak_pointer (G_OBJECT (model),
+ (gpointer)&action_widget->doc_model);
+
+ g_signal_connect (model, "notify::document",
+ G_CALLBACK (ev_page_action_widget_document_changed_cb),
+ action_widget);
+}
+
+static void
+ev_page_action_widget_finalize (GObject *object)
+{
+ EvPageActionWidget *action_widget = EV_PAGE_ACTION_WIDGET (object);
+
+ if (action_widget->doc_model != NULL) {
+ if (action_widget->signal_id > 0) {
+ g_signal_handler_disconnect (action_widget->doc_model,
+ action_widget->signal_id);
+ action_widget->signal_id = 0;
+ }
+ g_object_remove_weak_pointer (G_OBJECT (action_widget->doc_model),
+ (gpointer)&action_widget->doc_model);
+ action_widget->doc_model = NULL;
+ }
+
+ if (action_widget->document) {
+ g_object_unref (action_widget->document);
+ action_widget->document = NULL;
+ }
+
+ G_OBJECT_CLASS (ev_page_action_widget_parent_class)->finalize (object);
+}
+
+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 (EvPageActionWidgetClass, 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_links_model (EvPageActionWidget *proxy, GtkTreeModel *model)
+{
+ GtkTreeModel *filter_model;
+ GtkEntryCompletion *completion;
+ GtkCellRenderer *renderer;
+
+ if (!model)
+ return;
+
+ /* Magik */
+ 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);
+}
+
+void
+ev_page_action_widget_grab_focus (EvPageActionWidget *proxy)
+{
+ gtk_widget_grab_focus (proxy->entry);
+}
+
diff --git a/src/ev-page-action-widget.h b/src/ev-page-action-widget.h
new file mode 100644
index 0000000..cf33b55
--- /dev/null
+++ b/src/ev-page-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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <evince-view.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 _EvPageActionWidgetClass
+{
+ GtkToolItemClass parent_class;
+
+ void (* activate_link) (EvPageActionWidget *page_action,
+ EvLink *link);
+};
+
+GType ev_page_action_widget_get_type (void) G_GNUC_CONST;
+
+void ev_page_action_widget_update_links_model (EvPageActionWidget *proxy,
+ GtkTreeModel *model);
+
+void ev_page_action_widget_set_model (EvPageActionWidget *action_widget,
+ EvDocumentModel *doc_model);
+void ev_page_action_widget_grab_focus (EvPageActionWidget *proxy);
diff --git a/src/ev-page-action.c b/src/ev-page-action.c
new file mode 100644
index 0000000..ff1f9fe
--- /dev/null
+++ b/src/ev-page-action.c
@@ -0,0 +1,239 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "ev-page-action.h"
+#include "ev-page-action-widget.h"
+
+struct _EvPageActionPrivate
+{
+ EvDocumentModel *doc_model;
+ GtkTreeModel *model;
+};
+
+
+static void ev_page_action_init (EvPageAction *action);
+static void ev_page_action_class_init (EvPageActionClass *class);
+
+enum
+{
+ ACTIVATE_LINK,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = {0, };
+
+G_DEFINE_TYPE (EvPageAction, ev_page_action, GTK_TYPE_ACTION)
+
+#define EV_PAGE_ACTION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_PAGE_ACTION, EvPageActionPrivate))
+
+enum {
+ PROP_0,
+ PROP_MODEL
+};
+
+static GtkWidget *
+create_tool_item (GtkAction *action)
+{
+ GtkWidget *proxy;
+
+ proxy = g_object_new (EV_TYPE_PAGE_ACTION_WIDGET, NULL);
+
+ return proxy;
+}
+
+static void
+update_model (EvPageAction *page, GParamSpec *pspec, EvPageActionWidget *proxy)
+{
+ ev_page_action_widget_update_links_model (proxy, page->priv->model);
+}
+
+static void
+activate_link_cb (EvPageActionWidget *proxy, EvLink *link, EvPageAction *action)
+{
+ g_signal_emit (action, signals[ACTIVATE_LINK], 0, link);
+}
+
+static void
+connect_proxy (GtkAction *action, GtkWidget *proxy)
+{
+ EvPageAction *page = EV_PAGE_ACTION (action);
+
+ if (GTK_IS_TOOL_ITEM (proxy)) {
+ ev_page_action_widget_set_model (EV_PAGE_ACTION_WIDGET (proxy),
+ page->priv->doc_model);
+ g_signal_connect (proxy, "activate_link",
+ G_CALLBACK (activate_link_cb),
+ action);
+ 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);
+}
+
+static void
+ev_page_action_dispose (GObject *object)
+{
+ EvPageAction *page = EV_PAGE_ACTION (object);
+
+ if (page->priv->model) {
+ g_object_unref (page->priv->model);
+ page->priv->model = NULL;
+ }
+
+ page->priv->doc_model = NULL;
+
+ G_OBJECT_CLASS (ev_page_action_parent_class)->dispose (object);
+}
+
+static void
+ev_page_action_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EvPageAction *page = EV_PAGE_ACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_MODEL:
+ ev_page_action_set_links_model (page, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ev_page_action_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EvPageAction *page = EV_PAGE_ACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_MODEL:
+ g_value_set_object (value, page->priv->model);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+void
+ev_page_action_set_model (EvPageAction *page,
+ EvDocumentModel *model)
+{
+ g_return_if_fail (EV_IS_PAGE_ACTION (page));
+ g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+ if (page->priv->doc_model == model)
+ return;
+
+ page->priv->doc_model = model;
+}
+
+void
+ev_page_action_set_links_model (EvPageAction *page,
+ GtkTreeModel *links_model)
+{
+ g_return_if_fail (EV_IS_PAGE_ACTION (page));
+ g_return_if_fail (GTK_IS_TREE_MODEL (links_model));
+
+ if (page->priv->model == links_model)
+ return;
+
+ if (page->priv->model)
+ g_object_unref (page->priv->model);
+ page->priv->model = g_object_ref (links_model);
+
+ g_object_notify (G_OBJECT (page), "model");
+}
+
+void
+ev_page_action_grab_focus (EvPageAction *page_action)
+{
+ GSList *proxies;
+
+ proxies = gtk_action_get_proxies (GTK_ACTION (page_action));
+ for (; proxies != NULL; proxies = proxies->next) {
+ EvPageActionWidget *proxy;
+
+ proxy = EV_PAGE_ACTION_WIDGET (proxies->data);
+
+ if (gtk_widget_get_mapped (GTK_WIDGET (proxy)))
+ ev_page_action_widget_grab_focus (proxy);
+ }
+}
+
+static void
+ev_page_action_init (EvPageAction *page)
+{
+ page->priv = EV_PAGE_ACTION_GET_PRIVATE (page);
+}
+
+static void
+ev_page_action_class_init (EvPageActionClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GtkActionClass *action_class = GTK_ACTION_CLASS (class);
+
+ object_class->dispose = ev_page_action_dispose;
+ object_class->set_property = ev_page_action_set_property;
+ object_class->get_property = ev_page_action_get_property;
+
+ action_class->toolbar_item_type = GTK_TYPE_TOOL_ITEM;
+ action_class->create_tool_item = create_tool_item;
+ action_class->connect_proxy = connect_proxy;
+
+ signals[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);
+
+ g_object_class_install_property (object_class,
+ PROP_MODEL,
+ g_param_spec_object ("model",
+ "Model",
+ "Current Links Model",
+ GTK_TYPE_TREE_MODEL,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (object_class, sizeof (EvPageActionPrivate));
+}
diff --git a/src/ev-page-action.h b/src/ev-page-action.h
new file mode 100644
index 0000000..b18db61
--- /dev/null
+++ b/src/ev-page-action.h
@@ -0,0 +1,68 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef EV_PAGE_ACTION_H
+#define EV_PAGE_ACTION_H
+
+#include <gtk/gtk.h>
+
+#include <evince-document.h>
+#include <evince-view.h>
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_PAGE_ACTION (ev_page_action_get_type ())
+#define EV_PAGE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_ACTION, EvPageAction))
+#define EV_PAGE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_PAGE_ACTION, EvPageActionClass))
+#define EV_IS_PAGE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PAGE_ACTION))
+#define EV_IS_PAGE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EV_TYPE_PAGE_ACTION))
+#define EV_PAGE_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EV_TYPE_PAGE_ACTION, EvPageActionClass))
+
+typedef struct _EvPageAction EvPageAction;
+typedef struct _EvPageActionPrivate EvPageActionPrivate;
+typedef struct _EvPageActionClass EvPageActionClass;
+
+struct _EvPageAction
+{
+ GtkAction parent;
+
+ /*< private >*/
+ EvPageActionPrivate *priv;
+};
+
+struct _EvPageActionClass
+{
+ GtkActionClass parent_class;
+
+ void (* activate_link) (EvPageAction *page_action,
+ EvLink *link);
+};
+
+GType ev_page_action_get_type (void) G_GNUC_CONST;
+
+void ev_page_action_set_model (EvPageAction *page_action,
+ EvDocumentModel *model);
+void ev_page_action_set_links_model (EvPageAction *page_action,
+ GtkTreeModel *links_model);
+void ev_page_action_grab_focus (EvPageAction *page_action);
+
+G_END_DECLS
+
+#endif
diff --git a/src/evbp-viewer.c b/src/evbp-viewer.c
index 4d103b6..ca94962 100644
--- a/src/evbp-viewer.c
+++ b/src/evbp-viewer.c
@@ -19,6 +19,7 @@
#include <config.h>
#include "evbp-viewer.h"
+#include "ev-page-action.h"
#include <gtk/gtk.h>
G_DEFINE_TYPE(EvbpViewer, evbp_viewer, GTK_TYPE_BOX)
@@ -139,6 +140,16 @@ continuous_handler(GObject *gobject, GParamSpec *pspec, gpointer user_data)
}
static void
+page_action_link_activated(GtkAction *action, GObject *obj, gpointer user_data)
+{
+ EvLink *link = EV_LINK(obj);
+ EvbpViewer *viewer = EVBP_VIEWER(user_data);
+
+ ev_view_handle_link(EV_VIEW(viewer->view), link);
+ gtk_widget_grab_focus(viewer->view);
+}
+
+static void
evbp_viewer_class_init(EvbpViewerClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS(class);
@@ -178,6 +189,8 @@ static const gchar ui_string[] =
" <toolitem name=\"GoPreviousPage\" action=\"GoPreviousPage\"/>\n"
" <toolitem name=\"GoNextPage\" action=\"GoNextPage\"/>\n"
" <separator/>\n"
+ " <toolitem name=\"PageSelector\" action=\"PageSelector\"/>\n"
+ " <separator/>\n"
" <toolitem name=\"ViewBestFit\" action=\"ViewBestFit\"/>\n"
" <toolitem name=\"ViewPageWidth\" action=\"ViewPageWidth\"/>\n"
" <toolitem name=\"ViewContinuous\" action=\"ViewContinuous\"/>\n"
@@ -189,10 +202,13 @@ evbp_viewer_init(EvbpViewer *viewer)
{
GError *error = NULL;
GtkWidget *toolbar;
+ GtkAction *action;
gtk_orientable_set_orientation(GTK_ORIENTABLE(viewer),
GTK_ORIENTATION_VERTICAL);
+ viewer->model = ev_document_model_new();
+
viewer->action_group = gtk_action_group_new("ViewerActions");
gtk_action_group_add_actions(viewer->action_group, action_entries,
G_N_ELEMENTS(action_entries), viewer);
@@ -200,6 +216,18 @@ evbp_viewer_init(EvbpViewer *viewer)
toggle_action_entries,
G_N_ELEMENTS(toggle_action_entries),
viewer);
+ action = g_object_new(EV_TYPE_PAGE_ACTION,
+ "name", "PageSelector",
+ "label", "Page",
+ "tooltip", "Select Page",
+ "icon-name", "text-x-generic",
+ "visible-overflown", FALSE,
+ NULL);
+ ev_page_action_set_model(EV_PAGE_ACTION(action), viewer->model);
+ g_signal_connect(action, "activate-link",
+ G_CALLBACK(page_action_link_activated), viewer);
+ gtk_action_group_add_action(viewer->action_group, action);
+ g_object_unref(action);
gtk_action_group_set_sensitive(viewer->action_group, FALSE);
viewer->ui_manager = gtk_ui_manager_new();
@@ -216,7 +244,7 @@ evbp_viewer_init(EvbpViewer *viewer)
gtk_box_pack_start(GTK_BOX(viewer), toolbar, FALSE, FALSE, 0);
gtk_widget_show(toolbar);
- viewer->model = ev_document_model_new();
+ /* wire up toolbar callbacks */
sizing_mode_handler(G_OBJECT(viewer->model), NULL, viewer);
continuous_handler(G_OBJECT(viewer->model), NULL, viewer);
g_signal_connect(viewer->model, "notify::sizing-mode",
diff --git a/test/Makefile.am b/test/Makefile.am
index 138de29..7cb9744 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -5,5 +5,8 @@ noinst_PROGRAMS = mime previewer
mime_SOURCES = mime.c $(top_srcdir)/src/evbp-mime.c
-previewer_SOURCES = previewer.c $(top_srcdir)/src/evbp-viewer.h \
- $(top_srcdir)/src/evbp-viewer.c
+previewer_SOURCES = previewer.c \
+ $(top_srcdir)/src/evbp-viewer.h $(top_srcdir)/src/evbp-viewer.c \
+ $(top_srcdir)/src/ev-page-action.h $(top_srcdir)/src/ev-page-action.c \
+ $(top_srcdir)/src/ev-page-action-widget.h \
+ $(top_srcdir)/src/ev-page-action-widget.c