From: Carlos Garcia Campos Date: Mon, 6 Dec 2010 16:40:48 +0000 (+0100) Subject: shell: Add bookmarks menu to add and show internal bookmarks X-Git-Tag: EVINCE_2_91_4~46 X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=commitdiff_plain;h=f7eb83a4ad43b1b30af202eb8f33f3057c2a51c5;p=evince.git shell: Add bookmarks menu to add and show internal bookmarks Fixes bug #590655. --- diff --git a/data/evince-ui.xml b/data/evince-ui.xml index 80675466..3aca084f 100644 --- a/data/evince-ui.xml +++ b/data/evince-ui.xml @@ -60,6 +60,12 @@ + + + + + + diff --git a/shell/Makefile.am b/shell/Makefile.am index 7a303264..d760955d 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -35,6 +35,8 @@ evince_SOURCES= \ ev-annotation-properties-dialog.c \ ev-bookmarks.h \ ev-bookmarks.c \ + ev-bookmark-action.h \ + ev-bookmark-action.c \ ev-application.c \ ev-application.h \ ev-file-monitor.h \ diff --git a/shell/ev-bookmark-action.c b/shell/ev-bookmark-action.c new file mode 100644 index 00000000..3689d7aa --- /dev/null +++ b/shell/ev-bookmark-action.c @@ -0,0 +1,105 @@ +/* ev-bookmark-action.c + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2010 Carlos Garcia Campos + * + * Evince 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 of the License, or + * (at your option) any later version. + * + * Evince 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 "ev-bookmark-action.h" + +enum { + PROP_0, + PROP_PAGE +}; + +struct _EvBookmarkAction { + GtkAction base; + + guint page; +}; + +struct _EvBookmarkActionClass { + GtkActionClass base_class; +}; + +G_DEFINE_TYPE (EvBookmarkAction, ev_bookmark_action, GTK_TYPE_ACTION) + +static void +ev_bookmark_action_init (EvBookmarkAction *action) +{ +} + +static void +ev_bookmark_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EvBookmarkAction *action = EV_BOOKMARK_ACTION (object); + + switch (prop_id) { + case PROP_PAGE: + action->page = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +ev_bookmark_action_class_init (EvBookmarkActionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = ev_bookmark_action_set_property; + + g_object_class_install_property (gobject_class, + PROP_PAGE, + g_param_spec_uint ("page", + "Page", + "The bookmark page", + 0, G_MAXUINT, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE)); +} + +GtkAction * +ev_bookmark_action_new (EvBookmark *bookmark) +{ + GtkAction *action; + gchar *name; + + g_return_val_if_fail (bookmark->title != NULL, NULL); + + name = g_strdup_printf ("EvBookmark%u", bookmark->page); + action = GTK_ACTION (g_object_new (EV_TYPE_BOOKMARK_ACTION, + "name", name, + "label", bookmark->title, + "page", bookmark->page, + NULL)); + g_free (name); + + return action; +} + +guint +ev_bookmark_action_get_page (EvBookmarkAction *action) +{ + g_return_val_if_fail (EV_IS_BOOKMARK_ACTION (action), 0); + + return action->page; +} diff --git a/shell/ev-bookmark-action.h b/shell/ev-bookmark-action.h new file mode 100644 index 00000000..8a36cdc5 --- /dev/null +++ b/shell/ev-bookmark-action.h @@ -0,0 +1,45 @@ +/* ev-bookmark-action.h + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2010 Carlos Garcia Campos + * + * Evince 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 of the License, or + * (at your option) any later version. + * + * Evince 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_BOOKMARK_ACTION_H +#define EV_BOOKMARK_ACTION_H + +#include +#include + +#include "ev-bookmarks.h" + +G_BEGIN_DECLS + +#define EV_TYPE_BOOKMARK_ACTION (ev_bookmark_action_get_type()) +#define EV_BOOKMARK_ACTION(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_BOOKMARK_ACTION, EvBookmarkAction)) +#define EV_BOOKMARK_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_BOOKMARK_ACTION, EvBookmarkActionClass)) +#define EV_IS_BOOKMARK_ACTION(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_BOOKMARK_ACTION)) + +typedef struct _EvBookmarkAction EvBookmarkAction; +typedef struct _EvBookmarkActionClass EvBookmarkActionClass; + +GType ev_bookmark_action_get_type (void) G_GNUC_CONST; +GtkAction *ev_bookmark_action_new (EvBookmark *bookmark); +guint ev_bookmark_action_get_page (EvBookmarkAction *action); + +G_END_DECLS + +#endif /* EV_BOOKMARK_ACTION_H */ diff --git a/shell/ev-window.c b/shell/ev-window.c index e5acd408..4fe71833 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -91,6 +91,8 @@ #include "ev-print-operation.h" #include "ev-progress-message-area.h" #include "ev-annotation-properties-dialog.h" +#include "ev-bookmarks.h" +#include "ev-bookmark-action.h" #ifdef ENABLE_DBUS #include "ev-media-player-keys.h" @@ -163,6 +165,8 @@ struct _EvWindowPrivate { GtkRecentManager *recent_manager; GtkActionGroup *recent_action_group; guint recent_ui_id; + GtkActionGroup *bookmarks_action_group; + guint bookmarks_ui_id; GtkUIManager *ui_manager; /* Fullscreen mode */ @@ -192,6 +196,7 @@ struct _EvWindowPrivate { EvWindowPageMode page_mode; EvWindowTitle *title; EvMetadata *metadata; + EvBookmarks *bookmarks; gboolean is_new_doc; /* Load params */ @@ -345,6 +350,7 @@ static void ev_window_update_max_min_scale (EvWindow *windo static void ev_window_emit_closed (EvWindow *window); static void ev_window_emit_doc_loaded (EvWindow *window); #endif +static void ev_window_setup_bookmarks (EvWindow *window); static guint ev_window_n_copies = 0; @@ -448,6 +454,10 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) ev_window_set_action_sensitive (ev_window, "ViewAutoscroll", has_pages); ev_window_set_action_sensitive (ev_window, "ViewInvertedColors", has_pages); + /* Bookmarks menu */ + ev_window_set_action_sensitive (ev_window, "BookmarksAdd", + has_pages && ev_window->priv->bookmarks); + /* 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); @@ -784,18 +794,17 @@ ev_window_warning_message (EvWindow *window, ev_window_set_message_area (window, area); } -typedef struct _FindTask { +typedef struct _PageTitleData { const gchar *page_label; - gchar *chapter; -} FindTask; + gchar *page_title; +} PageTitleData; static gboolean -ev_window_find_chapter (GtkTreeModel *tree_model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data) +ev_window_find_page_title (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + PageTitleData *data) { - FindTask *task = (FindTask *)data; gchar *page_string; gtk_tree_model_get (tree_model, iter, @@ -805,9 +814,9 @@ ev_window_find_chapter (GtkTreeModel *tree_model, if (!page_string) return FALSE; - if (!strcmp (page_string, task->page_label)) { + if (!strcmp (page_string, data->page_label)) { gtk_tree_model_get (tree_model, iter, - EV_DOCUMENT_LINKS_COLUMN_MARKUP, &task->chapter, + EV_DOCUMENT_LINKS_COLUMN_MARKUP, &data->page_title, -1); g_free (page_string); return TRUE; @@ -817,12 +826,41 @@ ev_window_find_chapter (GtkTreeModel *tree_model, return FALSE; } +static gchar * +ev_window_get_page_title (EvWindow *window, + const gchar *page_label) +{ + if (EV_IS_DOCUMENT_LINKS (window->priv->document) && + ev_document_links_has_document_links (EV_DOCUMENT_LINKS (window->priv->document))) { + PageTitleData data; + GtkTreeModel *model; + + data.page_label = page_label; + data.page_title = NULL; + + g_object_get (G_OBJECT (window->priv->sidebar_links), + "model", &model, + NULL); + if (model) { + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc)ev_window_find_page_title, + &data); + + g_object_unref (model); + } + + return data.page_title; + } + + return NULL; +} + static void ev_window_add_history (EvWindow *window, gint page, EvLink *link) { gchar *page_label = NULL; + gchar *page_title; gchar *link_title; - FindTask find_task; EvLink *real_link; EvLinkAction *action; EvLinkDest *dest; @@ -845,34 +883,19 @@ ev_window_add_history (EvWindow *window, gint page, EvLink *link) if (!page_label) return; - - find_task.page_label = page_label; - find_task.chapter = NULL; - - if (ev_document_links_has_document_links (EV_DOCUMENT_LINKS (window->priv->document))) { - GtkTreeModel *model; - - g_object_get (G_OBJECT (window->priv->sidebar_links), "model", &model, NULL); - - if (model) { - gtk_tree_model_foreach (model, - ev_window_find_chapter, - &find_task); - - g_object_unref (model); - } - } - if (find_task.chapter) - link_title = g_strdup_printf (_("Page %s — %s"), page_label, find_task.chapter); - else + page_title = ev_window_get_page_title (window, page_label); + if (page_title) { + link_title = g_strdup_printf (_("Page %s — %s"), page_label, page_title); + g_free (page_title); + } else { link_title = g_strdup_printf (_("Page %s"), page_label); - + } + real_link = ev_link_new (link_title, action); ev_history_add_link (window->priv->history, real_link); - g_free (find_task.chapter); g_free (link_title); g_free (page_label); g_object_unref (real_link); @@ -2008,6 +2031,8 @@ ev_window_open_uri (EvWindow *ev_window, if (ev_window->priv->metadata) g_object_unref (ev_window->priv->metadata); + if (ev_window->priv->bookmarks) + g_object_unref (ev_window->priv->bookmarks); source_file = g_file_new_for_uri (uri); if (!ev_file_is_temp (source_file) && ev_is_metadata_supported_for_file (source_file)) { @@ -2017,6 +2042,15 @@ ev_window_open_uri (EvWindow *ev_window, ev_window->priv->metadata = NULL; } + if (ev_window->priv->metadata) { + ev_window->priv->bookmarks = ev_bookmarks_new (ev_window->priv->metadata); + g_signal_connect_swapped (ev_window->priv->bookmarks, "changed", + G_CALLBACK (ev_window_setup_bookmarks), + ev_window); + } else { + ev_window->priv->bookmarks = NULL; + } + if (ev_window->priv->search_string) g_free (ev_window->priv->search_string); ev_window->priv->search_string = search_string ? @@ -2028,6 +2062,7 @@ ev_window_open_uri (EvWindow *ev_window, setup_size_from_metadata (ev_window); setup_model_from_metadata (ev_window); + ev_window_setup_bookmarks (ev_window); ev_window->priv->load_job = ev_job_load_new (uri); g_signal_connect (ev_window->priv->load_job, @@ -4338,6 +4373,92 @@ ev_window_cmd_go_backward (GtkAction *action, EvWindow *ev_window) } } +static void +ev_window_cmd_bookmark_activate (GtkAction *action, + EvWindow *window) +{ + guint page = ev_bookmark_action_get_page (EV_BOOKMARK_ACTION (action)); + + ev_document_model_set_page (window->priv->model, page); +} + +static gint +compare_bookmarks (EvBookmark *a, + EvBookmark *b) +{ + return strcmp (a->title, b->title); +} + +static void +ev_window_setup_bookmarks (EvWindow *window) +{ + GList *items, *l; + + if (!window->priv->bookmarks) + return; + + if (window->priv->bookmarks_ui_id > 0) { + gtk_ui_manager_remove_ui (window->priv->ui_manager, + window->priv->bookmarks_ui_id); + gtk_ui_manager_ensure_update (window->priv->ui_manager); + } + window->priv->bookmarks_ui_id = gtk_ui_manager_new_merge_id (window->priv->ui_manager); + + if (window->priv->bookmarks_action_group) { + gtk_ui_manager_remove_action_group (window->priv->ui_manager, + window->priv->bookmarks_action_group); + g_object_unref (window->priv->bookmarks_action_group); + } + window->priv->bookmarks_action_group = gtk_action_group_new ("BookmarksActions"); + gtk_ui_manager_insert_action_group (window->priv->ui_manager, + window->priv->bookmarks_action_group, -1); + + items = ev_bookmarks_get_bookmarks (window->priv->bookmarks); + items = g_list_sort (items, (GCompareFunc)compare_bookmarks); + + for (l = items; l && l->data; l = g_list_next (l)) { + EvBookmark *bm = (EvBookmark *)l->data; + GtkAction *action; + + action = ev_bookmark_action_new (bm); + g_signal_connect (action, "activate", + G_CALLBACK (ev_window_cmd_bookmark_activate), + window); + gtk_action_group_add_action (window->priv->bookmarks_action_group, + action); + + gtk_ui_manager_add_ui (window->priv->ui_manager, + window->priv->bookmarks_ui_id, + "/MainMenu/BookmarksMenu/BookmarksItems", + gtk_action_get_label (action), + gtk_action_get_name (action), + GTK_UI_MANAGER_MENUITEM, + FALSE); + + g_object_unref (action); + } + + g_list_free (items); +} + +static void +ev_window_cmd_bookmarks_add (GtkAction *action, + EvWindow *window) +{ + EvBookmark bm; + gchar *page_label; + gchar *page_title; + + bm.page = ev_document_model_get_page (window->priv->model); + page_label = ev_document_get_page_label (window->priv->document, bm.page); + page_title = ev_window_get_page_title (window, page_label); + bm.title = page_title ? page_title : g_strdup_printf (_("Page %s"), page_label); + g_free (page_label); + + /* EvBookmarks takes ownership of bookmark */ + ev_bookmarks_add (window->priv->bookmarks, &bm); +} + static void ev_window_cmd_view_reload (GtkAction *action, EvWindow *ev_window) { @@ -5172,6 +5293,11 @@ ev_window_dispose (GObject *object) } #endif /* ENABLE_DBUS */ + if (priv->bookmarks) { + g_object_unref (priv->bookmarks); + priv->bookmarks = NULL; + } + if (priv->metadata) { g_object_unref (priv->metadata); priv->metadata = NULL; @@ -5217,6 +5343,11 @@ ev_window_dispose (GObject *object) priv->recent_action_group = NULL; } + if (priv->bookmarks_action_group) { + g_object_unref (priv->bookmarks_action_group); + priv->bookmarks_action_group = NULL; + } + if (priv->recent_manager) { g_signal_handlers_disconnect_by_func (priv->recent_manager, ev_window_setup_recent, @@ -5446,6 +5577,7 @@ static const GtkActionEntry entries[] = { { "Edit", NULL, N_("_Edit") }, { "View", NULL, N_("_View") }, { "Go", NULL, N_("_Go") }, + { "Bookmarks", NULL, N_("_Bookmarks") }, { "Help", NULL, N_("_Help") }, /* File menu */ @@ -5519,6 +5651,11 @@ static const GtkActionEntry entries[] = { N_("Go to the last page"), G_CALLBACK (ev_window_cmd_go_last_page) }, + /* Bookmarks menu */ + { "BookmarksAdd", GTK_STOCK_ADD, N_("_Add Bookmark"), "D", + N_("Add a bookmark for the current page"), + G_CALLBACK (ev_window_cmd_bookmarks_add) }, + /* Help menu */ { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1", NULL, G_CALLBACK (ev_window_cmd_help_contents) },