1 /* ev-sidebar-annotations.c
2 * this file is part of evince, a gnome document viewer
4 * Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
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.
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.
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.
23 #include <glib/gi18n.h>
25 #include "ev-document-annotations.h"
26 #include "ev-sidebar-page.h"
27 #include "ev-sidebar-annotations.h"
29 #include "ev-job-scheduler.h"
30 #include "ev-stock-icons.h"
51 struct _EvSidebarAnnotationsPrivate {
57 GtkToolItem *annot_text_item;
60 guint selection_changed_id;
63 static void ev_sidebar_annotations_page_iface_init (EvSidebarPageInterface *iface);
64 static void ev_sidebar_annotations_load (EvSidebarAnnotations *sidebar_annots);
66 static guint signals[N_SIGNALS];
68 G_DEFINE_TYPE_EXTENDED (EvSidebarAnnotations,
69 ev_sidebar_annotations,
72 G_IMPLEMENT_INTERFACE (EV_TYPE_SIDEBAR_PAGE,
73 ev_sidebar_annotations_page_iface_init))
75 #define EV_SIDEBAR_ANNOTATIONS_GET_PRIVATE(object) \
76 (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_ANNOTATIONS, EvSidebarAnnotationsPrivate))
79 ev_sidebar_annotations_dispose (GObject *object)
81 EvSidebarAnnotations *sidebar_annots = EV_SIDEBAR_ANNOTATIONS (object);
82 EvSidebarAnnotationsPrivate *priv = sidebar_annots->priv;
85 g_object_unref (priv->document);
86 priv->document = NULL;
89 G_OBJECT_CLASS (ev_sidebar_annotations_parent_class)->dispose (object);
93 ev_sidebar_annotations_create_simple_model (const gchar *message)
99 /* Creates a fake model to indicate that we're loading */
100 retval = (GtkTreeModel *)gtk_list_store_new (N_COLUMNS,
105 gtk_list_store_append (GTK_LIST_STORE (retval), &iter);
106 markup = g_strdup_printf ("<span size=\"larger\" style=\"italic\">%s</span>",
108 gtk_list_store_set (GTK_LIST_STORE (retval), &iter,
109 COLUMN_MARKUP, markup,
117 ev_sidebar_annotations_add_annots_list (EvSidebarAnnotations *ev_annots)
120 GtkTreeModel *loading_model;
121 GtkCellRenderer *renderer;
122 GtkTreeViewColumn *column;
123 GtkTreeSelection *selection;
126 swindow = gtk_scrolled_window_new (NULL, NULL);
127 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
128 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
129 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
132 /* Create tree view */
133 loading_model = ev_sidebar_annotations_create_simple_model (_("Loading…"));
134 ev_annots->priv->tree_view = gtk_tree_view_new_with_model (loading_model);
135 g_object_unref (loading_model);
137 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ev_annots->priv->tree_view),
139 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ev_annots->priv->tree_view));
140 gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
142 column = gtk_tree_view_column_new ();
144 renderer = gtk_cell_renderer_pixbuf_new ();
145 gtk_tree_view_column_pack_start (column, renderer, FALSE);
146 gtk_tree_view_column_set_attributes (column, renderer,
147 "pixbuf", COLUMN_ICON,
150 renderer = gtk_cell_renderer_text_new ();
151 gtk_tree_view_column_pack_start (column, renderer, TRUE);
152 gtk_tree_view_column_set_attributes (column, renderer,
153 "markup", COLUMN_MARKUP,
155 gtk_tree_view_append_column (GTK_TREE_VIEW (ev_annots->priv->tree_view),
158 gtk_container_add (GTK_CONTAINER (swindow), ev_annots->priv->tree_view);
159 gtk_widget_show (ev_annots->priv->tree_view);
161 label = gtk_label_new (_("List"));
162 gtk_notebook_append_page (GTK_NOTEBOOK (ev_annots->priv->notebook),
164 gtk_widget_show (label);
166 gtk_widget_show (swindow);
170 ev_sidebar_annotations_text_annot_button_toggled (GtkToggleToolButton *toolbutton,
171 EvSidebarAnnotations *sidebar_annots)
173 EvAnnotationType annot_type;
175 if (!gtk_toggle_tool_button_get_active (toolbutton)) {
176 g_signal_emit (sidebar_annots, signals[ANNOT_ADD_CANCELLED], 0, NULL);
180 if (GTK_TOOL_ITEM (toolbutton) == sidebar_annots->priv->annot_text_item)
181 annot_type = EV_ANNOTATION_TYPE_TEXT;
183 annot_type = EV_ANNOTATION_TYPE_UNKNOWN;
185 g_signal_emit (sidebar_annots, signals[BEGIN_ANNOT_ADD], 0, annot_type);
189 ev_sidebar_annotations_add_annots_palette (EvSidebarAnnotations *ev_annots)
196 swindow = gtk_scrolled_window_new (NULL, NULL);
197 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
198 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
199 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
202 ev_annots->priv->palette = gtk_tool_palette_new ();
203 group = gtk_tool_item_group_new (_("Annotations"));
204 gtk_container_add (GTK_CONTAINER (ev_annots->priv->palette), group);
206 /* FIXME: use a better icon than EDIT */
207 item = gtk_toggle_tool_button_new ();
208 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), GTK_STOCK_EDIT);
209 gtk_tool_button_set_label (GTK_TOOL_BUTTON (item), _("Text"));
210 gtk_widget_set_tooltip_text (GTK_WIDGET (item), _("Add text annotation"));
211 ev_annots->priv->annot_text_item = item;
212 g_signal_connect (item, "toggled",
213 G_CALLBACK (ev_sidebar_annotations_text_annot_button_toggled),
215 gtk_tool_item_group_insert (GTK_TOOL_ITEM_GROUP (group), item, -1);
216 gtk_widget_show (GTK_WIDGET (item));
218 gtk_container_add (GTK_CONTAINER (swindow), ev_annots->priv->palette);
219 gtk_widget_show (ev_annots->priv->palette);
221 label = gtk_label_new (_("Add"));
222 gtk_notebook_append_page (GTK_NOTEBOOK (ev_annots->priv->notebook),
224 gtk_widget_show (label);
226 gtk_widget_show (swindow);
230 ev_sidebar_annotations_init (EvSidebarAnnotations *ev_annots)
232 ev_annots->priv = EV_SIDEBAR_ANNOTATIONS_GET_PRIVATE (ev_annots);
234 ev_annots->priv->notebook = gtk_notebook_new ();
235 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (ev_annots->priv->notebook), FALSE);
236 gtk_notebook_set_show_border (GTK_NOTEBOOK (ev_annots->priv->notebook), FALSE);
237 ev_sidebar_annotations_add_annots_list (ev_annots);
238 ev_sidebar_annotations_add_annots_palette (ev_annots);
239 gtk_container_add (GTK_CONTAINER (ev_annots), ev_annots->priv->notebook);
240 gtk_widget_show (ev_annots->priv->notebook);
244 ev_sidebar_annotations_get_property (GObject *object,
249 EvSidebarAnnotations *ev_sidebar_annots;
251 ev_sidebar_annots = EV_SIDEBAR_ANNOTATIONS (object);
255 g_value_set_object (value, ev_sidebar_annots->priv->notebook);
258 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
264 ev_sidebar_annotations_class_init (EvSidebarAnnotationsClass *klass)
266 GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
268 g_object_class->get_property = ev_sidebar_annotations_get_property;
269 g_object_class->dispose = ev_sidebar_annotations_dispose;
271 g_type_class_add_private (g_object_class, sizeof (EvSidebarAnnotationsPrivate));
273 g_object_class_override_property (g_object_class, PROP_WIDGET, "main-widget");
275 signals[ANNOT_ACTIVATED] =
276 g_signal_new ("annot-activated",
277 G_TYPE_FROM_CLASS (g_object_class),
278 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
279 G_STRUCT_OFFSET (EvSidebarAnnotationsClass, annot_activated),
281 g_cclosure_marshal_VOID__POINTER,
284 signals[BEGIN_ANNOT_ADD] =
285 g_signal_new ("begin-annot-add",
286 G_TYPE_FROM_CLASS (g_object_class),
287 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
288 G_STRUCT_OFFSET (EvSidebarAnnotationsClass, begin_annot_add),
290 g_cclosure_marshal_VOID__ENUM,
292 EV_TYPE_ANNOTATION_TYPE);
293 signals[ANNOT_ADD_CANCELLED] =
294 g_signal_new ("annot-add-cancelled",
295 G_TYPE_FROM_CLASS (g_object_class),
296 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
297 G_STRUCT_OFFSET (EvSidebarAnnotationsClass, annot_add_cancelled),
299 g_cclosure_marshal_VOID__VOID,
305 ev_sidebar_annotations_new (void)
307 return GTK_WIDGET (g_object_new (EV_TYPE_SIDEBAR_ANNOTATIONS, NULL));
311 ev_sidebar_annotations_annot_added (EvSidebarAnnotations *sidebar_annots,
314 GtkToggleToolButton *toolbutton;
316 if (EV_IS_ANNOTATION_TEXT (annot)) {
317 toolbutton = GTK_TOGGLE_TOOL_BUTTON (sidebar_annots->priv->annot_text_item);
318 g_signal_handlers_block_by_func (toolbutton,
319 ev_sidebar_annotations_text_annot_button_toggled,
321 gtk_toggle_tool_button_set_active (toolbutton, FALSE);
322 g_signal_handlers_unblock_by_func (toolbutton,
323 ev_sidebar_annotations_text_annot_button_toggled,
327 ev_sidebar_annotations_load (sidebar_annots);
331 selection_changed_cb (GtkTreeSelection *selection,
332 EvSidebarAnnotations *sidebar_annots)
337 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
338 EvMapping *mapping = NULL;
340 gtk_tree_model_get (model, &iter,
341 COLUMN_ANNOT_MAPPING, &mapping,
344 g_signal_emit (sidebar_annots, signals[ANNOT_ACTIVATED], 0, mapping);
349 job_finished_callback (EvJobAnnots *job,
350 EvSidebarAnnotations *sidebar_annots)
352 EvSidebarAnnotationsPrivate *priv;
354 GtkTreeSelection *selection;
356 GdkPixbuf *text_icon = NULL;
357 GdkPixbuf *attachment_icon = NULL;
359 priv = sidebar_annots->priv;
364 list = ev_sidebar_annotations_create_simple_model (_("Document contains no annotations"));
365 gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), list);
366 g_object_unref (list);
368 g_object_unref (job);
374 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
375 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
376 if (priv->selection_changed_id == 0) {
377 priv->selection_changed_id =
378 g_signal_connect (selection, "changed",
379 G_CALLBACK (selection_changed_cb),
383 model = gtk_tree_store_new (N_COLUMNS,
388 for (l = job->annots; l; l = g_list_next (l)) {
389 EvMappingList *mapping_list;
393 gboolean found = FALSE;
395 mapping_list = (EvMappingList *)l->data;
396 page_label = g_strdup_printf (_("Page %d"),
397 ev_mapping_list_get_page (mapping_list) + 1);
398 gtk_tree_store_append (model, &iter, NULL);
399 gtk_tree_store_set (model, &iter,
400 COLUMN_MARKUP, page_label,
404 for (ll = ev_mapping_list_get_list (mapping_list); ll; ll = g_list_next (ll)) {
407 const gchar *modified;
409 GtkTreeIter child_iter;
410 GdkPixbuf *pixbuf = NULL;
412 annot = ((EvMapping *)(ll->data))->data;
413 if (!EV_IS_ANNOTATION_MARKUP (annot))
416 label = ev_annotation_markup_get_label (EV_ANNOTATION_MARKUP (annot));
417 modified = ev_annotation_get_modified (annot);
419 markup = g_strdup_printf ("<span weight=\"bold\">%s</span>\n%s",
422 markup = g_strdup_printf ("<span weight=\"bold\">%s</span>", label);
425 if (EV_IS_ANNOTATION_TEXT (annot)) {
427 /* FIXME: use a better icon than EDIT */
428 text_icon = gtk_widget_render_icon (priv->tree_view,
430 GTK_ICON_SIZE_BUTTON,
434 } else if (EV_IS_ANNOTATION_ATTACHMENT (annot)) {
435 if (!attachment_icon) {
436 attachment_icon = gtk_widget_render_icon (priv->tree_view,
438 GTK_ICON_SIZE_BUTTON,
441 pixbuf = attachment_icon;
444 gtk_tree_store_append (model, &child_iter, &iter);
445 gtk_tree_store_set (model, &child_iter,
446 COLUMN_MARKUP, markup,
448 COLUMN_ANNOT_MAPPING, ll->data,
455 gtk_tree_store_remove (model, &iter);
458 gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view),
459 GTK_TREE_MODEL (model));
460 g_object_unref (model);
463 g_object_unref (text_icon);
465 g_object_unref (attachment_icon);
467 g_object_unref (job);
472 ev_sidebar_annotations_load (EvSidebarAnnotations *sidebar_annots)
474 EvSidebarAnnotationsPrivate *priv = sidebar_annots->priv;
477 g_signal_handlers_disconnect_by_func (priv->job,
478 job_finished_callback,
480 g_object_unref (priv->job);
483 priv->job = ev_job_annots_new (priv->document);
484 g_signal_connect (priv->job, "finished",
485 G_CALLBACK (job_finished_callback),
487 /* The priority doesn't matter for this job */
488 ev_job_scheduler_push_job (priv->job, EV_JOB_PRIORITY_NONE);
492 ev_sidebar_annotations_document_changed_cb (EvDocumentModel *model,
494 EvSidebarAnnotations *sidebar_annots)
496 EvDocument *document = ev_document_model_get_document (model);
497 EvSidebarAnnotationsPrivate *priv = sidebar_annots->priv;
500 if (!EV_IS_DOCUMENT_ANNOTATIONS (document))
504 g_object_unref (priv->document);
505 priv->document = g_object_ref (document);
507 show_tabs = ev_document_annotations_can_add_annotation (EV_DOCUMENT_ANNOTATIONS (document));
508 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), show_tabs);
510 ev_sidebar_annotations_load (sidebar_annots);
513 /* EvSidebarPageIface */
515 ev_sidebar_annotations_set_model (EvSidebarPage *sidebar_page,
516 EvDocumentModel *model)
518 g_signal_connect (model, "notify::document",
519 G_CALLBACK (ev_sidebar_annotations_document_changed_cb),
524 ev_sidebar_annotations_support_document (EvSidebarPage *sidebar_page,
525 EvDocument *document)
527 return (EV_IS_DOCUMENT_ANNOTATIONS (document));
531 ev_sidebar_annotations_get_label (EvSidebarPage *sidebar_page)
533 return _("Annotations");
537 ev_sidebar_annotations_page_iface_init (EvSidebarPageInterface *iface)
539 iface->support_document = ev_sidebar_annotations_support_document;
540 iface->set_model = ev_sidebar_annotations_set_model;
541 iface->get_label = ev_sidebar_annotations_get_label;