From c497b6a969f916a476d0bb01e38ff6584ff4bfe5 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Mon, 12 Jul 2010 10:40:39 +0000 Subject: [shell] Add a sidebar page to show the list of annotations --- diff --git a/shell/Makefile.am b/shell/Makefile.am index 94488b9..523d299 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -70,6 +70,8 @@ evince_SOURCES= \ ev-window-title.h \ ev-sidebar.c \ ev-sidebar.h \ + ev-sidebar-annotations.c \ + ev-sidebar-annotations.h \ ev-sidebar-attachments.c \ ev-sidebar-attachments.h \ ev-sidebar-layers.c \ diff --git a/shell/ev-sidebar-annotations.c b/shell/ev-sidebar-annotations.c new file mode 100644 index 0000000..67a49f1 --- /dev/null +++ b/shell/ev-sidebar-annotations.c @@ -0,0 +1,352 @@ +/* ev-sidebar-annotations.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "ev-document-annotations.h" +#include "ev-sidebar-page.h" +#include "ev-sidebar-annotations.h" +#include "ev-jobs.h" +#include "ev-job-scheduler.h" +#include "ev-stock-icons.h" + +enum { + PROP_0, + PROP_WIDGET +}; + +enum { + COLUMN_MARKUP, + COLUMN_ICON, + COLUMN_ANNOT_MAPPING, + N_COLUMNS +}; + +struct _EvSidebarAnnotationsPrivate { + GtkWidget *notebook; + GtkWidget *tree_view; + + EvJob *job; +}; + +static void ev_sidebar_annotations_page_iface_init (EvSidebarPageInterface *iface); + +G_DEFINE_TYPE_EXTENDED (EvSidebarAnnotations, + ev_sidebar_annotations, + GTK_TYPE_VBOX, + 0, + G_IMPLEMENT_INTERFACE (EV_TYPE_SIDEBAR_PAGE, + ev_sidebar_annotations_page_iface_init)) + +#define EV_SIDEBAR_ANNOTATIONS_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_ANNOTATIONS, EvSidebarAnnotationsPrivate)) + +static GtkTreeModel * +ev_sidebar_annotations_create_simple_model (const gchar *message) +{ + GtkTreeModel *retval; + GtkTreeIter iter; + gchar *markup; + + /* Creates a fake model to indicate that we're loading */ + retval = (GtkTreeModel *)gtk_list_store_new (N_COLUMNS, + G_TYPE_STRING, + GDK_TYPE_PIXBUF, + G_TYPE_POINTER); + + gtk_list_store_append (GTK_LIST_STORE (retval), &iter); + markup = g_strdup_printf ("%s", + message); + gtk_list_store_set (GTK_LIST_STORE (retval), &iter, + COLUMN_MARKUP, markup, + -1); + g_free (markup); + + return retval; +} + +static void +ev_sidebar_annotations_add_annots_list (EvSidebarAnnotations *ev_annots) +{ + GtkWidget *swindow; + GtkTreeModel *loading_model; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow), + GTK_SHADOW_IN); + + /* Create tree view */ + loading_model = ev_sidebar_annotations_create_simple_model (_("Loading…")); + ev_annots->priv->tree_view = gtk_tree_view_new_with_model (loading_model); + g_object_unref (loading_model); + + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ev_annots->priv->tree_view), + FALSE); + + column = gtk_tree_view_column_new (); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_set_attributes (column, renderer, + "pixbuf", COLUMN_ICON, + NULL); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_set_attributes (column, renderer, + "markup", COLUMN_MARKUP, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (ev_annots->priv->tree_view), + column); + + gtk_container_add (GTK_CONTAINER (swindow), ev_annots->priv->tree_view); + gtk_widget_show (ev_annots->priv->tree_view); + + gtk_notebook_append_page (GTK_NOTEBOOK (ev_annots->priv->notebook), + swindow, NULL); + gtk_widget_show (swindow); +} + +static void +ev_sidebar_annotations_init (EvSidebarAnnotations *ev_annots) +{ + ev_annots->priv = EV_SIDEBAR_ANNOTATIONS_GET_PRIVATE (ev_annots); + + ev_annots->priv->notebook = gtk_notebook_new (); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (ev_annots->priv->notebook), FALSE); + gtk_notebook_set_show_border (GTK_NOTEBOOK (ev_annots->priv->notebook), FALSE); + ev_sidebar_annotations_add_annots_list (ev_annots); + gtk_container_add (GTK_CONTAINER (ev_annots), ev_annots->priv->notebook); + gtk_widget_show (ev_annots->priv->notebook); +} + +static void +ev_sidebar_annotations_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EvSidebarAnnotations *ev_sidebar_annots; + + ev_sidebar_annots = EV_SIDEBAR_ANNOTATIONS (object); + + switch (prop_id) { + case PROP_WIDGET: + g_value_set_object (value, ev_sidebar_annots->priv->notebook); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ev_sidebar_annotations_class_init (EvSidebarAnnotationsClass *klass) +{ + GObjectClass *g_object_class = G_OBJECT_CLASS (klass); + + g_object_class->get_property = ev_sidebar_annotations_get_property; + + g_type_class_add_private (g_object_class, sizeof (EvSidebarAnnotationsPrivate)); + + g_object_class_override_property (g_object_class, PROP_WIDGET, "main-widget"); +} + +GtkWidget * +ev_sidebar_annotations_new (void) +{ + return GTK_WIDGET (g_object_new (EV_TYPE_SIDEBAR_ANNOTATIONS, NULL)); +} + +static void +job_finished_callback (EvJobAnnots *job, + EvSidebarAnnotations *sidebar_annots) +{ + EvSidebarAnnotationsPrivate *priv; + GtkTreeStore *model; + GList *l; + GdkPixbuf *text_icon = NULL; + GdkPixbuf *attachment_icon = NULL; + + priv = sidebar_annots->priv; + + if (!job->annots) { + GtkTreeModel *list; + + list = ev_sidebar_annotations_create_simple_model (_("Document contains no annotations")); + gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), list); + g_object_unref (list); + + g_object_unref (job); + priv->job = NULL; + + return; + } + + model = gtk_tree_store_new (N_COLUMNS, + G_TYPE_STRING, + GDK_TYPE_PIXBUF, + G_TYPE_POINTER); + + for (l = job->annots; l; l = g_list_next (l)) { + EvMappingList *mapping_list; + GList *ll; + gchar *page_label; + GtkTreeIter iter; + gboolean found = FALSE; + + mapping_list = (EvMappingList *)l->data; + page_label = g_strdup_printf (_("Page %d"), + ev_mapping_list_get_page (mapping_list) + 1); + gtk_tree_store_append (model, &iter, NULL); + gtk_tree_store_set (model, &iter, + COLUMN_MARKUP, page_label, + -1); + g_free (page_label); + + for (ll = ev_mapping_list_get_list (mapping_list); ll; ll = g_list_next (ll)) { + EvAnnotation *annot; + gchar *label; + gchar *markup; + GtkTreeIter child_iter; + GdkPixbuf *pixbuf = NULL; + + annot = ((EvMapping *)(ll->data))->data; + if (!EV_IS_ANNOTATION_MARKUP (annot)) + continue; + + label = ev_annotation_markup_get_label (EV_ANNOTATION_MARKUP (annot)); + if (annot->modified) { + markup = g_strdup_printf ("%s\n%s", + label, annot->modified); + } else { + markup = g_strdup_printf ("%s", label); + } + g_free (label); + + if (EV_IS_ANNOTATION_TEXT (annot)) { + if (!text_icon) { + /* FIXME: use a better icon than EDIT */ + text_icon = gtk_widget_render_icon (priv->tree_view, + GTK_STOCK_EDIT, + GTK_ICON_SIZE_BUTTON, + NULL); + } + pixbuf = text_icon; + } else if (EV_IS_ANNOTATION_ATTACHMENT (annot)) { + if (!attachment_icon) { + attachment_icon = gtk_widget_render_icon (priv->tree_view, + EV_STOCK_ATTACHMENT, + GTK_ICON_SIZE_BUTTON, + NULL); + } + pixbuf = attachment_icon; + } + + gtk_tree_store_append (model, &child_iter, &iter); + gtk_tree_store_set (model, &child_iter, + COLUMN_MARKUP, markup, + COLUMN_ICON, pixbuf, + COLUMN_ANNOT_MAPPING, ll->data, + -1); + g_free (markup); + found = TRUE; + } + + if (!found) + gtk_tree_store_remove (model, &iter); + } + + gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), + GTK_TREE_MODEL (model)); + g_object_unref (model); + + if (text_icon) + g_object_unref (text_icon); + if (attachment_icon) + g_object_unref (attachment_icon); + + g_object_unref (job); + priv->job = NULL; +} + + +static void +ev_sidebar_annotations_document_changed_cb (EvDocumentModel *model, + GParamSpec *pspec, + EvSidebarAnnotations *sidebar_annots) +{ + EvDocument *document = ev_document_model_get_document (model); + EvSidebarAnnotationsPrivate *priv = sidebar_annots->priv; + + if (!EV_IS_DOCUMENT_ANNOTATIONS (document)) + return; + + if (priv->job) { + g_signal_handlers_disconnect_by_func (priv->job, + job_finished_callback, + sidebar_annots); + g_object_unref (priv->job); + } + + priv->job = ev_job_annots_new (document); + g_signal_connect (priv->job, "finished", + G_CALLBACK (job_finished_callback), + sidebar_annots); + /* The priority doesn't matter for this job */ + ev_job_scheduler_push_job (priv->job, EV_JOB_PRIORITY_NONE); +} + +/* EvSidebarPageIface */ +static void +ev_sidebar_annotations_set_model (EvSidebarPage *sidebar_page, + EvDocumentModel *model) +{ + g_signal_connect (model, "notify::document", + G_CALLBACK (ev_sidebar_annotations_document_changed_cb), + sidebar_page); +} + +static gboolean +ev_sidebar_annotations_support_document (EvSidebarPage *sidebar_page, + EvDocument *document) +{ + return (EV_IS_DOCUMENT_ANNOTATIONS (document)); +} + +static const gchar * +ev_sidebar_annotations_get_label (EvSidebarPage *sidebar_page) +{ + return _("Annotations"); +} + +static void +ev_sidebar_annotations_page_iface_init (EvSidebarPageInterface *iface) +{ + iface->support_document = ev_sidebar_annotations_support_document; + iface->set_model = ev_sidebar_annotations_set_model; + iface->get_label = ev_sidebar_annotations_get_label; +} diff --git a/shell/ev-sidebar-annotations.h b/shell/ev-sidebar-annotations.h new file mode 100644 index 0000000..72c5cc3 --- /dev/null +++ b/shell/ev-sidebar-annotations.h @@ -0,0 +1,56 @@ +/* ev-sidebar-annotations.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __EV_SIDEBAR_ANNOTATIONS_H__ +#define __EV_SIDEBAR_ANNOTATIONS_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _EvSidebarAnnotations EvSidebarAnnotations; +typedef struct _EvSidebarAnnotationsClass EvSidebarAnnotationsClass; +typedef struct _EvSidebarAnnotationsPrivate EvSidebarAnnotationsPrivate; + +#define EV_TYPE_SIDEBAR_ANNOTATIONS (ev_sidebar_annotations_get_type()) +#define EV_SIDEBAR_ANNOTATIONS(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_SIDEBAR_ANNOTATIONS, EvSidebarAnnotations)) +#define EV_SIDEBAR_ANNOTATIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_SIDEBAR_ANNOTATIONS, EvSidebarAnnotationsClass)) +#define EV_IS_SIDEBAR_ANNOTATIONS(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_SIDEBAR_ANNOTATIONS)) +#define EV_IS_SIDEBAR_ANNOTATIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_SIDEBAR_ANNOTATIONS)) +#define EV_SIDEBAR_ANNOTATIONS_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_SIDEBAR_ANNOTATIONS, EvSidebarAnnotationsClass)) + +struct _EvSidebarAnnotations { + GtkVBox base_instance; + + EvSidebarAnnotationsPrivate *priv; +}; + +struct _EvSidebarAnnotationsClass { + GtkVBoxClass base_class; + +}; + +GType ev_sidebar_annotations_get_type (void) G_GNUC_CONST; +GtkWidget *ev_sidebar_annotations_new (void); + +G_END_DECLS + +#endif /* __EV_SIDEBAR_ANNOTATIONS_H__ */ diff --git a/shell/ev-window.c b/shell/ev-window.c index b00deee..9228f4a 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -78,6 +78,7 @@ #include "ev-page-action.h" #include "ev-password-view.h" #include "ev-properties-dialog.h" +#include "ev-sidebar-annotations.h" #include "ev-sidebar-attachments.h" #include "ev-sidebar.h" #include "ev-sidebar-links.h" @@ -140,6 +141,7 @@ struct _EvWindowPrivate { GtkWidget *sidebar_links; GtkWidget *sidebar_attachments; GtkWidget *sidebar_layers; + GtkWidget *sidebar_annots; /* Settings */ GSettings *settings; @@ -246,6 +248,7 @@ struct _EvWindowPrivate { #define THUMBNAILS_SIDEBAR_ID "thumbnails" #define ATTACHMENTS_SIDEBAR_ID "attachments" #define LAYERS_SIDEBAR_ID "layers" +#define ANNOTS_SIDEBAR_ID "annotations" #define EV_PRINT_SETTINGS_FILE "print-settings" #define EV_PRINT_SETTINGS_GROUP "Print Settings" @@ -933,6 +936,7 @@ setup_sidebar_from_metadata (EvWindow *window) GtkWidget *links = window->priv->sidebar_links; GtkWidget *thumbs = window->priv->sidebar_thumbs; GtkWidget *attachments = window->priv->sidebar_attachments; + GtkWidget *annots = window->priv->sidebar_annots; GtkWidget *layers = window->priv->sidebar_layers; gchar *page_id; gint sidebar_size; @@ -963,6 +967,8 @@ setup_sidebar_from_metadata (EvWindow *window) ev_sidebar_set_page (EV_SIDEBAR (sidebar), attachments); } else if (strcmp (page_id, LAYERS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (layers), document)) { ev_sidebar_set_page (EV_SIDEBAR (sidebar), layers); + } else if (strcmp (page_id, ANNOTS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (annots), document)) { + ev_sidebar_set_page (EV_SIDEBAR (sidebar), annots); } } else if (document) { if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) { @@ -973,6 +979,8 @@ setup_sidebar_from_metadata (EvWindow *window) ev_sidebar_set_page (EV_SIDEBAR (sidebar), attachments); } else if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (layers), document)) { ev_sidebar_set_page (EV_SIDEBAR (sidebar), layers); + } else if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (annots), document)) { + ev_sidebar_set_page (EV_SIDEBAR (sidebar), annots); } } } @@ -4408,6 +4416,8 @@ ev_window_sidebar_current_page_changed_cb (EvSidebar *ev_sidebar, id = ATTACHMENTS_SIDEBAR_ID; } else if (current_page == ev_window->priv->sidebar_layers) { id = LAYERS_SIDEBAR_ID; + } else if (current_page == ev_window->priv->sidebar_annots) { + id = ANNOTS_SIDEBAR_ID; } else { g_assert_not_reached(); } @@ -6525,6 +6535,12 @@ ev_window_init (EvWindow *ev_window) ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar), sidebar_widget); + sidebar_widget = ev_sidebar_annotations_new (); + ev_window->priv->sidebar_annots = sidebar_widget; + gtk_widget_show (sidebar_widget); + ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar), + sidebar_widget); + ev_window->priv->view_box = gtk_vbox_new (FALSE, 0); ev_window->priv->scrolled_window = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW, -- cgit v0.9.1