]> www.fi.muni.cz Git - evince.git/commitdiff
Added missing files.
authorCarlos Garcia Campos <carlosgc@gnome.org>
Mon, 3 Apr 2006 09:37:04 +0000 (09:37 +0000)
committerCarlos Garcia Campos <carlosgc@src.gnome.org>
Mon, 3 Apr 2006 09:37:04 +0000 (09:37 +0000)
2006-04-03  Carlos Garcia Campos  <carlosgc@gnome.org>
* backend/ev-attachment.[ch]:
* shell/ev-attachment-bar.[ch]:
Added missing files.

ChangeLog
backend/ev-attachment.c [new file with mode: 0644]
backend/ev-attachment.h [new file with mode: 0644]
shell/ev-attachment-bar.c [new file with mode: 0644]
shell/ev-attachment-bar.h [new file with mode: 0644]

index c1b9d2beb608289540e325c06a11f39a81ec63c5..9198e594216c10e63f752ca41b1658bf05d6a9a2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,11 @@
-2006-04-02  Carlos Garcia Campos  <carlosgc@gnome.org>
+2006-04-03  Carlos Garcia Campos  <carlosgc@gnome.org>
+
+       * backend/ev-attachment.[ch]:
+       * shell/ev-attachment-bar.[ch]:
+
+       Added missing files. 
+
+2006-04-03  Carlos Garcia Campos  <carlosgc@gnome.org>
 
        * backend/Makefile.am:
        * data/evince-ui.xml:
