2 * this file is part of evince, a gnome document viewer
4 * Copyright (C) 2006 Carlos Garcia Campos
7 * Carlos Garcia Campos <carlosgc@gnome.org>
9 * Evince is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * Evince is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
24 #include <glib/gi18n.h>
25 #include <glib/gstdio.h>
28 #include <libgnomeui/gnome-icon-lookup.h>
30 #include "ev-attachment-bar.h"
47 static const GtkTargetEntry drag_targets[] = {
48 { "text/uri-list", 0, 0 }
51 static guint signals[N_SIGNALS];
53 struct _EvAttachmentBarPrivate {
59 GtkIconTheme *icon_theme;
60 GHashTable *icon_cache;
63 G_DEFINE_TYPE (EvAttachmentBar, ev_attachment_bar, GTK_TYPE_EXPANDER)
65 #define EV_ATTACHMENT_BAR_GET_PRIVATE(object) \
66 (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_ATTACHMENT_BAR, EvAttachmentBarPrivate))
70 ev_attachment_bar_icon_cache_add (EvAttachmentBar *ev_attachbar,
71 const gchar *mime_type,
72 const GdkPixbuf *pixbuf)
74 g_assert (mime_type != NULL);
75 g_assert (GDK_IS_PIXBUF (pixbuf));
77 g_hash_table_insert (ev_attachbar->priv->icon_cache,
78 (gpointer)g_strdup (mime_type),
84 icon_theme_get_pixbuf_from_mime_type (GtkIconTheme *icon_theme,
85 const gchar *mime_type)
87 GdkPixbuf *pixbuf = NULL;
90 icon = gnome_icon_lookup (icon_theme,
94 GNOME_ICON_LOOKUP_FLAGS_NONE,
97 pixbuf = gtk_icon_theme_load_icon (icon_theme,
105 ev_attachment_bar_icon_cache_get (EvAttachmentBar *ev_attachbar,
106 const gchar *mime_type)
108 GdkPixbuf *pixbuf = NULL;
110 g_assert (mime_type != NULL);
112 pixbuf = g_hash_table_lookup (ev_attachbar->priv->icon_cache,
115 if (GDK_IS_PIXBUF (pixbuf))
118 pixbuf = icon_theme_get_pixbuf_from_mime_type (ev_attachbar->priv->icon_theme,
121 if (GDK_IS_PIXBUF (pixbuf))
122 ev_attachment_bar_icon_cache_add (ev_attachbar,
130 icon_cache_update_icon (gchar *key,
132 EvAttachmentBar *ev_attachbar)
134 GdkPixbuf *pixbuf = NULL;
136 pixbuf = icon_theme_get_pixbuf_from_mime_type (ev_attachbar->priv->icon_theme,
139 ev_attachment_bar_icon_cache_add (ev_attachbar,
147 ev_attachment_bar_icon_cache_refresh (EvAttachmentBar *ev_attachbar)
149 g_hash_table_foreach_remove (ev_attachbar->priv->icon_cache,
150 (GHRFunc) icon_cache_update_icon,
155 ev_attachment_bar_toggled (GObject *object,
156 GParamSpec *param_spec,
159 EvAttachmentBar *attachbar = EV_ATTACHMENT_BAR (object);
160 GtkExpander *expander = GTK_EXPANDER (object);
162 if (!attachbar->priv->label)
165 if (gtk_expander_get_expanded (expander)) {
166 gtk_label_set_text (GTK_LABEL (attachbar->priv->label),
167 _("Hide attachments bar"));
169 gtk_label_set_text (GTK_LABEL (attachbar->priv->label),
170 _("Show attachments bar"));
174 static EvAttachment *
175 ev_attachment_bar_get_attachment_at_pos (EvAttachmentBar *ev_attachbar,
179 GtkTreePath *path = NULL;
181 EvAttachment *attachment = NULL;
183 path = gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
189 gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model),
191 gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
192 COLUMN_ATTACHMENT, &attachment,
195 gtk_icon_view_select_path (GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
198 gtk_tree_path_free (path);
204 ev_attachment_bar_button_press (EvAttachmentBar *ev_attachbar,
205 GdkEventButton *event,
206 GtkWidget *icon_view)
208 EvAttachment *attachment;
209 gboolean handled = FALSE;
211 if (!GTK_WIDGET_HAS_FOCUS (icon_view)) {
212 gtk_widget_grab_focus (icon_view);
215 if (event->button == 2)
218 attachment = ev_attachment_bar_get_attachment_at_pos (ev_attachbar,
224 switch (event->button) {
226 if (event->type == GDK_2BUTTON_PRESS) {
227 GError *error = NULL;
229 ev_attachment_open (attachment, &error);
232 g_warning (error->message);
233 g_error_free (error);
240 g_signal_emit (ev_attachbar, signals[SIGNAL_POPUP_MENU], 0, attachment);
246 g_object_unref (attachment);
252 ev_attachment_bar_focus_in (GtkWidget *widget,
253 GdkEventFocus *event)
255 EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (widget);
257 if (gtk_expander_get_expanded (GTK_EXPANDER (ev_attachbar)))
258 gtk_widget_grab_focus (ev_attachbar->priv->icon_view);
264 ev_attachment_bar_popup_menu (GtkWidget *widget)
266 EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (widget);
267 EvAttachment *attachment;
270 gtk_widget_get_pointer (widget, &x, &y);
271 attachment = ev_attachment_bar_get_attachment_at_pos (ev_attachbar,
276 g_signal_emit (ev_attachbar, signals[SIGNAL_POPUP_MENU], 0, attachment);
282 ev_attachment_bar_update_icons (EvAttachmentBar *ev_attachbar,
288 ev_attachment_bar_icon_cache_refresh (ev_attachbar);
290 valid = gtk_tree_model_get_iter_first (
291 GTK_TREE_MODEL (ev_attachbar->priv->model),
295 EvAttachment *attachment = NULL;
296 GdkPixbuf *pixbuf = NULL;
297 const gchar *mime_type;
299 gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
300 COLUMN_ATTACHMENT, &attachment,
303 mime_type = ev_attachment_get_mime_type (attachment);
306 g_object_unref (attachment);
308 pixbuf = ev_attachment_bar_icon_cache_get (ev_attachbar,
311 gtk_list_store_set (ev_attachbar->priv->model, &iter,
315 valid = gtk_tree_model_iter_next (
316 GTK_TREE_MODEL (ev_attachbar->priv->model),
322 ev_attachment_bar_drag_data_get (GtkWidget *widget,
323 GdkDragContext *drag_context,
324 GtkSelectionData *data,
329 EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (user_data);
330 EvAttachment *attachment;
333 GList *selected = NULL;
334 gchar *uri, *filename;
335 GError *error = NULL;
337 selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (ev_attachbar->priv->icon_view));
341 path = (GtkTreePath *) selected->data;
343 gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model),
345 gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
346 COLUMN_ATTACHMENT, &attachment,
349 filename = g_build_filename (g_get_tmp_dir (),
350 ev_attachment_get_name (attachment),
352 uri = g_filename_to_uri (filename, NULL, NULL);
354 g_object_set_data_full (G_OBJECT (drag_context),
355 "tmp-filename", filename,
359 if (ev_attachment_save (attachment, uri, &error)) {
360 gtk_selection_data_set (data,
368 g_warning (error->message);
369 g_error_free (error);
373 g_object_unref (attachment);
374 g_list_foreach (selected,
375 (GFunc) gtk_tree_path_free,
377 g_list_free (selected);
381 ev_attachment_bar_drag_data_delete (GtkWidget *widget,
382 GdkDragContext *drag_context,
387 filename = g_object_get_data (G_OBJECT (drag_context), "tmp-filename");
389 if (filename && g_file_test (filename, G_FILE_TEST_EXISTS))
394 ev_attachment_bar_destroy (GtkObject *object)
396 EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (object);
398 if (ev_attachbar->priv->model) {
399 g_object_unref (ev_attachbar->priv->model);
400 ev_attachbar->priv->model = NULL;
403 if (ev_attachbar->priv->icon_cache) {
404 g_hash_table_destroy (ev_attachbar->priv->icon_cache);
405 ev_attachbar->priv->icon_cache = NULL;
408 (* GTK_OBJECT_CLASS (ev_attachment_bar_parent_class)->destroy) (object);
412 ev_attachment_bar_class_init (EvAttachmentBarClass *ev_attachbar_class)
414 GObjectClass *g_object_class;
415 GtkObjectClass *gtk_object_class;
416 GtkWidgetClass *gtk_widget_class;
418 g_object_class = G_OBJECT_CLASS (ev_attachbar_class);
419 gtk_object_class = GTK_OBJECT_CLASS (ev_attachbar_class);
420 gtk_widget_class = GTK_WIDGET_CLASS (ev_attachbar_class);
422 gtk_object_class->destroy = ev_attachment_bar_destroy;
423 gtk_widget_class->popup_menu = ev_attachment_bar_popup_menu;
424 gtk_widget_class->focus_in_event = ev_attachment_bar_focus_in;
426 g_type_class_add_private (g_object_class, sizeof (EvAttachmentBarPrivate));
429 signals[SIGNAL_POPUP_MENU] =
430 g_signal_new ("popup",
431 G_TYPE_FROM_CLASS (g_object_class),
432 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
433 G_STRUCT_OFFSET (EvAttachmentBarClass, popup_menu),
435 g_cclosure_marshal_VOID__OBJECT,
441 ev_attachment_bar_init (EvAttachmentBar *ev_attachbar)
445 ev_attachbar->priv = EV_ATTACHMENT_BAR_GET_PRIVATE (ev_attachbar);
447 swindow = gtk_scrolled_window_new (NULL, NULL);
448 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
450 GTK_POLICY_AUTOMATIC);
451 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
453 gtk_widget_set_size_request (swindow, -1, MIN_HEIGHT);
456 ev_attachbar->priv->model = gtk_list_store_new (N_COLS,
463 ev_attachbar->priv->icon_view =
464 gtk_icon_view_new_with_model (GTK_TREE_MODEL (ev_attachbar->priv->model));
465 gtk_icon_view_set_columns (GTK_ICON_VIEW (ev_attachbar->priv->icon_view), -1);
466 g_object_set (G_OBJECT (ev_attachbar->priv->icon_view),
467 "text-column", COLUMN_NAME,
468 "pixbuf-column", COLUMN_ICON,
470 g_signal_connect_swapped (G_OBJECT (ev_attachbar->priv->icon_view),
471 "button-press-event",
472 G_CALLBACK (ev_attachment_bar_button_press),
473 (gpointer) ev_attachbar);
475 gtk_container_add (GTK_CONTAINER (swindow),
476 ev_attachbar->priv->icon_view);
477 gtk_widget_show (ev_attachbar->priv->icon_view);
479 gtk_container_add (GTK_CONTAINER (ev_attachbar),
481 gtk_widget_show (swindow);
484 ev_attachbar->priv->icon_theme = gtk_icon_theme_get_default ();
485 g_signal_connect_swapped (G_OBJECT (ev_attachbar->priv->icon_theme),
487 G_CALLBACK (ev_attachment_bar_update_icons),
488 (gpointer) ev_attachbar);
491 ev_attachbar->priv->icon_cache = g_hash_table_new_full (g_str_hash,
497 gtk_icon_view_enable_model_drag_source (
498 GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
501 G_N_ELEMENTS (drag_targets),
503 g_signal_connect (G_OBJECT (ev_attachbar->priv->icon_view),
505 G_CALLBACK (ev_attachment_bar_drag_data_get),
506 (gpointer) ev_attachbar);
507 g_signal_connect (G_OBJECT (ev_attachbar->priv->icon_view),
509 G_CALLBACK (ev_attachment_bar_drag_data_delete),
510 (gpointer) ev_attachbar);
512 g_signal_connect (G_OBJECT (ev_attachbar),
514 G_CALLBACK (ev_attachment_bar_toggled),
520 ev_attachment_bar_setup (EvAttachmentBar *ev_attachbar)
525 hbox = gtk_hbox_new (FALSE, 6);
526 image = gtk_image_new_from_stock ("gnome-stock-attach",
528 gtk_box_pack_start (GTK_BOX (hbox),
531 gtk_widget_show (image);
533 ev_attachbar->priv->label = gtk_label_new (_("Show attachments bar"));
534 gtk_box_pack_start (GTK_BOX (hbox),
535 ev_attachbar->priv->label,
537 gtk_widget_show (ev_attachbar->priv->label);
539 gtk_expander_set_label_widget (GTK_EXPANDER (ev_attachbar), hbox);
540 gtk_widget_show (hbox);
544 ev_attachment_bar_new (void)
546 GtkWidget *ev_attachbar;
548 ev_attachbar = g_object_new (EV_TYPE_ATTACHMENT_BAR, NULL);
550 ev_attachment_bar_setup (EV_ATTACHMENT_BAR (ev_attachbar));
556 ev_attachment_bar_set_document (EvAttachmentBar *ev_attachbar,
557 EvDocument *document)
559 GList *attachments = NULL;
562 if (!ev_document_has_attachments (document))
565 attachments = ev_document_get_attachments (document);
567 gtk_list_store_clear (ev_attachbar->priv->model);
569 for (l = attachments; l && l->data; l = g_list_next (l)) {
570 EvAttachment *attachment;
572 GdkPixbuf *pixbuf = NULL;
573 const gchar *mime_type;
575 attachment = EV_ATTACHMENT (l->data);
577 mime_type = ev_attachment_get_mime_type (attachment);
578 pixbuf = ev_attachment_bar_icon_cache_get (ev_attachbar,
581 gtk_list_store_append (ev_attachbar->priv->model, &iter);
582 gtk_list_store_set (ev_attachbar->priv->model, &iter,
583 COLUMN_NAME, ev_attachment_get_name (attachment),
585 COLUMN_ATTACHMENT, attachment,
588 g_object_unref (attachment);
591 g_list_free (attachments);