From 7f0f254c6655bc301102eaaebabc1d98dade9912 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Mon, 6 Dec 2010 17:31:47 +0100 Subject: [PATCH] shell: Add EvBookmarks to handle internal document bookmarks Bookmarks are stored in the document metadata using GVariant. --- shell/Makefile.am | 2 + shell/ev-bookmarks.c | 285 +++++++++++++++++++++++++++++++++++++++++++ shell/ev-bookmarks.h | 57 +++++++++ shell/ev-metadata.h | 1 + 4 files changed, 345 insertions(+) create mode 100644 shell/ev-bookmarks.c create mode 100644 shell/ev-bookmarks.h diff --git a/shell/Makefile.am b/shell/Makefile.am index 7e3cf8c9..7a303264 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -33,6 +33,8 @@ evince_SOURCES= \ eggfindbar.h \ ev-annotation-properties-dialog.h \ ev-annotation-properties-dialog.c \ + ev-bookmarks.h \ + ev-bookmarks.c \ ev-application.c \ ev-application.h \ ev-file-monitor.h \ diff --git a/shell/ev-bookmarks.c b/shell/ev-bookmarks.c new file mode 100644 index 00000000..5072fcbe --- /dev/null +++ b/shell/ev-bookmarks.c @@ -0,0 +1,285 @@ +/* ev-bookmarks.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 + +#include "ev-bookmarks.h" + +enum { + PROP_0, + PROP_METADATA +}; + +enum { + CHANGED, + N_SIGNALS +}; + +struct _EvBookmarks { + GObject base; + + EvMetadata *metadata; + GList *items; +}; + +struct _EvBookmarksClass { + GObjectClass base_class; + + void (*changed) (EvBookmarks *bookmarks); +}; + +G_DEFINE_TYPE (EvBookmarks, ev_bookmarks, G_TYPE_OBJECT) + +static guint signals[N_SIGNALS]; + +static gint +ev_bookmark_compare (EvBookmark *a, + EvBookmark *b) +{ + if (a->page < b->page) + return -1; + if (a->page > b->page) + return 1; + return 0; +} + +static void +ev_bookmark_free (EvBookmark *bm) +{ + if (G_UNLIKELY(!bm)) + return; + + g_free (bm->title); + g_slice_free (EvBookmark, bm); +} + +static void +ev_bookmarks_finalize (GObject *object) +{ + EvBookmarks *bookmarks = EV_BOOKMARKS (object); + + if (bookmarks->items) { + g_list_free_full (bookmarks->items, (GDestroyNotify)ev_bookmark_free); + bookmarks->items = NULL; + } + + if (bookmarks->metadata) { + g_object_unref (bookmarks->metadata); + bookmarks->metadata = NULL; + } + + G_OBJECT_CLASS (ev_bookmarks_parent_class)->finalize (object); +} + +static void +ev_bookmarks_init (EvBookmarks *bookmarks) +{ +} + +static void +ev_bookmarks_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EvBookmarks *bookmarks = EV_BOOKMARKS (object); + + switch (prop_id) { + case PROP_METADATA: + bookmarks->metadata = (EvMetadata *)g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +ev_bookmarks_constructed (GObject *object) +{ + EvBookmarks *bookmarks = EV_BOOKMARKS (object); + gchar *bm_list_str; + GVariant *bm_list; + GVariantIter iter; + GVariant *child; + GError *error = NULL; + + if (!ev_metadata_get_string (bookmarks->metadata, "bookmarks", &bm_list_str)) + return; + + if (!bm_list_str || bm_list_str[0] == '\0') + return; + + bm_list = g_variant_parse ((const GVariantType *)"a(us)", + bm_list_str, NULL, NULL, + &error); + if (!bm_list) { + g_warning ("Error getting bookmarks: %s\n", error->message); + g_error_free (error); + + return; + } + + g_variant_iter_init (&iter, bm_list); + while ((child = g_variant_iter_next_value (&iter))) { + EvBookmark *bm = g_slice_new (EvBookmark); + + g_variant_get (child, "(us)", &bm->page, &bm->title); + if (bm->title && strlen (bm->title) > 0) + bookmarks->items = g_list_prepend (bookmarks->items, bm); + g_variant_unref (child); + } + g_variant_unref (bm_list); + + bookmarks->items = g_list_reverse (bookmarks->items); +} + +static void +ev_bookmarks_class_init (EvBookmarksClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = ev_bookmarks_set_property; + gobject_class->finalize = ev_bookmarks_finalize; + gobject_class->constructed = ev_bookmarks_constructed; + + g_object_class_install_property (gobject_class, + PROP_METADATA, + g_param_spec_object ("metadata", + "Metadata", + "The document metadata", + EV_TYPE_METADATA, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE)); + /* Signals */ + signals[CHANGED] = + g_signal_new ("changed", + EV_TYPE_BOOKMARKS, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EvBookmarksClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +EvBookmarks * +ev_bookmarks_new (EvMetadata *metadata) +{ + g_return_val_if_fail (EV_IS_METADATA (metadata), NULL); + + return EV_BOOKMARKS (g_object_new (EV_TYPE_BOOKMARKS, + "metadata", metadata, NULL)); +} + +static void +ev_bookmarks_save (EvBookmarks *bookmarks) +{ + GList *l; + GVariantBuilder builder; + GVariant *bm_list; + gchar *bm_list_str; + + if (!bookmarks->items) { + ev_metadata_set_string (bookmarks->metadata, "bookmarks", ""); + return; + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + for (l = bookmarks->items; l; l = g_list_next (l)) { + EvBookmark *bm = (EvBookmark *)l->data; + + g_variant_builder_add (&builder, "(u&s)", bm->page, bm->title); + } + bm_list = g_variant_builder_end (&builder); + + bm_list_str = g_variant_print (bm_list, FALSE); + g_variant_unref (bm_list); + ev_metadata_set_string (bookmarks->metadata, "bookmarks", bm_list_str); + g_free (bm_list_str); +} + +GList * +ev_bookmarks_get_bookmarks (EvBookmarks *bookmarks) +{ + g_return_val_if_fail (EV_IS_BOOKMARKS (bookmarks), NULL); + + return g_list_copy (bookmarks->items); +} + +void +ev_bookmarks_add (EvBookmarks *bookmarks, + EvBookmark *bookmark) +{ + EvBookmark *bm; + + g_return_if_fail (EV_IS_BOOKMARKS (bookmarks)); + g_return_if_fail (bookmark->title != NULL); + + if (g_list_find_custom (bookmarks->items, bookmark, (GCompareFunc)ev_bookmark_compare)) + return; + + bm = g_slice_new (EvBookmark); + *bm = *bookmark; + bookmarks->items = g_list_append (bookmarks->items, bm); + g_signal_emit (bookmarks, signals[CHANGED], 0); + ev_bookmarks_save (bookmarks); +} + +void +ev_bookmarks_delete (EvBookmarks *bookmarks, + EvBookmark *bookmark) +{ + GList *bm_link; + + g_return_if_fail (EV_IS_BOOKMARKS (bookmarks)); + + bm_link = g_list_find_custom (bookmarks->items, bookmark, (GCompareFunc)ev_bookmark_compare); + if (!bm_link) + return; + + bookmarks->items = g_list_delete_link (bookmarks->items, bm_link); + g_signal_emit (bookmarks, signals[CHANGED], 0); + ev_bookmarks_save (bookmarks); +} + +void +ev_bookmarks_update (EvBookmarks *bookmarks, + EvBookmark *bookmark) +{ + GList *bm_link; + EvBookmark *bm; + + g_return_if_fail (EV_IS_BOOKMARKS (bookmarks)); + g_return_if_fail (bookmark->title != NULL); + + bm_link = g_list_find_custom (bookmarks->items, bookmark, (GCompareFunc)ev_bookmark_compare); + if (!bm_link) + return; + + bm = (EvBookmark *)bm_link->data; + + if (strcmp (bookmark->title, bm->title) == 0) + return; + + g_free (bm->title); + *bm = *bookmark; + g_signal_emit (bookmarks, signals[CHANGED], 0); + ev_bookmarks_save (bookmarks); +} diff --git a/shell/ev-bookmarks.h b/shell/ev-bookmarks.h new file mode 100644 index 00000000..d15ebad9 --- /dev/null +++ b/shell/ev-bookmarks.h @@ -0,0 +1,57 @@ +/* ev-bookmarks.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_BOOKMARKS_H +#define EV_BOOKMARKS_H + +#include + +#include "ev-metadata.h" + +G_BEGIN_DECLS + +#define EV_TYPE_BOOKMARKS (ev_bookmarks_get_type()) +#define EV_BOOKMARKS(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_BOOKMARKS, EvBookmarks)) +#define EV_BOOKMARKS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_BOOKMARKS, EvBookmarksClass)) +#define EV_IS_BOOKMARKS(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_BOOKMARKS)) + +typedef struct _EvBookmarks EvBookmarks; +typedef struct _EvBookmarksClass EvBookmarksClass; + +typedef struct _EvBookmark { + guint page; + gchar *title; +} EvBookmark; + +GType ev_bookmarks_get_type (void) G_GNUC_CONST; +EvBookmarks *ev_bookmarks_new (EvMetadata *metadata); +GList *ev_bookmarks_get_bookmarks (EvBookmarks *bookmarks); +void ev_bookmarks_add (EvBookmarks *bookmarks, + EvBookmark *bookmark); +void ev_bookmarks_delete (EvBookmarks *bookmarks, + EvBookmark *bookmark); +void ev_bookmarks_update (EvBookmarks *bookmarks, + EvBookmark *bookmark); + + + +G_END_DECLS + +#endif /* EV_BOOKMARKS_H */ diff --git a/shell/ev-metadata.h b/shell/ev-metadata.h index f5ce67d2..8daf61cb 100644 --- a/shell/ev-metadata.h +++ b/shell/ev-metadata.h @@ -22,6 +22,7 @@ #define EV_METADATA_H #include +#include G_BEGIN_DECLS -- 2.43.5