]> www.fi.muni.cz Git - evince.git/blob - shell/ev-bookmarks.c
shell: Add a new sidebar page for bookmarks
[evince.git] / shell / ev-bookmarks.c
1 /* ev-bookmarks.c
2  *  this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2010 Carlos Garcia Campos  <carlosgc@gnome.org>
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #include <string.h>
24
25 #include "ev-bookmarks.h"
26
27 enum {
28         PROP_0,
29         PROP_METADATA
30 };
31
32 enum {
33         CHANGED,
34         N_SIGNALS
35 };
36
37 struct _EvBookmarks {
38         GObject base;
39
40         EvMetadata *metadata;
41         GList *items;
42 };
43
44 struct _EvBookmarksClass {
45         GObjectClass base_class;
46
47         void (*changed) (EvBookmarks *bookmarks);
48 };
49
50 G_DEFINE_TYPE (EvBookmarks, ev_bookmarks, G_TYPE_OBJECT)
51
52 static guint signals[N_SIGNALS];
53
54 static gint
55 ev_bookmark_compare (EvBookmark *a,
56                      EvBookmark *b)
57 {
58         if (a->page < b->page)
59                 return -1;
60         if (a->page > b->page)
61                 return 1;
62         return 0;
63 }
64
65 static void
66 ev_bookmark_free (EvBookmark *bm)
67 {
68         if (G_UNLIKELY(!bm))
69                 return;
70
71         g_free (bm->title);
72         g_slice_free (EvBookmark, bm);
73 }
74
75 static void
76 ev_bookmarks_finalize (GObject *object)
77 {
78         EvBookmarks *bookmarks = EV_BOOKMARKS (object);
79
80         if (bookmarks->items) {
81                 g_list_free_full (bookmarks->items, (GDestroyNotify)ev_bookmark_free);
82                 bookmarks->items = NULL;
83         }
84
85         if (bookmarks->metadata) {
86                 g_object_unref (bookmarks->metadata);
87                 bookmarks->metadata = NULL;
88         }
89
90         G_OBJECT_CLASS (ev_bookmarks_parent_class)->finalize (object);
91 }
92
93 static void
94 ev_bookmarks_init (EvBookmarks *bookmarks)
95 {
96 }
97
98 static void
99 ev_bookmarks_set_property (GObject      *object,
100                            guint         prop_id,
101                            const GValue *value,
102                            GParamSpec   *pspec)
103 {
104         EvBookmarks *bookmarks = EV_BOOKMARKS (object);
105
106         switch (prop_id) {
107         case PROP_METADATA:
108                 bookmarks->metadata = (EvMetadata *)g_value_dup_object (value);
109                 break;
110         default:
111                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
112         }
113 }
114
115 static void
116 ev_bookmarks_constructed (GObject *object)
117 {
118         EvBookmarks *bookmarks = EV_BOOKMARKS (object);
119         gchar       *bm_list_str;
120         GVariant    *bm_list;
121         GVariantIter iter;
122         GVariant    *child;
123         GError      *error = NULL;
124
125         if (!ev_metadata_get_string (bookmarks->metadata, "bookmarks", &bm_list_str))
126                 return;
127
128         if (!bm_list_str || bm_list_str[0] == '\0')
129                 return;
130
131         bm_list = g_variant_parse ((const GVariantType *)"a(us)",
132                                    bm_list_str, NULL, NULL,
133                                    &error);
134         if (!bm_list) {
135                 g_warning ("Error getting bookmarks: %s\n", error->message);
136                 g_error_free (error);
137
138                 return;
139         }
140
141         g_variant_iter_init (&iter, bm_list);
142         while ((child = g_variant_iter_next_value (&iter))) {
143                 EvBookmark *bm = g_slice_new (EvBookmark);
144
145                 g_variant_get (child, "(us)", &bm->page, &bm->title);
146                 if (bm->title && strlen (bm->title) > 0)
147                         bookmarks->items = g_list_prepend (bookmarks->items, bm);
148                 g_variant_unref (child);
149         }
150         g_variant_unref (bm_list);
151
152         bookmarks->items = g_list_reverse (bookmarks->items);
153 }
154
155 static void
156 ev_bookmarks_class_init (EvBookmarksClass *klass)
157 {
158         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
159
160         gobject_class->set_property = ev_bookmarks_set_property;
161         gobject_class->finalize = ev_bookmarks_finalize;
162         gobject_class->constructed = ev_bookmarks_constructed;
163
164         g_object_class_install_property (gobject_class,
165                                          PROP_METADATA,
166                                          g_param_spec_object ("metadata",
167                                                               "Metadata",
168                                                               "The document metadata",
169                                                               EV_TYPE_METADATA,
170                                                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
171         /* Signals */
172         signals[CHANGED] =
173                 g_signal_new ("changed",
174                               EV_TYPE_BOOKMARKS,
175                               G_SIGNAL_RUN_LAST,
176                               G_STRUCT_OFFSET (EvBookmarksClass, changed),
177                               NULL, NULL,
178                               g_cclosure_marshal_VOID__VOID,
179                               G_TYPE_NONE, 0);
180 }
181
182 EvBookmarks *
183 ev_bookmarks_new (EvMetadata *metadata)
184 {
185         g_return_val_if_fail (EV_IS_METADATA (metadata), NULL);
186
187         return EV_BOOKMARKS (g_object_new (EV_TYPE_BOOKMARKS,
188                                            "metadata", metadata, NULL));
189 }
190
191 static void
192 ev_bookmarks_save (EvBookmarks *bookmarks)
193 {
194         GList          *l;
195         GVariantBuilder builder;
196         GVariant       *bm_list;
197         gchar          *bm_list_str;
198
199         if (!bookmarks->items) {
200                 ev_metadata_set_string (bookmarks->metadata, "bookmarks", "");
201                 return;
202         }
203
204         g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
205         for (l = bookmarks->items; l; l = g_list_next (l)) {
206                 EvBookmark *bm = (EvBookmark *)l->data;
207
208                 g_variant_builder_add (&builder, "(u&s)", bm->page, bm->title);
209         }
210         bm_list = g_variant_builder_end (&builder);
211
212         bm_list_str = g_variant_print (bm_list, FALSE);
213         g_variant_unref (bm_list);
214         ev_metadata_set_string (bookmarks->metadata, "bookmarks", bm_list_str);
215         g_free (bm_list_str);
216 }
217
218 GList *
219 ev_bookmarks_get_bookmarks (EvBookmarks *bookmarks)
220 {
221         g_return_val_if_fail (EV_IS_BOOKMARKS (bookmarks), NULL);
222
223         return g_list_copy (bookmarks->items);
224 }
225
226 void
227 ev_bookmarks_add (EvBookmarks *bookmarks,
228                   EvBookmark  *bookmark)
229 {
230         EvBookmark *bm;
231
232         g_return_if_fail (EV_IS_BOOKMARKS (bookmarks));
233         g_return_if_fail (bookmark->title != NULL);
234
235         if (g_list_find_custom (bookmarks->items, bookmark, (GCompareFunc)ev_bookmark_compare))
236                 return;
237
238         bm = g_slice_new (EvBookmark);
239         *bm = *bookmark;
240         bookmarks->items = g_list_append (bookmarks->items, bm);
241         g_signal_emit (bookmarks, signals[CHANGED], 0);
242         ev_bookmarks_save (bookmarks);
243 }
244
245 void
246 ev_bookmarks_delete (EvBookmarks *bookmarks,
247                      EvBookmark  *bookmark)
248 {
249         GList *bm_link;
250
251         g_return_if_fail (EV_IS_BOOKMARKS (bookmarks));
252
253         bm_link = g_list_find_custom (bookmarks->items, bookmark, (GCompareFunc)ev_bookmark_compare);
254         if (!bm_link)
255                 return;
256
257         bookmarks->items = g_list_delete_link (bookmarks->items, bm_link);
258         g_signal_emit (bookmarks, signals[CHANGED], 0);
259         ev_bookmarks_save (bookmarks);
260 }
261
262 void
263 ev_bookmarks_update (EvBookmarks *bookmarks,
264                      EvBookmark  *bookmark)
265 {
266         GList      *bm_link;
267         EvBookmark *bm;
268
269         g_return_if_fail (EV_IS_BOOKMARKS (bookmarks));
270         g_return_if_fail (bookmark->title != NULL);
271
272         bm_link = g_list_find_custom (bookmarks->items, bookmark, (GCompareFunc)ev_bookmark_compare);
273         if (!bm_link)
274                 return;
275
276         bm = (EvBookmark *)bm_link->data;
277
278         if (strcmp (bookmark->title, bm->title) == 0)
279                 return;
280
281         g_free (bm->title);
282         *bm = *bookmark;
283         g_signal_emit (bookmarks, signals[CHANGED], 0);
284         ev_bookmarks_save (bookmarks);
285 }