diff --git a/backend/ev-attachment.c b/backend/ev-attachment.c
new file mode 100644 (file)
index 0000000..9d5aaff
--- /dev/null
@@ -0,0 +1,395 @@
+/* this file is part of evince, a gnome document viewer
+ *
+ *  Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * 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 <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libgnomevfs/gnome-vfs-mime-handlers.h>
+#include <libgnomevfs/gnome-vfs-mime-utils.h>
+#include "ev-attachment.h"
+
+enum
+{
+       PROP_0,
+       PROP_NAME,
+       PROP_DESCRIPTION,
+       PROP_MTIME,
+       PROP_CTIME,
+       PROP_SIZE,
+       PROP_DATA
+};
+
+struct _EvAttachmentPrivate {
+       gchar                   *name;
+       gchar                   *description;
+       GTime                    mtime;
+       GTime                    ctime;
+       gsize                    size;
+       gchar                   *data;
+       gchar                   *mime_type;
+
+       GnomeVFSMimeApplication *app;
+       gchar                   *tmp_uri;
+};
+
+#define EV_ATTACHMENT_GET_PRIVATE(object) \
+                (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_ATTACHMENT, EvAttachmentPrivate))
+
+G_DEFINE_TYPE (EvAttachment, ev_attachment, G_TYPE_OBJECT)
+
+GQuark
+ev_attachment_error_quark (void)
+{
+       static GQuark error_quark = 0;
+       
+       if (error_quark == 0)
+               error_quark =
+                       g_quark_from_static_string ("ev-attachment-error-quark");
+       
+       return error_quark;
+}
+
+static void
+ev_attachment_finalize (GObject *object)
+{
+       EvAttachment *attachment = EV_ATTACHMENT (object);
+
+       if (attachment->priv->name) {
+               g_free (attachment->priv->name);
+               attachment->priv->name = NULL;
+       }
+
+       if (attachment->priv->description) {
+               g_free (attachment->priv->description);
+               attachment->priv->description = NULL;
+       }
+
+       if (attachment->priv->data) {
+               g_free (attachment->priv->data);
+               attachment->priv->data = NULL;
+       }
+
+       if (attachment->priv->mime_type) {
+               g_free (attachment->priv->mime_type);
+               attachment->priv->mime_type = NULL;
+       }
+
+       if (attachment->priv->app) {
+               gnome_vfs_mime_application_free (attachment->priv->app);
+               attachment->priv->app = NULL;
+       }
+
+       if (attachment->priv->tmp_uri) {
+               g_unlink (attachment->priv->tmp_uri);
+               g_free (attachment->priv->tmp_uri);
+               attachment->priv->tmp_uri = NULL;
+       }
+
+       (* G_OBJECT_CLASS (ev_attachment_parent_class)->finalize) (object);
+}
+
+static void
+ev_attachment_set_property (GObject      *object,
+                           guint         prop_id,
+                           const GValue *value,
+                           GParamSpec   *param_spec)
+{
+       EvAttachment *attachment = EV_ATTACHMENT (object);
+
+       switch (prop_id) {
+       case PROP_NAME:
+               attachment->priv->name = g_value_dup_string (value);
+               break;
+       case PROP_DESCRIPTION:
+               attachment->priv->description = g_value_dup_string (value);
+               break;
+       case PROP_MTIME:
+               attachment->priv->mtime = g_value_get_ulong (value);
+               break;
+       case PROP_CTIME:
+               attachment->priv->ctime = g_value_get_ulong (value);
+               break;
+       case PROP_SIZE:
+               attachment->priv->size = g_value_get_uint (value);
+               break;
+       case PROP_DATA:
+               attachment->priv->data = g_value_get_pointer (value);
+               attachment->priv->mime_type =
+                       g_strdup (gnome_vfs_get_mime_type_for_data (attachment->priv->data,
+                                                                   attachment->priv->size));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+                                                  prop_id,
+                                                  param_spec);
+               break;
+       }
+}
+
+static void
+ev_attachment_class_init (EvAttachmentClass *klass)
+{
+       GObjectClass *g_object_class;
+
+       g_object_class = G_OBJECT_CLASS (klass);
+
+       g_object_class->set_property = ev_attachment_set_property;
+
+       g_type_class_add_private (g_object_class, sizeof (EvAttachmentPrivate));
+
+       /* Properties */
+       g_object_class_install_property (g_object_class,
+                                        PROP_NAME,
+                                        g_param_spec_string ("name",
+                                                             "Name",
+                                                             "The attachment name",
+                                                             NULL,
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (g_object_class,
+                                        PROP_DESCRIPTION,
+                                        g_param_spec_string ("description",
+                                                             "Description",
+                                                             "The attachment description",
+                                                             NULL,
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (g_object_class,
+                                        PROP_MTIME,
+                                        g_param_spec_ulong ("mtime",
+                                                            "ModifiedTime", 
+                                                            "The attachment modification date",
+                                                            0, G_MAXULONG, 0,
+                                                            G_PARAM_WRITABLE |
+                                                            G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (g_object_class,
+                                        PROP_CTIME,
+                                        g_param_spec_ulong ("ctime",
+                                                            "CreationTime",
+                                                            "The attachment creation date",
+                                                            0, G_MAXULONG, 0,
+                                                            G_PARAM_WRITABLE |
+                                                            G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (g_object_class,
+                                        PROP_SIZE,
+                                        g_param_spec_uint ("size",
+                                                           "Size",
+                                                           "The attachment size",
+                                                           0, G_MAXUINT, 0,
+                                                           G_PARAM_WRITABLE |
+                                                           G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (g_object_class,
+                                        PROP_DATA,
+                                        g_param_spec_pointer ("data",
+                                                              "Data",
+                                                              "The attachment data",
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY));
+       
+       g_object_class->finalize = ev_attachment_finalize;
+}
+
+static void
+ev_attachment_init (EvAttachment *attachment)
+{
+       attachment->priv = EV_ATTACHMENT_GET_PRIVATE (attachment);
+
+       attachment->priv->name = NULL;
+       attachment->priv->description = NULL;
+       attachment->priv->data = NULL;
+       attachment->priv->mime_type = NULL;
+
+       attachment->priv->tmp_uri = NULL;
+}
+
+EvAttachment *
+ev_attachment_new (const gchar *name,
+                  const gchar *description,
+                  GTime        mtime,
+                  GTime        ctime,
+                  gsize        size,
+                  gpointer     data)
+{
+       EvAttachment *attachment;
+
+       attachment = g_object_new (EV_TYPE_ATTACHMENT,
+                                  "name", name,
+                                  "description", description,
+                                  "mtime", mtime,
+                                  "ctime", ctime,
+                                  "size", size,
+                                  "data", data,
+                                  NULL);
+
+       return attachment;
+}
+
+const gchar *
+ev_attachment_get_name (EvAttachment *attachment)
+{
+       g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
+
+       return attachment->priv->name;
+}
+
+const gchar *
+ev_attachment_get_description (EvAttachment *attachment)
+{
+       g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
+
+       return attachment->priv->description;
+}
+
+GTime
+ev_attachment_get_modification_date (EvAttachment *attachment)
+{
+       g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), 0);
+
+       return attachment->priv->mtime;
+}
+
+GTime
+ev_attachment_get_creation_date (EvAttachment *attachment)
+{
+       g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), 0);
+
+       return attachment->priv->ctime;
+}
+
+const gchar *
+ev_attachment_get_mime_type (EvAttachment *attachment)
+{
+       g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
+
+       return attachment->priv->mime_type;
+}
+
+gboolean
+ev_attachment_save (EvAttachment *attachment,
+                   const gchar  *uri,
+                   GError      **error)
+{
+       GnomeVFSHandle  *handle = NULL;
+       GnomeVFSFileSize written;
+       GnomeVFSResult   result;
+       
+       g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       result = gnome_vfs_create (&handle, uri,
+                                  GNOME_VFS_OPEN_WRITE |
+                                  GNOME_VFS_OPEN_TRUNCATE,
+                                  FALSE, 0644);
+       if (result != GNOME_VFS_OK) {
+               g_set_error (error,
+                            EV_ATTACHMENT_ERROR, 
+                            (gint) result,
+                            _("Couldn't save attachment '%s': %s"),
+                            uri, 
+                            gnome_vfs_result_to_string (result));
+               
+               return FALSE;
+       }
+
+       result = gnome_vfs_write (handle, attachment->priv->data,
+                                 attachment->priv->size, &written);
+       if (result != GNOME_VFS_OK || written < attachment->priv->size){
+               g_set_error (error,
+                            EV_ATTACHMENT_ERROR,
+                            (gint) result,
+                            _("Couldn't save attachment '%s': %s"),
+                            uri,
+                            gnome_vfs_result_to_string (result));
+               
+               gnome_vfs_close (handle);
+
+               return FALSE;
+       }
+
+       gnome_vfs_close (handle);
+
+       return TRUE;
+}
+
+static gboolean
+ev_attachment_launch_app (EvAttachment *attachment,
+                         GError      **error)
+{
+       GnomeVFSResult result;
+       GList         *uris = NULL;
+
+       g_assert (attachment->priv->tmp_uri != NULL);
+       g_assert (attachment->priv->app != NULL);
+
+       uris = g_list_prepend (uris, attachment->priv->tmp_uri);
+       result = gnome_vfs_mime_application_launch (attachment->priv->app,
+                                                   uris);
+
+       if (result != GNOME_VFS_OK) {
+               g_set_error (error,
+                            EV_ATTACHMENT_ERROR,
+                            (gint) result,
+                            _("Couldn't open attachment '%s': %s"),
+                            attachment->priv->name,
+                            gnome_vfs_result_to_string (result));
+
+               g_list_free (uris);
+               
+               return FALSE;
+       }
+
+       g_list_free (uris);
+       
+       return TRUE;
+}
+
+gboolean
+ev_attachment_open (EvAttachment *attachment,
+                   GError      **error)
+{
+
+       gboolean retval = FALSE;
+
+       if (!attachment->priv->app)
+               attachment->priv->app =
+                       gnome_vfs_mime_get_default_application (attachment->priv->mime_type);
+
+       if (attachment->priv->tmp_uri &&
+           g_file_test (attachment->priv->tmp_uri, G_FILE_TEST_EXISTS)) {
+               retval = ev_attachment_launch_app (attachment, error);
+       } else {
+               gchar *uri, *filename;
+               
+               filename = g_build_filename (g_get_tmp_dir (), attachment->priv->name, NULL);
+               uri = g_filename_to_uri (filename, NULL, NULL);
+
+               if (ev_attachment_save (attachment, uri, error)) {
+                       if (attachment->priv->tmp_uri)
+                               g_free (attachment->priv->tmp_uri);
+                       attachment->priv->tmp_uri = g_strdup (filename);
+
+                       retval = ev_attachment_launch_app (attachment, error);
+               }
+
+               g_free (filename);
+               g_free (uri);
+       }
+
+       return retval;
+}
diff --git a/backend/ev-attachment.h b/backend/ev-attachment.h
new file mode 100644 (file)
index 0000000..994b654
--- /dev/null
@@ -0,0 +1,72 @@
+/* this file is part of evince, a gnome document viewer
+ *
+ *  Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * 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_ATTACHMENT_H__
+#define __EV_ATTACHMENT_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EvAttachment        EvAttachment;
+typedef struct _EvAttachmentClass   EvAttachmentClass;
+typedef struct _EvAttachmentPrivate EvAttachmentPrivate;
+
+#define EV_TYPE_ATTACHMENT              (ev_attachment_get_type())
+#define EV_ATTACHMENT(object)           (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_ATTACHMENT, EvAttachment))
+#define EV_ATTACHMENT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_ATTACHMENT, EvAttachmentClass))
+#define EV_IS_ATTACHMENT(object)        (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_ATTACHMENT))
+#define EV_IS_ATTACHMENT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_ATTACHMENT))
+#define EV_ATTACHMENT_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_ATTACHMENT, EvAttachmentClass))
+
+#define EV_ATTACHMENT_ERROR (ev_attachment_error_quark ())
+
+struct _EvAttachment {
+       GObject base_instance;
+       
+       EvAttachmentPrivate *priv;
+};
+
+struct _EvAttachmentClass {
+       GObjectClass base_class;
+};
+
+GType         ev_attachment_get_type             (void) G_GNUC_CONST;
+GQuark        ev_attachment_error_quark          (void) G_GNUC_CONST;
+EvAttachment *ev_attachment_new                  (const gchar  *name,
+                                                 const gchar  *description,
+                                                 GTime         mtime,
+                                                 GTime         ctime,
+                                                 gsize         size,
+                                                 gpointer      data);
+
+const gchar *ev_attachment_get_name              (EvAttachment *attachment);
+const gchar *ev_attachment_get_description       (EvAttachment *attachment);
+GTime        ev_attachment_get_modification_date (EvAttachment *attachment);
+GTime        ev_attachment_get_creation_date     (EvAttachment *attachment);
+const gchar *ev_attachment_get_mime_type         (EvAttachment *attachment);
+gboolean     ev_attachment_save                  (EvAttachment *attachment,
+                                                 const gchar  *uri,
+                                                 GError      **error);
+gboolean     ev_attachment_open                  (EvAttachment *attachment,
+                                                 GError      **error);
+
+G_END_DECLS
+
+#endif /* __EV_ATTACHMENT_H__ */
diff --git a/shell/ev-attachment-bar.c b/shell/ev-attachment-bar.c
new file mode 100644 (file)
index 0000000..26e0687
--- /dev/null
@@ -0,0 +1,592 @@
+/* ev-attachment-bar.c
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2006 Carlos Garcia Campos
+ *
+ * Author:
+ *   Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * 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 <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include <libgnomeui/gnome-icon-lookup.h>
+
+#include "ev-attachment-bar.h"
+
+#define MIN_HEIGHT 92
+
+enum {
+       COLUMN_ICON,
+       COLUMN_NAME,
+       COLUMN_DESCRIPTION,
+       COLUMN_ATTACHMENT,
+       N_COLS
+};
+
+enum {
+       SIGNAL_POPUP_MENU,
+       N_SIGNALS
+};
+
+static const GtkTargetEntry drag_targets[] = {
+       { "text/uri-list", 0, 0 }
+};
+
+static guint signals[N_SIGNALS];
+
+struct _EvAttachmentBarPrivate {
+       GtkWidget      *label;
+       GtkWidget      *icon_view;
+       GtkListStore   *model;
+
+       /* Icons */
+       GtkIconTheme   *icon_theme;
+       GHashTable     *icon_cache;
+};
+
+G_DEFINE_TYPE (EvAttachmentBar, ev_attachment_bar, GTK_TYPE_EXPANDER)
+
+#define EV_ATTACHMENT_BAR_GET_PRIVATE(object) \
+                (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_ATTACHMENT_BAR, EvAttachmentBarPrivate))
+
+/* Icon cache */
+static void
+ev_attachment_bar_icon_cache_add (EvAttachmentBar *ev_attachbar,
+                                 const gchar     *mime_type,
+                                 const GdkPixbuf *pixbuf)
+{
+       g_assert (mime_type != NULL);
+       g_assert (GDK_IS_PIXBUF (pixbuf));
+
+       g_hash_table_insert (ev_attachbar->priv->icon_cache,
+                            (gpointer)g_strdup (mime_type),
+                            (gpointer)pixbuf);
+                            
+}
+
+static GdkPixbuf *
+icon_theme_get_pixbuf_from_mime_type (GtkIconTheme *icon_theme,
+                                     const gchar  *mime_type)
+{
+       GdkPixbuf *pixbuf = NULL;
+       gchar     *icon;
+
+       icon = gnome_icon_lookup (icon_theme,
+                                 NULL, NULL,
+                                 NULL, NULL,
+                                 mime_type,
+                                 GNOME_ICON_LOOKUP_FLAGS_NONE,
+                                 NULL);
+
+       pixbuf = gtk_icon_theme_load_icon (icon_theme,
+                                          icon, 48, 0, NULL);
+       g_free (icon);
+
+       return pixbuf;
+}
+
+static GdkPixbuf *
+ev_attachment_bar_icon_cache_get (EvAttachmentBar *ev_attachbar,
+                                 const gchar     *mime_type)
+{
+       GdkPixbuf *pixbuf = NULL;
+       
+       g_assert (mime_type != NULL);
+
+       pixbuf = g_hash_table_lookup (ev_attachbar->priv->icon_cache,
+                                     mime_type);
+
+       if (GDK_IS_PIXBUF (pixbuf))
+               return pixbuf;
+
+       pixbuf = icon_theme_get_pixbuf_from_mime_type (ev_attachbar->priv->icon_theme,
+                                                      mime_type);
+
+       if (GDK_IS_PIXBUF (pixbuf))
+               ev_attachment_bar_icon_cache_add (ev_attachbar,
+                                                 mime_type,
+                                                 pixbuf);
+
+       return pixbuf;
+}
+
+static gboolean
+icon_cache_update_icon (gchar           *key,
+                       GdkPixbuf       *value,
+                       EvAttachmentBar *ev_attachbar)
+{
+       GdkPixbuf *pixbuf = NULL;
+
+       pixbuf = icon_theme_get_pixbuf_from_mime_type (ev_attachbar->priv->icon_theme,
+                                                      key);
+
+       ev_attachment_bar_icon_cache_add (ev_attachbar,
+                                         key,
+                                         pixbuf);
+       
+       return FALSE;
+}
+
+static void
+ev_attachment_bar_icon_cache_refresh (EvAttachmentBar *ev_attachbar)
+{
+       g_hash_table_foreach_remove (ev_attachbar->priv->icon_cache,
+                                    (GHRFunc) icon_cache_update_icon,
+                                    ev_attachbar);
+}
+
+static void
+ev_attachment_bar_toggled (GObject    *object,
+                          GParamSpec *param_spec,
+                          gpointer    user_data)
+{
+       EvAttachmentBar *attachbar = EV_ATTACHMENT_BAR (object);
+       GtkExpander     *expander = GTK_EXPANDER (object);
+
+       if (!attachbar->priv->label)
+               return;
+       
+       if (gtk_expander_get_expanded (expander)) {
+               gtk_label_set_text (GTK_LABEL (attachbar->priv->label),
+                                   _("Hide attachments bar"));
+       } else {
+               gtk_label_set_text (GTK_LABEL (attachbar->priv->label),
+                                   _("Show attachments bar"));
+       }
+}
+
+static EvAttachment *
+ev_attachment_bar_get_attachment_at_pos (EvAttachmentBar *ev_attachbar,
+                                        gint             x,
+                                        gint             y)
+{
+       GtkTreePath  *path = NULL;
+       GtkTreeIter   iter;
+       EvAttachment *attachment = NULL;
+
+       path = gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
+                                             x, y);
+       if (!path) {
+               return NULL;
+       }
+
+       gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model),
+                                &iter, path);
+       gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
+                           COLUMN_ATTACHMENT, &attachment,
+                           -1);
+
+       gtk_icon_view_select_path (GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
+                                  path);
+       
+       gtk_tree_path_free (path);
+
+       return attachment;
+}
+
+static gboolean
+ev_attachment_bar_button_press (EvAttachmentBar *ev_attachbar,
+                               GdkEventButton  *event,
+                               GtkWidget       *icon_view)
+{
+       EvAttachment *attachment;
+       gboolean      handled = FALSE;
+
+       if (!GTK_WIDGET_HAS_FOCUS (icon_view)) {
+               gtk_widget_grab_focus (icon_view);
+       }
+       
+       if (event->button == 2)
+               return FALSE;
+
+       attachment = ev_attachment_bar_get_attachment_at_pos (ev_attachbar,
+                                                             event->x,
+                                                             event->y);
+       if (!attachment)
+               return FALSE;
+
+       switch (event->button) {
+       case 1:
+               if (event->type == GDK_2BUTTON_PRESS) {
+                       GError *error = NULL;
+
+                       ev_attachment_open (attachment, &error);
+
+                       if (error) {
+                               g_warning (error->message);
+                               g_error_free (error);
+                       }
+                                           
+                       handled = TRUE;
+               }
+               break;
+       case 3:
+               g_signal_emit (ev_attachbar, signals[SIGNAL_POPUP_MENU], 0, attachment);
+               handled = TRUE;
+               
+               break;
+       }
+
+       g_object_unref (attachment);
+
+       return handled;
+}
+
+static gboolean
+ev_attachment_bar_focus_in (GtkWidget     *widget,
+                           GdkEventFocus *event)
+{
+       EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (widget);
+
+       if (gtk_expander_get_expanded (GTK_EXPANDER (ev_attachbar)))
+               gtk_widget_grab_focus (ev_attachbar->priv->icon_view);
+
+       return TRUE;
+}
+
+static gboolean
+ev_attachment_bar_popup_menu (GtkWidget *widget)
+{
+       EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (widget);
+       EvAttachment    *attachment;
+       gint             x, y;
+
+       gtk_widget_get_pointer (widget, &x, &y);
+       attachment = ev_attachment_bar_get_attachment_at_pos (ev_attachbar,
+                                                             x, y);
+       if (!attachment)
+               return FALSE;
+
+       g_signal_emit (ev_attachbar, signals[SIGNAL_POPUP_MENU], 0, attachment);
+
+       return TRUE;
+}
+
+static void
+ev_attachment_bar_update_icons (EvAttachmentBar *ev_attachbar,
+                               gpointer         user_data)
+{
+       GtkTreeIter iter;
+       gboolean    valid;
+
+       ev_attachment_bar_icon_cache_refresh (ev_attachbar);
+       
+       valid = gtk_tree_model_get_iter_first (
+               GTK_TREE_MODEL (ev_attachbar->priv->model),
+               &iter);
+
+       while (valid) {
+               EvAttachment *attachment = NULL;
+               GdkPixbuf    *pixbuf = NULL;
+               const gchar  *mime_type;
+
+               gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
+                                   COLUMN_ATTACHMENT, &attachment,
+                                   -1);
+
+               mime_type = ev_attachment_get_mime_type (attachment);
+
+               if (attachment)
+                       g_object_unref (attachment);
+
+               pixbuf = ev_attachment_bar_icon_cache_get (ev_attachbar,
+                                                          mime_type);
+
+               gtk_list_store_set (ev_attachbar->priv->model, &iter,
+                                   COLUMN_ICON, pixbuf,
+                                   -1);
+
+               valid = gtk_tree_model_iter_next (
+                       GTK_TREE_MODEL (ev_attachbar->priv->model),
+                       &iter);
+       }
+}
+
+static void
+ev_attachment_bar_drag_data_get (GtkWidget        *widget,
+                                GdkDragContext   *drag_context,
+                                GtkSelectionData *data,
+                                guint             info,
+                                guint             time,
+                                gpointer          user_data)
+{
+       EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (user_data);
+       EvAttachment    *attachment;
+       GtkTreePath     *path;
+       GtkTreeIter      iter;
+       GList           *selected = NULL;
+       gchar           *uri, *filename;
+       GError          *error = NULL;
+
+       selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (ev_attachbar->priv->icon_view));
+       if (!selected)
+               return;
+
+       path = (GtkTreePath *) selected->data;
+
+       gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model),
+                                &iter, path);
+       gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
+                           COLUMN_ATTACHMENT, &attachment,
+                           -1);
+
+       filename = g_build_filename (g_get_tmp_dir (),
+                                    ev_attachment_get_name (attachment),
+                                    NULL);
+       uri = g_filename_to_uri (filename, NULL, NULL);
+
+       g_object_set_data_full (G_OBJECT (drag_context),
+                               "tmp-filename", filename,
+                               g_free);
+       
+       
+       if (ev_attachment_save (attachment, uri, &error)) {
+               gtk_selection_data_set (data,
+                                       data->target,
+                                       8,
+                                       (guchar *)uri,
+                                       strlen (uri));
+       }
+       
+       if (error) {
+               g_warning (error->message);
+               g_error_free (error);
+       }
+
+       g_free (uri);
+       g_object_unref (attachment);
+       g_list_foreach (selected,
+                       (GFunc) gtk_tree_path_free,
+                       NULL);
+       g_list_free (selected);
+}
+
+static void
+ev_attachment_bar_drag_data_delete (GtkWidget      *widget,
+                                   GdkDragContext *drag_context,
+                                   gpointer        user_data)
+{
+       gchar *filename;
+
+       filename = g_object_get_data (G_OBJECT (drag_context), "tmp-filename");
+       
+       if (filename && g_file_test (filename, G_FILE_TEST_EXISTS))
+               g_unlink (filename);
+}
+
+static void
+ev_attachment_bar_destroy (GtkObject *object)
+{
+       EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (object);
+
+       if (ev_attachbar->priv->model) {
+               g_object_unref (ev_attachbar->priv->model);
+               ev_attachbar->priv->model = NULL;
+       }
+
+       if (ev_attachbar->priv->icon_cache) {
+               g_hash_table_destroy (ev_attachbar->priv->icon_cache);
+               ev_attachbar->priv->icon_cache = NULL;
+       }
+
+       (* GTK_OBJECT_CLASS (ev_attachment_bar_parent_class)->destroy) (object);
+}
+
+static void
+ev_attachment_bar_class_init (EvAttachmentBarClass *ev_attachbar_class)
+{
+       GObjectClass   *g_object_class;
+       GtkObjectClass *gtk_object_class;
+       GtkWidgetClass *gtk_widget_class;
+
+       g_object_class = G_OBJECT_CLASS (ev_attachbar_class);
+       gtk_object_class = GTK_OBJECT_CLASS (ev_attachbar_class);
+       gtk_widget_class = GTK_WIDGET_CLASS (ev_attachbar_class);
+
+       gtk_object_class->destroy = ev_attachment_bar_destroy;
+       gtk_widget_class->popup_menu = ev_attachment_bar_popup_menu;
+       gtk_widget_class->focus_in_event = ev_attachment_bar_focus_in;
+
+       g_type_class_add_private (g_object_class, sizeof (EvAttachmentBarPrivate));
+
+       /* Signals */
+       signals[SIGNAL_POPUP_MENU] =
+               g_signal_new ("popup",
+                             G_TYPE_FROM_CLASS (g_object_class),
+                             G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                             G_STRUCT_OFFSET (EvAttachmentBarClass, popup_menu),
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__OBJECT,
+                             G_TYPE_NONE, 1,
+                             G_TYPE_OBJECT);
+}
+
+static void
+ev_attachment_bar_init (EvAttachmentBar *ev_attachbar)
+{
+       GtkWidget *swindow;
+       
+       ev_attachbar->priv = EV_ATTACHMENT_BAR_GET_PRIVATE (ev_attachbar);
+
+       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);
+       gtk_widget_set_size_request (swindow, -1, MIN_HEIGHT);
+
+       /* Data Model */
+       ev_attachbar->priv->model = gtk_list_store_new (N_COLS,
+                                                       GDK_TYPE_PIXBUF, 
+                                                       G_TYPE_STRING,  
+                                                       G_TYPE_STRING,
+                                                       EV_TYPE_ATTACHMENT);
+
+       /* Icon View */
+       ev_attachbar->priv->icon_view =
+               gtk_icon_view_new_with_model (GTK_TREE_MODEL (ev_attachbar->priv->model));
+       gtk_icon_view_set_columns (GTK_ICON_VIEW (ev_attachbar->priv->icon_view), -1);
+       g_object_set (G_OBJECT (ev_attachbar->priv->icon_view),
+                     "text-column", COLUMN_NAME,
+                     "pixbuf-column", COLUMN_ICON,
+                     NULL);
+       g_signal_connect_swapped (G_OBJECT (ev_attachbar->priv->icon_view),
+                                 "button-press-event",
+                                 G_CALLBACK (ev_attachment_bar_button_press),
+                                 (gpointer) ev_attachbar);
+
+       gtk_container_add (GTK_CONTAINER (swindow),
+                          ev_attachbar->priv->icon_view);
+       gtk_widget_show (ev_attachbar->priv->icon_view);
+
+       gtk_container_add (GTK_CONTAINER (ev_attachbar),
+                          swindow);
+       gtk_widget_show (swindow);
+
+       /* Icon Theme */
+       ev_attachbar->priv->icon_theme = gtk_icon_theme_get_default ();
+       g_signal_connect_swapped (G_OBJECT (ev_attachbar->priv->icon_theme),
+                                 "changed",
+                                 G_CALLBACK (ev_attachment_bar_update_icons),
+                                 (gpointer) ev_attachbar);
+
+       /* Icon Cache */
+       ev_attachbar->priv->icon_cache = g_hash_table_new_full (g_str_hash,
+                                                               g_str_equal,
+                                                               g_free,
+                                                               g_object_unref);
+
+       /* Drag and Drop */
+       gtk_icon_view_enable_model_drag_source (
+               GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
+                              GDK_BUTTON1_MASK,
+                              drag_targets,
+                              G_N_ELEMENTS (drag_targets),
+                              GDK_ACTION_MOVE);
+       g_signal_connect (G_OBJECT (ev_attachbar->priv->icon_view),
+                         "drag-data-get",
+                         G_CALLBACK (ev_attachment_bar_drag_data_get),
+                         (gpointer) ev_attachbar);
+       g_signal_connect (G_OBJECT (ev_attachbar->priv->icon_view),
+                         "drag-data-delete",
+                         G_CALLBACK (ev_attachment_bar_drag_data_delete),
+                         (gpointer) ev_attachbar);
+
+       g_signal_connect (G_OBJECT (ev_attachbar),
+                         "notify::expanded",
+                         G_CALLBACK (ev_attachment_bar_toggled),
+                         NULL);
+       
+}
+
+static void
+ev_attachment_bar_setup (EvAttachmentBar *ev_attachbar)
+{
+       GtkWidget *hbox;
+       GtkWidget *image;
+
+       hbox = gtk_hbox_new (FALSE, 6);
+       image = gtk_image_new_from_stock ("gnome-stock-attach",
+                                         GTK_ICON_SIZE_MENU);
+       gtk_box_pack_start (GTK_BOX (hbox),
+                           image,
+                           FALSE, FALSE, 0);
+       gtk_widget_show (image);
+
+       ev_attachbar->priv->label = gtk_label_new (_("Show attachments bar"));
+       gtk_box_pack_start (GTK_BOX (hbox),
+                           ev_attachbar->priv->label,
+                           FALSE, FALSE, 0);
+       gtk_widget_show (ev_attachbar->priv->label);
+
+       gtk_expander_set_label_widget (GTK_EXPANDER (ev_attachbar), hbox);
+       gtk_widget_show (hbox);
+}
+
+GtkWidget *
+ev_attachment_bar_new (void)
+{
+       GtkWidget *ev_attachbar;
+
+       ev_attachbar = g_object_new (EV_TYPE_ATTACHMENT_BAR, NULL);
+
+       ev_attachment_bar_setup (EV_ATTACHMENT_BAR (ev_attachbar));
+
+       return ev_attachbar;
+}
+
+void
+ev_attachment_bar_set_document (EvAttachmentBar *ev_attachbar,
+                               EvDocument      *document)
+{
+       GList *attachments = NULL;
+       GList *l;
+       
+       if (!ev_document_has_attachments (document))
+               return;
+
+       attachments = ev_document_get_attachments (document);
+
+       gtk_list_store_clear (ev_attachbar->priv->model);
+                                          
+       for (l = attachments; l && l->data; l = g_list_next (l)) {
+               EvAttachment *attachment;
+               GtkTreeIter   iter;
+               GdkPixbuf    *pixbuf = NULL;
+               const gchar  *mime_type;
+
+               attachment = EV_ATTACHMENT (l->data);
+
+               mime_type = ev_attachment_get_mime_type (attachment);
+               pixbuf = ev_attachment_bar_icon_cache_get (ev_attachbar,
+                                                          mime_type);
+
+               gtk_list_store_append (ev_attachbar->priv->model, &iter);
+               gtk_list_store_set (ev_attachbar->priv->model, &iter,
+                                   COLUMN_NAME, ev_attachment_get_name (attachment),
+                                   COLUMN_ICON, pixbuf,
+                                   COLUMN_ATTACHMENT, attachment, 
+                                   -1);
+
+               g_object_unref (attachment);
+       }
+
+       g_list_free (attachments);
+}
diff --git a/shell/ev-attachment-bar.h b/shell/ev-attachment-bar.h
new file mode 100644 (file)
index 0000000..4099067
--- /dev/null
@@ -0,0 +1,66 @@
+/* ev-attachment-bar.h
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2006 Carlos Garcia Campos
+ *
+ * Author:
+ *   Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * 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_ATTACHMENT_BAR_H__
+#define __EV_ATTACHMENT_BAR_H__
+
+#include <gtk/gtkexpander.h>
+#include "ev-attachment.h"
+#include "ev-document.h"
+
+G_BEGIN_DECLS
+
+typedef struct _EvAttachmentBar        EvAttachmentBar;
+typedef struct _EvAttachmentBarClass   EvAttachmentBarClass;
+typedef struct _EvAttachmentBarPrivate EvAttachmentBarPrivate;
+
+#define EV_TYPE_ATTACHMENT_BAR              (ev_attachment_bar_get_type())
+#define EV_ATTACHMENT_BAR(object)           (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_ATTACHMENT_BAR, EvAttachmentBar))
+#define EV_ATTACHMENT_BAR_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_ATTACHMENT_BAR, EvAttachmentBarClass))
+#define EV_IS_ATTACHMENT_BAR(object)        (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_ATTACHMENT_BAR))
+#define EV_IS_ATTACHMENT_BAR_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_ATTACHMENT_BAR))
+#define EV_ATTACHMENT_BAR_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_ATTACHMENT_BAR, EvAttachmentBarClass))
+
+struct _EvAttachmentBar {
+       GtkExpander base_instance;
+
+       EvAttachmentBarPrivate *priv;
+};
+
+struct _EvAttachmentBarClass {
+       GtkExpanderClass base_class;
+
+       /* Signals */
+       void (*popup_menu) (EvAttachmentBar *ev_attachbar,
+                           EvAttachment    *attachment);
+};
+
+GType      ev_attachment_bar_get_type     (void) G_GNUC_CONST;
+GtkWidget *ev_attachment_bar_new          (void);
+
+void       ev_attachment_bar_set_document (EvAttachmentBar *ev_attachbar,
+                                          EvDocument      *document);
+
+G_END_DECLS
+
+#endif /* __EV_ATTACHMENT_BAR_H__ */