]> www.fi.muni.cz Git - evince.git/blob - shell/ev-attachment-bar.c
Updated Spanish translation.
[evince.git] / shell / ev-attachment-bar.c
1 /* ev-attachment-bar.c
2  *  this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2006 Carlos Garcia Campos
5  *
6  * Author:
7  *   Carlos Garcia Campos <carlosgc@gnome.org>
8  *
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.
13  *
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.
18  *
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.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <glib/gi18n.h>
29 #include <glib/gstdio.h>
30 #include <gtk/gtk.h>
31 #include <string.h>
32 #include <libgnomeui/gnome-icon-lookup.h>
33
34 #include "ev-attachment-bar.h"
35
36 #define MIN_HEIGHT 92
37
38 enum {
39         COLUMN_ICON,
40         COLUMN_NAME,
41         COLUMN_DESCRIPTION,
42         COLUMN_ATTACHMENT,
43         N_COLS
44 };
45
46 enum {
47         SIGNAL_POPUP_MENU,
48         N_SIGNALS
49 };
50
51 static const GtkTargetEntry drag_targets[] = {
52         { "text/uri-list", 0, 0 }
53 };
54
55 static guint signals[N_SIGNALS];
56
57 struct _EvAttachmentBarPrivate {
58         GtkWidget      *label;
59         GtkWidget      *icon_view;
60         GtkListStore   *model;
61
62         /* Icons */
63         GtkIconTheme   *icon_theme;
64         GHashTable     *icon_cache;
65 };
66
67 G_DEFINE_TYPE (EvAttachmentBar, ev_attachment_bar, GTK_TYPE_EXPANDER)
68
69 #define EV_ATTACHMENT_BAR_GET_PRIVATE(object) \
70                 (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_ATTACHMENT_BAR, EvAttachmentBarPrivate))
71
72 /* Icon cache */
73 static void
74 ev_attachment_bar_icon_cache_add (EvAttachmentBar *ev_attachbar,
75                                   const gchar     *mime_type,
76                                   const GdkPixbuf *pixbuf)
77 {
78         g_assert (mime_type != NULL);
79         g_assert (GDK_IS_PIXBUF (pixbuf));
80
81         g_hash_table_insert (ev_attachbar->priv->icon_cache,
82                              (gpointer)g_strdup (mime_type),
83                              (gpointer)pixbuf);
84                              
85 }
86
87 static GdkPixbuf *
88 icon_theme_get_pixbuf_from_mime_type (GtkIconTheme *icon_theme,
89                                       const gchar  *mime_type)
90 {
91         GdkPixbuf *pixbuf = NULL;
92         gchar     *icon;
93
94         icon = gnome_icon_lookup (icon_theme,
95                                   NULL, NULL,
96                                   NULL, NULL,
97                                   mime_type,
98                                   GNOME_ICON_LOOKUP_FLAGS_NONE,
99                                   NULL);
100
101         pixbuf = gtk_icon_theme_load_icon (icon_theme,
102                                            icon, 48, 0, NULL);
103         g_free (icon);
104
105         return pixbuf;
106 }
107
108 static GdkPixbuf *
109 ev_attachment_bar_icon_cache_get (EvAttachmentBar *ev_attachbar,
110                                   const gchar     *mime_type)
111 {
112         GdkPixbuf *pixbuf = NULL;
113         
114         g_assert (mime_type != NULL);
115
116         pixbuf = g_hash_table_lookup (ev_attachbar->priv->icon_cache,
117                                       mime_type);
118
119         if (GDK_IS_PIXBUF (pixbuf))
120                 return pixbuf;
121
122         pixbuf = icon_theme_get_pixbuf_from_mime_type (ev_attachbar->priv->icon_theme,
123                                                        mime_type);
124
125         if (GDK_IS_PIXBUF (pixbuf))
126                 ev_attachment_bar_icon_cache_add (ev_attachbar,
127                                                   mime_type,
128                                                   pixbuf);
129
130         return pixbuf;
131 }
132
133 static gboolean
134 icon_cache_update_icon (gchar           *key,
135                         GdkPixbuf       *value,
136                         EvAttachmentBar *ev_attachbar)
137 {
138         GdkPixbuf *pixbuf = NULL;
139
140         pixbuf = icon_theme_get_pixbuf_from_mime_type (ev_attachbar->priv->icon_theme,
141                                                        key);
142
143         ev_attachment_bar_icon_cache_add (ev_attachbar,
144                                           key,
145                                           pixbuf);
146         
147         return FALSE;
148 }
149
150 static void
151 ev_attachment_bar_icon_cache_refresh (EvAttachmentBar *ev_attachbar)
152 {
153         g_hash_table_foreach_remove (ev_attachbar->priv->icon_cache,
154                                      (GHRFunc) icon_cache_update_icon,
155                                      ev_attachbar);
156 }
157
158 static void
159 ev_attachment_bar_toggled (GObject    *object,
160                            GParamSpec *param_spec,
161                            gpointer    user_data)
162 {
163         EvAttachmentBar *attachbar = EV_ATTACHMENT_BAR (object);
164         GtkExpander     *expander = GTK_EXPANDER (object);
165
166         if (!attachbar->priv->label)
167                 return;
168         
169         if (gtk_expander_get_expanded (expander)) {
170                 gtk_label_set_text (GTK_LABEL (attachbar->priv->label),
171                                     _("Hide attachments bar"));
172         } else {
173                 gtk_label_set_text (GTK_LABEL (attachbar->priv->label),
174                                     _("Show attachments bar"));
175         }
176 }
177
178 static EvAttachment *
179 ev_attachment_bar_get_attachment_at_pos (EvAttachmentBar *ev_attachbar,
180                                          gint             x,
181                                          gint             y)
182 {
183         GtkTreePath  *path = NULL;
184         GtkTreeIter   iter;
185         EvAttachment *attachment = NULL;
186
187         path = gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
188                                               x, y);
189         if (!path) {
190                 return NULL;
191         }
192
193         gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model),
194                                  &iter, path);
195         gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
196                             COLUMN_ATTACHMENT, &attachment,
197                             -1);
198
199         gtk_icon_view_select_path (GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
200                                    path);
201         
202         gtk_tree_path_free (path);
203
204         return attachment;
205 }
206
207 static gboolean
208 ev_attachment_bar_popup_menu_show (EvAttachmentBar *ev_attachbar,
209                                    gint             x,
210                                    gint             y)
211 {
212         GtkIconView *icon_view;
213         GtkTreePath *path;
214         GList       *selected = NULL, *l;
215         GList       *attach_list = NULL;
216
217         icon_view = GTK_ICON_VIEW (ev_attachbar->priv->icon_view);
218         
219         path = gtk_icon_view_get_path_at_pos (icon_view, x, y);
220         if (!path)
221                 return FALSE;
222
223         if (!gtk_icon_view_path_is_selected (icon_view, path)) {
224                 gtk_icon_view_unselect_all (icon_view);
225                 gtk_icon_view_select_path (icon_view, path);
226         }
227
228         gtk_tree_path_free (path);
229         
230         selected = gtk_icon_view_get_selected_items (icon_view);
231         if (!selected)
232                 return FALSE;
233
234         for (l = selected; l && l->data; l = g_list_next (l)) {
235                 GtkTreeIter   iter;
236                 EvAttachment *attachment = NULL;
237
238                 path = (GtkTreePath *) l->data;
239
240                 gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model),
241                                          &iter, path);
242                 gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
243                                     COLUMN_ATTACHMENT, &attachment,
244                                     -1);
245
246                 if (attachment)
247                         attach_list = g_list_prepend (attach_list, attachment);
248
249                 gtk_tree_path_free (path);
250         }
251
252         g_list_free (selected);
253
254         if (!attach_list)
255                 return FALSE;
256
257         g_signal_emit (ev_attachbar, signals[SIGNAL_POPUP_MENU], 0, attach_list);
258
259         return TRUE;
260 }
261
262 static gboolean
263 ev_attachment_bar_popup_menu (GtkWidget *widget)
264 {
265         EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (widget);
266         gint             x, y;
267
268         gtk_widget_get_pointer (widget, &x, &y);
269
270         return ev_attachment_bar_popup_menu_show (ev_attachbar, x, y);
271 }
272
273 static gboolean
274 ev_attachment_bar_button_press (EvAttachmentBar *ev_attachbar,
275                                 GdkEventButton  *event,
276                                 GtkWidget       *icon_view)
277 {
278         if (!GTK_WIDGET_HAS_FOCUS (icon_view)) {
279                 gtk_widget_grab_focus (icon_view);
280         }
281         
282         if (event->button == 2)
283                 return FALSE;
284
285         switch (event->button) {
286         case 1:
287                 if (event->type == GDK_2BUTTON_PRESS) {
288                         GError *error = NULL;
289                         EvAttachment *attachment;
290
291                         attachment = ev_attachment_bar_get_attachment_at_pos (ev_attachbar,
292                                                                               event->x,
293                                                                               event->y);
294                         if (!attachment)
295                                 return FALSE;
296                         
297                         ev_attachment_open (attachment, &error);
298
299                         if (error) {
300                                 g_warning (error->message);
301                                 g_error_free (error);
302                         }
303
304                         g_object_unref (attachment);
305                                             
306                         return TRUE;
307                 }
308                 break;
309         case 3: 
310                 return ev_attachment_bar_popup_menu_show (ev_attachbar, event->x, event->y);
311         }
312
313         return FALSE;
314 }
315
316 static gboolean
317 ev_attachment_bar_focus_in (GtkWidget     *widget,
318                             GdkEventFocus *event)
319 {
320         EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (widget);
321
322         if (gtk_expander_get_expanded (GTK_EXPANDER (ev_attachbar)))
323                 gtk_widget_grab_focus (ev_attachbar->priv->icon_view);
324
325         return TRUE;
326 }
327
328 static void
329 ev_attachment_bar_update_icons (EvAttachmentBar *ev_attachbar,
330                                 gpointer         user_data)
331 {
332         GtkTreeIter iter;
333         gboolean    valid;
334
335         ev_attachment_bar_icon_cache_refresh (ev_attachbar);
336         
337         valid = gtk_tree_model_get_iter_first (
338                 GTK_TREE_MODEL (ev_attachbar->priv->model),
339                 &iter);
340
341         while (valid) {
342                 EvAttachment *attachment = NULL;
343                 GdkPixbuf    *pixbuf = NULL;
344                 const gchar  *mime_type;
345
346                 gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
347                                     COLUMN_ATTACHMENT, &attachment,
348                                     -1);
349
350                 mime_type = ev_attachment_get_mime_type (attachment);
351
352                 if (attachment)
353                         g_object_unref (attachment);
354
355                 pixbuf = ev_attachment_bar_icon_cache_get (ev_attachbar,
356                                                            mime_type);
357
358                 gtk_list_store_set (ev_attachbar->priv->model, &iter,
359                                     COLUMN_ICON, pixbuf,
360                                     -1);
361
362                 valid = gtk_tree_model_iter_next (
363                         GTK_TREE_MODEL (ev_attachbar->priv->model),
364                         &iter);
365         }
366 }
367
368 static void
369 ev_attachment_bar_drag_data_get (GtkWidget        *widget,
370                                  GdkDragContext   *drag_context,
371                                  GtkSelectionData *data,
372                                  guint             info,
373                                  guint             time,
374                                  gpointer          user_data)
375 {
376         EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (user_data);
377         GString         *uri_list;
378         gchar           *uris = NULL;
379         GList           *selected = NULL, *l;
380
381         selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (ev_attachbar->priv->icon_view));
382         if (!selected)
383                 return;
384
385         uri_list = g_string_new (NULL);
386         
387         for (l = selected; l && l->data; l = g_list_next (l)) {
388                 EvAttachment *attachment;
389                 GtkTreePath  *path;
390                 GtkTreeIter   iter;
391                 gchar        *uri, *filename;
392                 GError       *error = NULL;
393                 
394                 path = (GtkTreePath *) l->data;
395
396                 gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model),
397                                          &iter, path);
398                 gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
399                                     COLUMN_ATTACHMENT, &attachment,
400                                     -1);
401
402                 filename = g_build_filename (g_get_tmp_dir (),
403                                              ev_attachment_get_name (attachment),
404                                              NULL);
405                 
406                 uri = g_filename_to_uri (filename, NULL, NULL);
407
408                 if (ev_attachment_save (attachment, filename, &error)) {
409                         g_string_append (uri_list, uri);
410                         g_string_append_c (uri_list, '\n');
411                 }
412         
413                 if (error) {
414                         g_warning (error->message);
415                         g_error_free (error);
416                 }
417
418                 g_free (uri);
419                 gtk_tree_path_free (path);
420                 g_object_unref (attachment);
421         }
422
423         uris = g_string_free (uri_list, FALSE);
424
425         if (uris) {
426                 gtk_selection_data_set (data,
427                                         data->target,
428                                         8,
429                                         (guchar *)uris,
430                                         strlen (uris));
431         }
432
433         g_list_free (selected);
434 }
435
436 static void
437 ev_attachment_bar_destroy (GtkObject *object)
438 {
439         EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (object);
440
441         if (ev_attachbar->priv->model) {
442                 g_object_unref (ev_attachbar->priv->model);
443                 ev_attachbar->priv->model = NULL;
444         }
445
446         if (ev_attachbar->priv->icon_cache) {
447                 g_hash_table_destroy (ev_attachbar->priv->icon_cache);
448                 ev_attachbar->priv->icon_cache = NULL;
449         }
450
451         (* GTK_OBJECT_CLASS (ev_attachment_bar_parent_class)->destroy) (object);
452 }
453
454 static void
455 ev_attachment_bar_class_init (EvAttachmentBarClass *ev_attachbar_class)
456 {
457         GObjectClass   *g_object_class;
458         GtkObjectClass *gtk_object_class;
459         GtkWidgetClass *gtk_widget_class;
460
461         g_object_class = G_OBJECT_CLASS (ev_attachbar_class);
462         gtk_object_class = GTK_OBJECT_CLASS (ev_attachbar_class);
463         gtk_widget_class = GTK_WIDGET_CLASS (ev_attachbar_class);
464
465         gtk_object_class->destroy = ev_attachment_bar_destroy;
466         gtk_widget_class->popup_menu = ev_attachment_bar_popup_menu;
467         gtk_widget_class->focus_in_event = ev_attachment_bar_focus_in;
468
469         g_type_class_add_private (g_object_class, sizeof (EvAttachmentBarPrivate));
470
471         /* Signals */
472         signals[SIGNAL_POPUP_MENU] =
473                 g_signal_new ("popup",
474                               G_TYPE_FROM_CLASS (g_object_class),
475                               G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
476                               G_STRUCT_OFFSET (EvAttachmentBarClass, popup_menu),
477                               NULL, NULL,
478                               g_cclosure_marshal_VOID__POINTER,
479                               G_TYPE_NONE, 1,
480                               G_TYPE_POINTER);
481 }
482
483 static void
484 ev_attachment_bar_init (EvAttachmentBar *ev_attachbar)
485 {
486         GtkWidget *swindow;
487         
488         ev_attachbar->priv = EV_ATTACHMENT_BAR_GET_PRIVATE (ev_attachbar);
489
490         swindow = gtk_scrolled_window_new (NULL, NULL);
491         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
492                                         GTK_POLICY_NEVER,
493                                         GTK_POLICY_AUTOMATIC);
494         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
495                                              GTK_SHADOW_IN);
496         gtk_widget_set_size_request (swindow, -1, MIN_HEIGHT);
497
498         /* Data Model */
499         ev_attachbar->priv->model = gtk_list_store_new (N_COLS,
500                                                         GDK_TYPE_PIXBUF, 
501                                                         G_TYPE_STRING,  
502                                                         G_TYPE_STRING,
503                                                         EV_TYPE_ATTACHMENT);
504
505         /* Icon View */
506         ev_attachbar->priv->icon_view =
507                 gtk_icon_view_new_with_model (GTK_TREE_MODEL (ev_attachbar->priv->model));
508         gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
509                                           GTK_SELECTION_MULTIPLE);
510         gtk_icon_view_set_columns (GTK_ICON_VIEW (ev_attachbar->priv->icon_view), -1);
511         g_object_set (G_OBJECT (ev_attachbar->priv->icon_view),
512                       "text-column", COLUMN_NAME,
513                       "pixbuf-column", COLUMN_ICON,
514                       NULL);
515         g_signal_connect_swapped (G_OBJECT (ev_attachbar->priv->icon_view),
516                                   "button-press-event",
517                                   G_CALLBACK (ev_attachment_bar_button_press),
518                                   (gpointer) ev_attachbar);
519
520         gtk_container_add (GTK_CONTAINER (swindow),
521                            ev_attachbar->priv->icon_view);
522         gtk_widget_show (ev_attachbar->priv->icon_view);
523
524         gtk_container_add (GTK_CONTAINER (ev_attachbar),
525                            swindow);
526         gtk_widget_show (swindow);
527
528         /* Icon Theme */
529         ev_attachbar->priv->icon_theme = gtk_icon_theme_get_default ();
530         g_signal_connect_swapped (G_OBJECT (ev_attachbar->priv->icon_theme),
531                                   "changed",
532                                   G_CALLBACK (ev_attachment_bar_update_icons),
533                                   (gpointer) ev_attachbar);
534
535         /* Icon Cache */
536         ev_attachbar->priv->icon_cache = g_hash_table_new_full (g_str_hash,
537                                                                 g_str_equal,
538                                                                 g_free,
539                                                                 g_object_unref);
540
541         /* Drag and Drop */
542 #ifdef HAVE_GTK_ICON_VIEW_ENABLE_MODEL_DRAG_SOURCE
543         gtk_icon_view_enable_model_drag_source (
544                 GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
545                                GDK_BUTTON1_MASK,
546                                drag_targets,
547                                G_N_ELEMENTS (drag_targets),
548                                GDK_ACTION_COPY);
549 #endif
550         g_signal_connect (G_OBJECT (ev_attachbar->priv->icon_view),
551                           "drag-data-get",
552                           G_CALLBACK (ev_attachment_bar_drag_data_get),
553                           (gpointer) ev_attachbar);
554
555         g_signal_connect (G_OBJECT (ev_attachbar),
556                           "notify::expanded",
557                           G_CALLBACK (ev_attachment_bar_toggled),
558                           NULL);
559         
560 }
561
562 static void
563 ev_attachment_bar_setup (EvAttachmentBar *ev_attachbar)
564 {
565         GtkWidget *hbox;
566         GtkWidget *image;
567
568         hbox = gtk_hbox_new (FALSE, 6);
569         image = gtk_image_new_from_stock ("gnome-stock-attach",
570                                           GTK_ICON_SIZE_MENU);
571         gtk_box_pack_start (GTK_BOX (hbox),
572                             image,
573                             FALSE, FALSE, 0);
574         gtk_widget_show (image);
575
576         ev_attachbar->priv->label = gtk_label_new (_("Show attachments bar"));
577         gtk_box_pack_start (GTK_BOX (hbox),
578                             ev_attachbar->priv->label,
579                             FALSE, FALSE, 0);
580         gtk_widget_show (ev_attachbar->priv->label);
581
582         gtk_expander_set_label_widget (GTK_EXPANDER (ev_attachbar), hbox);
583         gtk_widget_show (hbox);
584 }
585
586 GtkWidget *
587 ev_attachment_bar_new (void)
588 {
589         GtkWidget *ev_attachbar;
590
591         ev_attachbar = g_object_new (EV_TYPE_ATTACHMENT_BAR, NULL);
592
593         ev_attachment_bar_setup (EV_ATTACHMENT_BAR (ev_attachbar));
594
595         return ev_attachbar;
596 }
597
598 void
599 ev_attachment_bar_set_document (EvAttachmentBar *ev_attachbar,
600                                 EvDocument      *document)
601 {
602         GList *attachments = NULL;
603         GList *l;
604         
605         if (!ev_document_has_attachments (document))
606                 return;
607
608         attachments = ev_document_get_attachments (document);
609
610         gtk_list_store_clear (ev_attachbar->priv->model);
611                                            
612         for (l = attachments; l && l->data; l = g_list_next (l)) {
613                 EvAttachment *attachment;
614                 GtkTreeIter   iter;
615                 GdkPixbuf    *pixbuf = NULL;
616                 const gchar  *mime_type;
617
618                 attachment = EV_ATTACHMENT (l->data);
619
620                 mime_type = ev_attachment_get_mime_type (attachment);
621                 pixbuf = ev_attachment_bar_icon_cache_get (ev_attachbar,
622                                                            mime_type);
623
624                 gtk_list_store_append (ev_attachbar->priv->model, &iter);
625                 gtk_list_store_set (ev_attachbar->priv->model, &iter,
626                                     COLUMN_NAME, ev_attachment_get_name (attachment),
627                                     COLUMN_ICON, pixbuf,
628                                     COLUMN_ATTACHMENT, attachment, 
629                                     -1);
630
631                 g_object_unref (attachment);
632         }
633
634         g_list_free (attachments);
635 }