From: Carlos Garcia Campos Date: Sat, 15 Nov 2008 10:08:38 +0000 (+0000) Subject: Add layers support. X-Git-Tag: EVINCE_2_25_2~14 X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=commitdiff_plain;h=7f94a4075450791807ee2699cb0e7a0293ccc2f3;p=evince.git Add layers support. 2008-11-15 Carlos Garcia Campos * shell/Makefile.am: * shell/ev-jobs.[ch]: (ev_job_layers_init), (ev_job_layers_dispose), (ev_job_layers_run), (ev_job_layers_class_init), (ev_job_layers_new): * shell/ev-sidebar-layers.[ch]: * shell/ev-view.[ch]: (ev_view_form_field_button_create_widget), (ev_view_form_field_text_save), (ev_view_form_field_choice_save), (ev_view_reload_page), (ev_view_reload): * shell/ev-window.c: (setup_sidebar_from_metadata), (ev_window_sidebar_current_page_changed_cb), (sidebar_layers_visibility_changed), (ev_window_init): Add layers support. svn path=/trunk/; revision=3268 --- diff --git a/ChangeLog b/ChangeLog index eb4bfdc8..9b3ab874 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2008-11-15 Carlos Garcia Campos + + * shell/Makefile.am: + * shell/ev-jobs.[ch]: (ev_job_layers_init), + (ev_job_layers_dispose), (ev_job_layers_run), + (ev_job_layers_class_init), (ev_job_layers_new): + * shell/ev-sidebar-layers.[ch]: + * shell/ev-view.[ch]: (ev_view_form_field_button_create_widget), + (ev_view_form_field_text_save), (ev_view_form_field_choice_save), + (ev_view_reload_page), (ev_view_reload): + * shell/ev-window.c: (setup_sidebar_from_metadata), + (ev_window_sidebar_current_page_changed_cb), + (sidebar_layers_visibility_changed), (ev_window_init): + + Add layers support. + 2008-11-15 Carlos Garcia Campos * data/icons/22x22/actions/Makefile.am: diff --git a/shell/Makefile.am b/shell/Makefile.am index 3dc7e154..b1dafd7a 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -1,18 +1,19 @@ -INCLUDES= \ - -DDATADIR=\"$(pkgdatadir)\" \ - -DGNOMEDATADIR=\"$(datadir)\" \ - -I$(top_srcdir)/cut-n-paste/zoom-control/ \ - -I$(top_srcdir)/cut-n-paste/toolbar-editor/ \ - -I$(top_srcdir)/cut-n-paste/totem-screensaver/ \ - -I$(top_srcdir)/cut-n-paste/gedit-message-area/ \ - -I$(top_srcdir)/cut-n-paste/evmountoperation/ \ - -I$(top_srcdir)/cut-n-paste/smclient/ \ - -I$(top_srcdir)/libdocument \ - -I$(top_srcdir)/properties \ - -DGNOMELOCALEDIR=\"$(datadir)/locale\" \ - -DGNOMEICONDIR=\""$(datadir)/pixmaps"\" \ - $(SHELL_CFLAGS) \ - $(WARN_CFLAGS) \ +INCLUDES= \ + -DDATADIR=\"$(pkgdatadir)\" \ + -DGNOMEDATADIR=\"$(datadir)\" \ + -I$(top_srcdir)/cut-n-paste/zoom-control/ \ + -I$(top_srcdir)/cut-n-paste/toolbar-editor/ \ + -I$(top_srcdir)/cut-n-paste/totem-screensaver/ \ + -I$(top_srcdir)/cut-n-paste/gedit-message-area/ \ + -I$(top_srcdir)/cut-n-paste/gimpcellrenderertoggle/ \ + -I$(top_srcdir)/cut-n-paste/evmountoperation/ \ + -I$(top_srcdir)/cut-n-paste/smclient/ \ + -I$(top_srcdir)/libdocument \ + -I$(top_srcdir)/properties \ + -DGNOMELOCALEDIR=\"$(datadir)/locale\" \ + -DGNOMEICONDIR=\""$(datadir)/pixmaps"\" \ + $(SHELL_CFLAGS) \ + $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED) bin_PROGRAMS=evince @@ -81,6 +82,8 @@ evince_SOURCES= \ ev-sidebar.h \ ev-sidebar-attachments.c \ ev-sidebar-attachments.h \ + ev-sidebar-layers.c \ + ev-sidebar-layers.h \ ev-sidebar-links.c \ ev-sidebar-links.h \ ev-sidebar-page.c \ @@ -95,15 +98,16 @@ evince_SOURCES= \ ev-transition-animation.h \ main.c -evince_LDADD= \ - $(top_builddir)/cut-n-paste/zoom-control/libephyzoom.la \ - $(top_builddir)/cut-n-paste/toolbar-editor/libtoolbareditor.la \ - $(top_builddir)/cut-n-paste/totem-screensaver/libtotemscrsaver.la \ - $(top_builddir)/cut-n-paste/gedit-message-area/libgeditmsgarea.la \ - $(top_builddir)/cut-n-paste/evmountoperation/libevmountoperation.la \ - $(top_builddir)/cut-n-paste/smclient/libsmclient.la \ - $(top_builddir)/properties/libevproperties.la \ - $(top_builddir)/libdocument/libevbackend.la \ +evince_LDADD= \ + $(top_builddir)/cut-n-paste/zoom-control/libephyzoom.la \ + $(top_builddir)/cut-n-paste/toolbar-editor/libtoolbareditor.la \ + $(top_builddir)/cut-n-paste/totem-screensaver/libtotemscrsaver.la \ + $(top_builddir)/cut-n-paste/gedit-message-area/libgeditmsgarea.la \ + $(top_builddir)/cut-n-paste/gimpcellrenderertoggle/libgimpcellrenderertoggle.la \ + $(top_builddir)/cut-n-paste/evmountoperation/libevmountoperation.la \ + $(top_builddir)/cut-n-paste/smclient/libsmclient.la \ + $(top_builddir)/properties/libevproperties.la \ + $(top_builddir)/libdocument/libevbackend.la \ $(SHELL_LIBS) BUILT_SOURCES = ev-marshal.h ev-marshal.c diff --git a/shell/ev-jobs.c b/shell/ev-jobs.c index dee23b8d..1a5dd475 100644 --- a/shell/ev-jobs.c +++ b/shell/ev-jobs.c @@ -32,6 +32,7 @@ #include "ev-document-fonts.h" #include "ev-document-security.h" #include "ev-document-find.h" +#include "ev-document-layers.h" #include "ev-debug.h" #include @@ -57,6 +58,8 @@ static void ev_job_print_init (EvJobPrint *job); static void ev_job_print_class_init (EvJobPrintClass *class); static void ev_job_find_init (EvJobFind *job); static void ev_job_find_class_init (EvJobFindClass *class); +static void ev_job_layers_init (EvJobLayers *job); +static void ev_job_layers_class_init (EvJobLayersClass *class); enum { CANCELLED, @@ -94,6 +97,7 @@ G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobFind, ev_job_find, EV_TYPE_JOB) +G_DEFINE_TYPE (EvJobLayers, ev_job_layers, EV_TYPE_JOB) /* EvJob */ static void @@ -1536,3 +1540,66 @@ ev_job_find_get_results (EvJobFind *job) return job->pages; } +/* EvJobLayers */ +static void +ev_job_layers_init (EvJobLayers *job) +{ + EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; +} + +static void +ev_job_layers_dispose (GObject *object) +{ + EvJobLayers *job; + + ev_debug_message (DEBUG_JOBS, NULL); + + job = EV_JOB_LAYERS (object); + + if (job->model) { + g_object_unref (job->model); + job->model = NULL; + } + + (* G_OBJECT_CLASS (ev_job_layers_parent_class)->dispose) (object); +} + +static gboolean +ev_job_layers_run (EvJob *job) +{ + EvJobLayers *job_layers = EV_JOB_LAYERS (job); + + ev_debug_message (DEBUG_JOBS, NULL); + ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); + + ev_document_doc_mutex_lock (); + job_layers->model = ev_document_layers_get_layers (EV_DOCUMENT_LAYERS (job->document)); + ev_document_doc_mutex_unlock (); + + ev_job_succeeded (job); + + return FALSE; +} + +static void +ev_job_layers_class_init (EvJobLayersClass *class) +{ + GObjectClass *oclass = G_OBJECT_CLASS (class); + EvJobClass *job_class = EV_JOB_CLASS (class); + + oclass->dispose = ev_job_layers_dispose; + job_class->run = ev_job_layers_run; +} + +EvJob * +ev_job_layers_new (EvDocument *document) +{ + EvJob *job; + + ev_debug_message (DEBUG_JOBS, NULL); + + job = g_object_new (EV_TYPE_JOB_LAYERS, NULL); + job->document = g_object_ref (document); + + return job; +} diff --git a/shell/ev-jobs.h b/shell/ev-jobs.h index 188759e9..6d6581a3 100644 --- a/shell/ev-jobs.h +++ b/shell/ev-jobs.h @@ -60,6 +60,9 @@ typedef struct _EvJobPrintClass EvJobPrintClass; typedef struct _EvJobFind EvJobFind; typedef struct _EvJobFindClass EvJobFindClass; +typedef struct _EvJobLayers EvJobLayers; +typedef struct _EvJobLayersClass EvJobLayersClass; + #define EV_TYPE_JOB (ev_job_get_type()) #define EV_JOB(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB, EvJob)) #define EV_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB, EvJobClass)) @@ -106,10 +109,15 @@ typedef struct _EvJobFindClass EvJobFindClass; #define EV_JOB_PRINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_PRINT, EvJobPrintClass)) #define EV_IS_JOB_PRINT(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_PRINT)) -#define EV_TYPE_JOB_FIND (ev_job_find_get_type()) -#define EV_JOB_FIND(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_FIND, EvJobFind)) -#define EV_JOB_FIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_FIND, EvJobFindClass)) -#define EV_IS_JOB_FIND(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_FIND)) +#define EV_TYPE_JOB_FIND (ev_job_find_get_type()) +#define EV_JOB_FIND(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_FIND, EvJobFind)) +#define EV_JOB_FIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_FIND, EvJobFindClass)) +#define EV_IS_JOB_FIND(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_FIND)) + +#define EV_TYPE_JOB_LAYERS (ev_job_layers_get_type()) +#define EV_JOB_LAYERS(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_LAYERS, EvJobLayers)) +#define EV_JOB_LAYERS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_LAYERS, EvJobLayersClass)) +#define EV_IS_JOB_LAYERS(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_LAYERS)) typedef enum { EV_JOB_RUN_THREAD, @@ -320,6 +328,18 @@ struct _EvJobFindClass gint page); }; +struct _EvJobLayers +{ + EvJob parent; + + GtkTreeModel *model; +}; + +struct _EvJobLayersClass +{ + EvJobClass parent_class; +}; + /* Base job class */ GType ev_job_get_type (void) G_GNUC_CONST; gboolean ev_job_run (EvJob *job); @@ -414,6 +434,10 @@ gdouble ev_job_find_get_progress (EvJobFind *job); gboolean ev_job_find_has_results (EvJobFind *job); GList **ev_job_find_get_results (EvJobFind *job); +/* EvJobLayers */ +GType ev_job_layers_get_type (void) G_GNUC_CONST; +EvJob *ev_job_layers_new (EvDocument *document); + G_END_DECLS #endif /* __EV_JOBS_H__ */ diff --git a/shell/ev-sidebar-layers.c b/shell/ev-sidebar-layers.c new file mode 100644 index 00000000..cebd96d4 --- /dev/null +++ b/shell/ev-sidebar-layers.c @@ -0,0 +1,405 @@ +/* ev-sidebar-layers.c + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2008 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 "gimpcellrenderertoggle.h" + +#include "ev-document-layers.h" +#include "ev-sidebar-page.h" +#include "ev-jobs.h" +#include "ev-job-scheduler.h" +#include "ev-stock-icons.h" +#include "ev-sidebar-layers.h" + +struct _EvSidebarLayersPrivate { + GtkTreeView *tree_view; + + EvDocument *document; + EvJob *job; +}; + +enum { + PROP_0, + PROP_WIDGET +}; + +enum { + LAYERS_VISIBILITY_CHANGED, + N_SIGNALS +}; + +static void ev_sidebar_layers_page_iface_init (EvSidebarPageIface *iface); +static void job_finished_callback (EvJobLayers *job, + EvSidebarLayers *sidebar_layers); + +static guint signals[N_SIGNALS]; + +G_DEFINE_TYPE_EXTENDED (EvSidebarLayers, + ev_sidebar_layers, + GTK_TYPE_VBOX, + 0, + G_IMPLEMENT_INTERFACE (EV_TYPE_SIDEBAR_PAGE, + ev_sidebar_layers_page_iface_init)) + +#define EV_SIDEBAR_LAYERS_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_LAYERS, EvSidebarLayersPrivate)) + +static void +ev_sidebar_layers_dispose (GObject *object) +{ + EvSidebarLayers *sidebar = EV_SIDEBAR_LAYERS (object); + + if (sidebar->priv->job) { + g_signal_handlers_disconnect_by_func (sidebar->priv->job, + job_finished_callback, + sidebar); + ev_job_cancel (sidebar->priv->job); + g_object_unref (sidebar->priv->job); + sidebar->priv->job = NULL; + } + + if (sidebar->priv->document) { + g_object_unref (sidebar->priv->document); + sidebar->priv->document = NULL; + } + + G_OBJECT_CLASS (ev_sidebar_layers_parent_class)->dispose (object); +} + +static void +ev_sidebar_layers_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EvSidebarLayers *ev_sidebar_layers; + + ev_sidebar_layers = EV_SIDEBAR_LAYERS (object); + + switch (prop_id) { + case PROP_WIDGET: + g_value_set_object (value, ev_sidebar_layers->priv->tree_view); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GtkTreeModel * +ev_sidebar_layers_create_loading_model (void) +{ + GtkTreeModel *retval; + GtkTreeIter iter; + gchar *markup; + + /* Creates a fake model to indicate that we're loading */ + retval = (GtkTreeModel *)gtk_list_store_new (EV_DOCUMENT_LAYERS_N_COLUMNS, + G_TYPE_STRING, + G_TYPE_OBJECT, + G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, + G_TYPE_INT); + + gtk_list_store_append (GTK_LIST_STORE (retval), &iter); + markup = g_strdup_printf ("%s", _("Loading...")); + gtk_list_store_set (GTK_LIST_STORE (retval), &iter, + EV_DOCUMENT_LAYERS_COLUMN_TITLE, markup, + EV_DOCUMENT_LAYERS_COLUMN_VISIBLE, FALSE, + EV_DOCUMENT_LAYERS_COLUMN_ENABLED, TRUE, + EV_DOCUMENT_LAYERS_COLUMN_SHOWTOGGLE, FALSE, + EV_DOCUMENT_LAYERS_COLUMN_RBGROUP, -1, + EV_DOCUMENT_LAYERS_COLUMN_LAYER, NULL, + -1); + g_free (markup); + + return retval; +} + +static gboolean +update_kids (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + if (gtk_tree_store_is_ancestor (GTK_TREE_STORE (model), parent, iter)) { + gboolean visible; + + gtk_tree_model_get (model, parent, + EV_DOCUMENT_LAYERS_COLUMN_VISIBLE, &visible, + -1); + gtk_tree_store_set (GTK_TREE_STORE (model), iter, + EV_DOCUMENT_LAYERS_COLUMN_ENABLED, visible, + -1); + } + + return FALSE; +} + +static gboolean +clear_rb_group (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gint *rb_group) +{ + gint group; + + gtk_tree_model_get (model, iter, + EV_DOCUMENT_LAYERS_COLUMN_RBGROUP, &group, + -1); + + if (group == *rb_group) { + gtk_tree_store_set (GTK_TREE_STORE (model), iter, + EV_DOCUMENT_LAYERS_COLUMN_VISIBLE, FALSE, + -1); + } + + return FALSE; +} + +static void +ev_sidebar_layers_visibility_changed (GtkCellRendererToggle *cell, + gchar *path_str, + EvSidebarLayers *ev_layers) +{ + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + gboolean visible; + EvLayer *layer; + + model = gtk_tree_view_get_model (ev_layers->priv->tree_view); + + path = gtk_tree_path_new_from_string (path_str); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + EV_DOCUMENT_LAYERS_COLUMN_VISIBLE, &visible, + EV_DOCUMENT_LAYERS_COLUMN_LAYER, &layer, + -1); + + visible = !visible; + if (visible) { + gint rb_group; + + ev_document_layers_show_layer (EV_DOCUMENT_LAYERS (ev_layers->priv->document), + layer); + + rb_group = ev_layer_get_rb_group (layer); + if (rb_group) { + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc)clear_rb_group, + &rb_group); + } + } else { + ev_document_layers_hide_layer (EV_DOCUMENT_LAYERS (ev_layers->priv->document), + layer); + } + + gtk_tree_store_set (GTK_TREE_STORE (model), &iter, + EV_DOCUMENT_LAYERS_COLUMN_VISIBLE, visible, + -1); + + if (ev_layer_is_parent (layer)) { + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc)update_kids, + &iter); + } + + gtk_tree_path_free (path); + + g_signal_emit (ev_layers, signals[LAYERS_VISIBILITY_CHANGED], 0); +} + +static GtkTreeView * +ev_sidebar_layers_create_tree_view (EvSidebarLayers *ev_layers) +{ + GtkTreeView *tree_view; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + + tree_view = GTK_TREE_VIEW (gtk_tree_view_new ()); + gtk_tree_view_set_headers_visible (tree_view, FALSE); + gtk_tree_selection_set_mode (gtk_tree_view_get_selection (tree_view), + GTK_SELECTION_NONE); + + + column = gtk_tree_view_column_new (); + + renderer = gimp_cell_renderer_toggle_new (EV_STOCK_VISIBLE); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_set_attributes (column, renderer, + "active", EV_DOCUMENT_LAYERS_COLUMN_VISIBLE, + "activatable", EV_DOCUMENT_LAYERS_COLUMN_ENABLED, + "visible", EV_DOCUMENT_LAYERS_COLUMN_SHOWTOGGLE, + "sensitive", EV_DOCUMENT_LAYERS_COLUMN_ENABLED, + NULL); + g_object_set (G_OBJECT (renderer), + "xpad", 0, + "ypad", 0, + NULL); + g_signal_connect (renderer, "toggled", + G_CALLBACK (ev_sidebar_layers_visibility_changed), + (gpointer)ev_layers); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_set_attributes (column, renderer, + "markup", EV_DOCUMENT_LAYERS_COLUMN_TITLE, + "sensitive", EV_DOCUMENT_LAYERS_COLUMN_ENABLED, + NULL); + g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL); + + gtk_tree_view_append_column (tree_view, column); + + return tree_view; +} + +static void +ev_sidebar_layers_init (EvSidebarLayers *ev_layers) +{ + GtkWidget *swindow; + GtkTreeModel *model; + + ev_layers->priv = EV_SIDEBAR_LAYERS_GET_PRIVATE (ev_layers); + + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow), + GTK_SHADOW_IN); + /* Data Model */ + model = ev_sidebar_layers_create_loading_model (); + + /* Layers list */ + ev_layers->priv->tree_view = ev_sidebar_layers_create_tree_view (ev_layers); + gtk_tree_view_set_model (ev_layers->priv->tree_view, model); + g_object_unref (model); + + gtk_container_add (GTK_CONTAINER (swindow), + GTK_WIDGET (ev_layers->priv->tree_view)); + + gtk_container_add (GTK_CONTAINER (ev_layers), swindow); + gtk_widget_show_all (GTK_WIDGET (ev_layers)); +} + +static void +ev_sidebar_layers_class_init (EvSidebarLayersClass *ev_layers_class) +{ + GObjectClass *g_object_class = G_OBJECT_CLASS (ev_layers_class); + + g_object_class->get_property = ev_sidebar_layers_get_property; + g_object_class->dispose = ev_sidebar_layers_dispose; + + g_type_class_add_private (g_object_class, sizeof (EvSidebarLayersPrivate)); + + g_object_class_override_property (g_object_class, PROP_WIDGET, "main-widget"); + + signals[LAYERS_VISIBILITY_CHANGED] = + g_signal_new ("layers_visibility_changed", + G_TYPE_FROM_CLASS (g_object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvSidebarLayersClass, layers_visibility_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0, G_TYPE_NONE); +} + +GtkWidget * +ev_sidebar_layers_new (void) +{ + return GTK_WIDGET (g_object_new (EV_TYPE_SIDEBAR_LAYERS, NULL)); +} + +static void +job_finished_callback (EvJobLayers *job, + EvSidebarLayers *sidebar_layers) +{ + EvSidebarLayersPrivate *priv; + + priv = sidebar_layers->priv; + + gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), job->model); + + g_object_unref (job); + priv->job = NULL; +} + +static void +ev_sidebar_layers_set_document (EvSidebarPage *sidebar_page, + EvDocument *document) +{ + EvSidebarLayers *sidebar_layers; + EvSidebarLayersPrivate *priv; + + g_return_if_fail (EV_IS_SIDEBAR_PAGE (sidebar_page)); + g_return_if_fail (EV_IS_DOCUMENT (document)); + + sidebar_layers = EV_SIDEBAR_LAYERS (sidebar_page); + + priv = sidebar_layers->priv; + + if (priv->document) { + gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), NULL); + g_object_unref (priv->document); + } + + priv->document = g_object_ref (document); + + if (priv->job) { + g_signal_handlers_disconnect_by_func (priv->job, + job_finished_callback, + sidebar_layers); + g_object_unref (priv->job); + } + + priv->job = ev_job_layers_new (document); + g_signal_connect (priv->job, "finished", + G_CALLBACK (job_finished_callback), + sidebar_layers); + /* The priority doesn't matter for this job */ + ev_job_scheduler_push_job (priv->job, EV_JOB_PRIORITY_NONE); +} + +static gboolean +ev_sidebar_layers_support_document (EvSidebarPage *sidebar_page, + EvDocument *document) +{ + return (EV_IS_DOCUMENT_LAYERS (document) && + ev_document_layers_has_layers (EV_DOCUMENT_LAYERS (document))); +} + +static const gchar* +ev_sidebar_layers_get_label (EvSidebarPage *sidebar_page) +{ + return _("Layers"); +} + +static void +ev_sidebar_layers_page_iface_init (EvSidebarPageIface *iface) +{ + iface->support_document = ev_sidebar_layers_support_document; + iface->set_document = ev_sidebar_layers_set_document; + iface->get_label = ev_sidebar_layers_get_label; +} + diff --git a/shell/ev-sidebar-layers.h b/shell/ev-sidebar-layers.h new file mode 100644 index 00000000..f974d79f --- /dev/null +++ b/shell/ev-sidebar-layers.h @@ -0,0 +1,58 @@ +/* ev-sidebar-layers.h + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2008 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_LAYERS_H__ +#define __EV_SIDEBAR_LAYERS_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _EvSidebarLayers EvSidebarLayers; +typedef struct _EvSidebarLayersClass EvSidebarLayersClass; +typedef struct _EvSidebarLayersPrivate EvSidebarLayersPrivate; + +#define EV_TYPE_SIDEBAR_LAYERS (ev_sidebar_layers_get_type()) +#define EV_SIDEBAR_LAYERS(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_SIDEBAR_LAYERS, EvSidebarLayers)) +#define EV_SIDEBAR_LAYERS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_SIDEBAR_LAYERS, EvSidebarLayersClass)) +#define EV_IS_SIDEBAR_LAYERS(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_SIDEBAR_LAYERS)) +#define EV_IS_SIDEBAR_LAYERS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_SIDEBAR_LAYERS)) +#define EV_SIDEBAR_LAYERS_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_SIDEBAR_LAYERS, EvSidebarLayersClass)) + +struct _EvSidebarLayers { + GtkVBox base_instance; + + EvSidebarLayersPrivate *priv; +}; + +struct _EvSidebarLayersClass { + GtkVBoxClass base_class; + + /* Signals */ + void (* layers_visibility_changed) (EvSidebarLayers *ev_layers); +}; + +GType ev_sidebar_layers_get_type (void) G_GNUC_CONST; +GtkWidget *ev_sidebar_layers_new (void); + +G_END_DECLS + +#endif /* __EV_SIDEBAR_LAYERS_H__ */ diff --git a/shell/ev-view.c b/shell/ev-view.c index 41efa337..9c575d27 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -220,6 +220,9 @@ static void draw_one_page (EvView static void draw_loading_text (EvView *view, GdkRectangle *page_area, GdkRectangle *expose_area); +static void ev_view_reload_page (EvView *view, + gint page, + GdkRegion *region); /*** Callbacks ***/ static void job_finished_cb (EvPixbufCache *pixbuf_cache, @@ -1703,11 +1706,7 @@ ev_view_form_field_button_create_widget (EvView *view, break; } - ev_pixbuf_cache_reload_page (view->pixbuf_cache, - field_region, - field->page->index, - view->rotation, - view->scale); + ev_view_reload_page (view, field->page->index, field_region); gdk_region_destroy (field_region); return NULL; @@ -1733,11 +1732,7 @@ ev_view_form_field_text_save (EvView *view, ev_document_forms_form_field_text_set_text (EV_DOCUMENT_FORMS (view->document), field, field_text->text); field->changed = FALSE; - ev_pixbuf_cache_reload_page (view->pixbuf_cache, - field_region, - field->page->index, - view->rotation, - view->scale); + ev_view_reload_page (view, field->page->index, field_region); gdk_region_destroy (field_region); } } @@ -1854,11 +1849,7 @@ ev_view_form_field_choice_save (EvView *view, } } field->changed = FALSE; - ev_pixbuf_cache_reload_page (view->pixbuf_cache, - field_region, - field->page->index, - view->rotation, - view->scale); + ev_view_reload_page (view, field->page->index, field_region); gdk_region_destroy (field_region); } } @@ -4471,6 +4462,25 @@ ev_view_set_document (EvView *view, } } +static void +ev_view_reload_page (EvView *view, + gint page, + GdkRegion *region) +{ + ev_pixbuf_cache_reload_page (view->pixbuf_cache, + region, + page, + view->rotation, + view->scale); +} + +void +ev_view_reload (EvView *view) +{ + ev_pixbuf_cache_clear (view->pixbuf_cache); + view_update_range_and_current_page (view); +} + /*** Zoom and sizing mode ***/ #define EPSILON 0.0000001 @@ -5871,7 +5881,7 @@ ev_view_previous_page (EvView *view) return FALSE; } } - + /*** Enum description for usage in signal ***/ GType diff --git a/shell/ev-view.h b/shell/ev-view.h index 424cecc9..d41edd1b 100644 --- a/shell/ev-view.h +++ b/shell/ev-view.h @@ -58,6 +58,8 @@ void ev_view_set_document (EvView *view, EvDocument *document); void ev_view_set_loading (EvView *view, gboolean loading); +void ev_view_reload (EvView *view); + /* Clipboard */ void ev_view_copy (EvView *view); void ev_view_copy_link_address (EvView *view, diff --git a/shell/ev-window.c b/shell/ev-window.c index 2e2e1bc3..ef96dce5 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -81,6 +81,7 @@ #include "ev-sidebar-links.h" #include "ev-sidebar-page.h" #include "ev-sidebar-thumbnails.h" +#include "ev-sidebar-layers.h" #include "ev-stock-icons.h" #include "ev-utils.h" #include "ev-view.h" @@ -129,6 +130,7 @@ struct _EvWindowPrivate { GtkWidget *sidebar_thumbs; GtkWidget *sidebar_links; GtkWidget *sidebar_attachments; + GtkWidget *sidebar_layers; /* Dialogs */ GtkWidget *properties; @@ -211,6 +213,7 @@ struct _EvWindowPrivate { #define LINKS_SIDEBAR_ID "links" #define THUMBNAILS_SIDEBAR_ID "thumbnails" #define ATTACHMENTS_SIDEBAR_ID "attachments" +#define LAYERS_SIDEBAR_ID "layers" static const gchar *document_print_settings[] = { GTK_PRINT_SETTINGS_N_COPIES, @@ -906,6 +909,7 @@ setup_sidebar_from_metadata (EvWindow *window, EvDocument *document) GtkWidget *links = window->priv->sidebar_links; GtkWidget *thumbs = window->priv->sidebar_thumbs; GtkWidget *attachments = window->priv->sidebar_attachments; + GtkWidget *layers = window->priv->sidebar_layers; GValue sidebar_size = { 0, }; GValue sidebar_page = { 0, }; GValue sidebar_visibility = { 0, }; @@ -916,19 +920,29 @@ setup_sidebar_from_metadata (EvWindow *window, EvDocument *document) g_value_unset(&sidebar_size); } - if (document && ev_metadata_manager_get (uri, "sidebar_page", &sidebar_page, FALSE)) { + if (document && ev_metadata_manager_get (uri, "sidebar_page", &sidebar_page, TRUE)) { const char *page_id = g_value_get_string (&sidebar_page); - + if (strcmp (page_id, LINKS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) { ev_sidebar_set_page (EV_SIDEBAR (sidebar), links); - } else if (strcmp (page_id, THUMBNAILS_SIDEBAR_ID) && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (thumbs), document)) { + } else if (strcmp (page_id, THUMBNAILS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (thumbs), document)) { ev_sidebar_set_page (EV_SIDEBAR (sidebar), thumbs); - } else if (strcmp (page_id, ATTACHMENTS_SIDEBAR_ID) && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (attachments), document)) { + } else if (strcmp (page_id, ATTACHMENTS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (attachments), document)) { 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); } g_value_unset (&sidebar_page); - } else if (document && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) { - ev_sidebar_set_page (EV_SIDEBAR (sidebar), links); + } else if (document) { + if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) { + ev_sidebar_set_page (EV_SIDEBAR (sidebar), links); + } else if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (thumbs), document)) { + ev_sidebar_set_page (EV_SIDEBAR (sidebar), thumbs); + } else if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (attachments), document)) { + 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); + } } if (ev_metadata_manager_get (uri, "sidebar_visibility", &sidebar_visibility, FALSE)) { @@ -3819,6 +3833,8 @@ ev_window_sidebar_current_page_changed_cb (EvSidebar *ev_sidebar, id = THUMBNAILS_SIDEBAR_ID; } else if (current_page == ev_window->priv->sidebar_attachments) { id = ATTACHMENTS_SIDEBAR_ID; + } else if (current_page == ev_window->priv->sidebar_layers) { + id = LAYERS_SIDEBAR_ID; } else { g_assert_not_reached(); } @@ -4592,6 +4608,13 @@ navigation_action_activate_link_cb (EvNavigationAction *action, EvLink *link, Ev gtk_widget_grab_focus (window->priv->view); } +static void +sidebar_layers_visibility_changed (EvSidebarLayers *layers, + EvWindow *window) +{ + ev_view_reload (EV_VIEW (window->priv->view)); +} + static void register_custom_actions (EvWindow *window, GtkActionGroup *group) { @@ -5493,6 +5516,16 @@ ev_window_init (EvWindow *ev_window) ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar), sidebar_widget); + sidebar_widget = ev_sidebar_layers_new (); + ev_window->priv->sidebar_layers = sidebar_widget; + g_signal_connect (sidebar_widget, + "layers_visibility_changed", + G_CALLBACK (sidebar_layers_visibility_changed), + ev_window); + 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,