]> www.fi.muni.cz Git - evince.git/blob - shell/ev-sidebar-annotations.c
67a49f1f2f38dc0dc90438fcae763f3633077ba0
[evince.git] / shell / ev-sidebar-annotations.c
1 /* ev-sidebar-annotations.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22
23 #include <glib/gi18n.h>
24
25 #include "ev-document-annotations.h"
26 #include "ev-sidebar-page.h"
27 #include "ev-sidebar-annotations.h"
28 #include "ev-jobs.h"
29 #include "ev-job-scheduler.h"
30 #include "ev-stock-icons.h"
31
32 enum {
33         PROP_0,
34         PROP_WIDGET
35 };
36
37 enum {
38         COLUMN_MARKUP,
39         COLUMN_ICON,
40         COLUMN_ANNOT_MAPPING,
41         N_COLUMNS
42 };
43
44 struct _EvSidebarAnnotationsPrivate {
45         GtkWidget  *notebook;
46         GtkWidget  *tree_view;
47
48         EvJob      *job;
49 };
50
51 static void ev_sidebar_annotations_page_iface_init (EvSidebarPageInterface *iface);
52
53 G_DEFINE_TYPE_EXTENDED (EvSidebarAnnotations,
54                         ev_sidebar_annotations,
55                         GTK_TYPE_VBOX,
56                         0,
57                         G_IMPLEMENT_INTERFACE (EV_TYPE_SIDEBAR_PAGE,
58                                                ev_sidebar_annotations_page_iface_init))
59
60 #define EV_SIDEBAR_ANNOTATIONS_GET_PRIVATE(object) \
61         (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_ANNOTATIONS, EvSidebarAnnotationsPrivate))
62
63 static GtkTreeModel *
64 ev_sidebar_annotations_create_simple_model (const gchar *message)
65 {
66         GtkTreeModel *retval;
67         GtkTreeIter iter;
68         gchar *markup;
69
70         /* Creates a fake model to indicate that we're loading */
71         retval = (GtkTreeModel *)gtk_list_store_new (N_COLUMNS,
72                                                      G_TYPE_STRING,
73                                                      GDK_TYPE_PIXBUF,
74                                                      G_TYPE_POINTER);
75
76         gtk_list_store_append (GTK_LIST_STORE (retval), &iter);
77         markup = g_strdup_printf ("<span size=\"larger\" style=\"italic\">%s</span>",
78                                   message);
79         gtk_list_store_set (GTK_LIST_STORE (retval), &iter,
80                             COLUMN_MARKUP, markup,
81                             -1);
82         g_free (markup);
83
84         return retval;
85 }
86
87 static void
88 ev_sidebar_annotations_add_annots_list (EvSidebarAnnotations *ev_annots)
89 {
90         GtkWidget         *swindow;
91         GtkTreeModel      *loading_model;
92         GtkCellRenderer   *renderer;
93         GtkTreeViewColumn *column;
94
95         swindow = gtk_scrolled_window_new (NULL, NULL);
96         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
97                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
98         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
99                                              GTK_SHADOW_IN);
100
101         /* Create tree view */
102         loading_model = ev_sidebar_annotations_create_simple_model (_("Loading…"));
103         ev_annots->priv->tree_view = gtk_tree_view_new_with_model (loading_model);
104         g_object_unref (loading_model);
105
106         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ev_annots->priv->tree_view),
107                                            FALSE);
108
109         column = gtk_tree_view_column_new ();
110
111         renderer = gtk_cell_renderer_pixbuf_new ();
112         gtk_tree_view_column_pack_start (column, renderer, FALSE);
113         gtk_tree_view_column_set_attributes (column, renderer,
114                                              "pixbuf", COLUMN_ICON,
115                                              NULL);
116
117         renderer = gtk_cell_renderer_text_new ();
118         gtk_tree_view_column_pack_start (column, renderer, TRUE);
119         gtk_tree_view_column_set_attributes (column, renderer,
120                                              "markup", COLUMN_MARKUP,
121                                              NULL);
122         gtk_tree_view_append_column (GTK_TREE_VIEW (ev_annots->priv->tree_view),
123                                      column);
124
125         gtk_container_add (GTK_CONTAINER (swindow), ev_annots->priv->tree_view);
126         gtk_widget_show (ev_annots->priv->tree_view);
127
128         gtk_notebook_append_page (GTK_NOTEBOOK (ev_annots->priv->notebook),
129                                   swindow, NULL);
130         gtk_widget_show (swindow);
131 }
132
133 static void
134 ev_sidebar_annotations_init (EvSidebarAnnotations *ev_annots)
135 {
136         ev_annots->priv = EV_SIDEBAR_ANNOTATIONS_GET_PRIVATE (ev_annots);
137
138         ev_annots->priv->notebook = gtk_notebook_new ();
139         gtk_notebook_set_show_tabs (GTK_NOTEBOOK (ev_annots->priv->notebook), FALSE);
140         gtk_notebook_set_show_border (GTK_NOTEBOOK (ev_annots->priv->notebook), FALSE);
141         ev_sidebar_annotations_add_annots_list (ev_annots);
142         gtk_container_add (GTK_CONTAINER (ev_annots), ev_annots->priv->notebook);
143         gtk_widget_show (ev_annots->priv->notebook);
144 }
145
146 static void
147 ev_sidebar_annotations_get_property (GObject    *object,
148                                      guint       prop_id,
149                                      GValue     *value,
150                                      GParamSpec *pspec)
151 {
152         EvSidebarAnnotations *ev_sidebar_annots;
153
154         ev_sidebar_annots = EV_SIDEBAR_ANNOTATIONS (object);
155
156         switch (prop_id) {
157                 case PROP_WIDGET:
158                         g_value_set_object (value, ev_sidebar_annots->priv->notebook);
159                         break;
160                 default:
161                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
162                         break;
163         }
164 }
165
166 static void
167 ev_sidebar_annotations_class_init (EvSidebarAnnotationsClass *klass)
168 {
169         GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
170
171         g_object_class->get_property = ev_sidebar_annotations_get_property;
172
173         g_type_class_add_private (g_object_class, sizeof (EvSidebarAnnotationsPrivate));
174
175         g_object_class_override_property (g_object_class, PROP_WIDGET, "main-widget");
176 }
177
178 GtkWidget *
179 ev_sidebar_annotations_new (void)
180 {
181         return GTK_WIDGET (g_object_new (EV_TYPE_SIDEBAR_ANNOTATIONS, NULL));
182 }
183
184 static void
185 job_finished_callback (EvJobAnnots          *job,
186                        EvSidebarAnnotations *sidebar_annots)
187 {
188         EvSidebarAnnotationsPrivate *priv;
189         GtkTreeStore *model;
190         GList *l;
191         GdkPixbuf *text_icon = NULL;
192         GdkPixbuf *attachment_icon = NULL;
193
194         priv = sidebar_annots->priv;
195
196         if (!job->annots) {
197                 GtkTreeModel *list;
198
199                 list = ev_sidebar_annotations_create_simple_model (_("Document contains no annotations"));
200                 gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), list);
201                 g_object_unref (list);
202
203                 g_object_unref (job);
204                 priv->job = NULL;
205
206                 return;
207         }
208
209         model = gtk_tree_store_new (N_COLUMNS,
210                                     G_TYPE_STRING,
211                                     GDK_TYPE_PIXBUF,
212                                     G_TYPE_POINTER);
213
214         for (l = job->annots; l; l = g_list_next (l)) {
215                 EvMappingList *mapping_list;
216                 GList         *ll;
217                 gchar         *page_label;
218                 GtkTreeIter    iter;
219                 gboolean       found = FALSE;
220
221                 mapping_list = (EvMappingList *)l->data;
222                 page_label = g_strdup_printf (_("Page %d"),
223                                               ev_mapping_list_get_page (mapping_list) + 1);
224                 gtk_tree_store_append (model, &iter, NULL);
225                 gtk_tree_store_set (model, &iter,
226                                     COLUMN_MARKUP, page_label,
227                                     -1);
228                 g_free (page_label);
229
230                 for (ll = ev_mapping_list_get_list (mapping_list); ll; ll = g_list_next (ll)) {
231                         EvAnnotation *annot;
232                         gchar        *label;
233                         gchar        *markup;
234                         GtkTreeIter   child_iter;
235                         GdkPixbuf    *pixbuf = NULL;
236
237                         annot = ((EvMapping *)(ll->data))->data;
238                         if (!EV_IS_ANNOTATION_MARKUP (annot))
239                                 continue;
240
241                         label = ev_annotation_markup_get_label (EV_ANNOTATION_MARKUP (annot));
242                         if (annot->modified) {
243                                 markup = g_strdup_printf ("<span weight=\"bold\">%s</span>\n%s",
244                                                           label, annot->modified);
245                         } else {
246                                 markup = g_strdup_printf ("<span weight=\"bold\">%s</span>", label);
247                         }
248                         g_free (label);
249
250                         if (EV_IS_ANNOTATION_TEXT (annot)) {
251                                 if (!text_icon) {
252                                         /* FIXME: use a better icon than EDIT */
253                                         text_icon = gtk_widget_render_icon (priv->tree_view,
254                                                                             GTK_STOCK_EDIT,
255                                                                             GTK_ICON_SIZE_BUTTON,
256                                                                             NULL);
257                                 }
258                                 pixbuf = text_icon;
259                         } else if (EV_IS_ANNOTATION_ATTACHMENT (annot)) {
260                                 if (!attachment_icon) {
261                                         attachment_icon = gtk_widget_render_icon (priv->tree_view,
262                                                                                   EV_STOCK_ATTACHMENT,
263                                                                                   GTK_ICON_SIZE_BUTTON,
264                                                                                   NULL);
265                                 }
266                                 pixbuf = attachment_icon;
267                         }
268
269                         gtk_tree_store_append (model, &child_iter, &iter);
270                         gtk_tree_store_set (model, &child_iter,
271                                             COLUMN_MARKUP, markup,
272                                             COLUMN_ICON, pixbuf,
273                                             COLUMN_ANNOT_MAPPING, ll->data,
274                                             -1);
275                         g_free (markup);
276                         found = TRUE;
277                 }
278
279                 if (!found)
280                         gtk_tree_store_remove (model, &iter);
281         }
282
283         gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view),
284                                  GTK_TREE_MODEL (model));
285         g_object_unref (model);
286
287         if (text_icon)
288                 g_object_unref (text_icon);
289         if (attachment_icon)
290                 g_object_unref (attachment_icon);
291
292         g_object_unref (job);
293         priv->job = NULL;
294 }
295
296
297 static void
298 ev_sidebar_annotations_document_changed_cb (EvDocumentModel      *model,
299                                             GParamSpec           *pspec,
300                                             EvSidebarAnnotations *sidebar_annots)
301 {
302         EvDocument *document = ev_document_model_get_document (model);
303         EvSidebarAnnotationsPrivate *priv = sidebar_annots->priv;
304
305         if (!EV_IS_DOCUMENT_ANNOTATIONS (document))
306                 return;
307
308         if (priv->job) {
309                 g_signal_handlers_disconnect_by_func (priv->job,
310                                                       job_finished_callback,
311                                                       sidebar_annots);
312                 g_object_unref (priv->job);
313         }
314
315         priv->job = ev_job_annots_new (document);
316         g_signal_connect (priv->job, "finished",
317                           G_CALLBACK (job_finished_callback),
318                           sidebar_annots);
319         /* The priority doesn't matter for this job */
320         ev_job_scheduler_push_job (priv->job, EV_JOB_PRIORITY_NONE);
321 }
322
323 /* EvSidebarPageIface */
324 static void
325 ev_sidebar_annotations_set_model (EvSidebarPage   *sidebar_page,
326                                   EvDocumentModel *model)
327 {
328         g_signal_connect (model, "notify::document",
329                           G_CALLBACK (ev_sidebar_annotations_document_changed_cb),
330                           sidebar_page);
331 }
332
333 static gboolean
334 ev_sidebar_annotations_support_document (EvSidebarPage *sidebar_page,
335                                          EvDocument    *document)
336 {
337         return (EV_IS_DOCUMENT_ANNOTATIONS (document));
338 }
339
340 static const gchar *
341 ev_sidebar_annotations_get_label (EvSidebarPage *sidebar_page)
342 {
343         return _("Annotations");
344 }
345
346 static void
347 ev_sidebar_annotations_page_iface_init (EvSidebarPageInterface *iface)
348 {
349         iface->support_document = ev_sidebar_annotations_support_document;
350         iface->set_model = ev_sidebar_annotations_set_model;
351         iface->get_label = ev_sidebar_annotations_get_label;
352 }