1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * gtk-file-chooser-preview: image preview widget for the GtkFileChooser.
5 *
6 * Copyright (C) 2004 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 *
21 * Author: Paolo Bacchilega
22 */
23
24 #include <config.h>
25 #include <glib/gi18n.h>
26 #include <gtk/gtk.h>
27 #include "glib-utils.h"
28 #include "gnome-desktop-thumbnail.h"
29 #include "gtk-file-chooser-preview.h"
30
31
32 #define MIN_WIDTH 150
33 #define PREVIEW_SIZE 120
34
35
36 struct _GtkFileChooserPreviewPrivateData {
37 char *uri;
38 GnomeDesktopThumbnailFactory
39 *thumb_factory;
40 GtkWidget *image;
41 GtkWidget *image_info;
42 GdkWindow *bin_window;
43 };
44
45
46 static GtkFrameClass *parent_class = NULL;
47
48 static void gtk_file_chooser_preview_class_init (GtkFileChooserPreviewClass *class);
49 static void gtk_file_chooser_preview_init (GtkFileChooserPreview *preview);
50 static void gtk_file_chooser_preview_finalize (GObject *object);
51
52
53 GType
gtk_file_chooser_preview_get_type()54 gtk_file_chooser_preview_get_type ()
55 {
56 static GType type = 0;
57
58 if (! type) {
59 GTypeInfo type_info = {
60 sizeof (GtkFileChooserPreviewClass),
61 NULL,
62 NULL,
63 (GClassInitFunc) gtk_file_chooser_preview_class_init,
64 NULL,
65 NULL,
66 sizeof (GtkFileChooserPreview),
67 0,
68 (GInstanceInitFunc) gtk_file_chooser_preview_init
69 };
70
71 type = g_type_register_static (GTK_TYPE_FRAME,
72 "GtkFileChooserPreview",
73 &type_info,
74 0);
75 }
76
77 return type;
78 }
79
80
81 static void
gtk_file_chooser_preview_get_preferred_width(GtkWidget * widget,int * minimal_width,int * natural_width)82 gtk_file_chooser_preview_get_preferred_width (GtkWidget *widget,
83 int *minimal_width,
84 int *natural_width)
85 {
86 *minimal_width = *natural_width = MIN_WIDTH;
87 }
88
89
90 static void
gtk_file_chooser_preview_class_init(GtkFileChooserPreviewClass * class)91 gtk_file_chooser_preview_class_init (GtkFileChooserPreviewClass *class)
92 {
93 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
94 GtkWidgetClass *widget_class;
95
96 parent_class = g_type_class_peek_parent (class);
97
98 gobject_class->finalize = gtk_file_chooser_preview_finalize;
99
100 widget_class = (GtkWidgetClass*) class;
101 widget_class->get_preferred_width = gtk_file_chooser_preview_get_preferred_width;
102 }
103
104
105 static void
gtk_file_chooser_preview_init(GtkFileChooserPreview * preview)106 gtk_file_chooser_preview_init (GtkFileChooserPreview *preview)
107 {
108 preview->priv = g_new0 (GtkFileChooserPreviewPrivateData, 1);
109 preview->priv->thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL);
110 preview->priv->uri = NULL;
111 }
112
113
114 static void
gtk_file_chooser_preview_finalize(GObject * object)115 gtk_file_chooser_preview_finalize (GObject *object)
116 {
117 GtkFileChooserPreview *preview;
118
119 g_return_if_fail (object != NULL);
120 g_return_if_fail (GTK_IS_FILE_CHOOSER_PREVIEW (object));
121
122 preview = GTK_FILE_CHOOSER_PREVIEW (object);
123 if (preview->priv != NULL) {
124 _g_object_unref (preview->priv->thumb_factory);
125 g_free (preview->priv->uri);
126
127 g_free (preview->priv);
128 preview->priv = NULL;
129 }
130
131 G_OBJECT_CLASS (parent_class)->finalize (object);
132 }
133
134
135 static void
set_void_preview(GtkFileChooserPreview * preview)136 set_void_preview (GtkFileChooserPreview *preview)
137 {
138 gtk_widget_hide (preview->priv->image);
139 gtk_widget_hide (preview->priv->image_info);
140 gtk_widget_set_sensitive (gtk_bin_get_child (GTK_BIN (preview)), FALSE);
141 }
142
143
144 static void
gtk_file_chooser_preview_construct(GtkFileChooserPreview * preview)145 gtk_file_chooser_preview_construct (GtkFileChooserPreview *preview)
146 {
147 GtkWidget *event_box;
148 GtkWidget *vbox;
149 GtkWidget *button;
150 GtkWidget *label;
151 GtkWidget *vbox2;
152
153 event_box = gtk_event_box_new ();
154 gtk_container_add (GTK_CONTAINER (preview), event_box);
155 gtk_widget_show (event_box);
156
157 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
158 gtk_container_add (GTK_CONTAINER (event_box), vbox);
159 gtk_widget_show (vbox);
160
161 button = gtk_button_new ();
162 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
163 gtk_widget_show (button);
164
165 label = gtk_label_new_with_mnemonic (_("Preview"));
166 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
167 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
168 gtk_label_set_yalign (GTK_LABEL (label), 0.5);
169 gtk_container_add (GTK_CONTAINER (button), label);
170 gtk_widget_show (label);
171
172 g_signal_connect (button, "button_press_event",
173 G_CALLBACK (gtk_true),
174 NULL);
175 g_signal_connect (button, "button_release_event",
176 G_CALLBACK (gtk_true),
177 NULL);
178 g_signal_connect (button, "enter_notify_event",
179 G_CALLBACK (gtk_true),
180 NULL);
181 g_signal_connect (button, "leave_notify_event",
182 G_CALLBACK (gtk_true),
183 NULL);
184
185 vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
186 gtk_widget_show (vbox2);
187 gtk_box_pack_start (GTK_BOX (vbox), vbox2, TRUE, FALSE, 0);
188
189 preview->priv->image = gtk_image_new ();
190 gtk_widget_show (preview->priv->image);
191 gtk_box_pack_start (GTK_BOX (vbox2), preview->priv->image, FALSE, FALSE, 0);
192
193 preview->priv->image_info = gtk_label_new (NULL);
194 gtk_label_set_justify (GTK_LABEL (preview->priv->image_info), GTK_JUSTIFY_CENTER);
195 gtk_label_set_xalign (GTK_LABEL (preview->priv->image_info), 0.5);
196 gtk_label_set_yalign (GTK_LABEL (preview->priv->image_info), 0.5);
197 gtk_widget_hide (preview->priv->image_info);
198 gtk_box_pack_start (GTK_BOX (vbox2), preview->priv->image_info, FALSE, FALSE, 0);
199
200 set_void_preview (preview);
201 }
202
203
204 GtkWidget *
gtk_file_chooser_preview_new(void)205 gtk_file_chooser_preview_new (void)
206 {
207 GtkFileChooserPreview *preview;
208
209 preview = GTK_FILE_CHOOSER_PREVIEW (g_object_new (GTK_TYPE_FILE_CHOOSER_PREVIEW,
210 "shadow", GTK_SHADOW_IN,
211 NULL));
212 gtk_file_chooser_preview_construct (preview);
213 return (GtkWidget*) preview;
214 }
215
216
217 void
gtk_file_chooser_preview_set_uri(GtkFileChooserPreview * preview,const char * uri)218 gtk_file_chooser_preview_set_uri (GtkFileChooserPreview *preview,
219 const char *uri)
220 {
221 GFile *file;
222 GFileInfo *info;
223 GTimeVal timeval;
224 GdkPixbuf *pixbuf;
225 char *thumb_uri;
226
227 g_free (preview->priv->uri);
228 preview->priv->uri = NULL;
229 if (uri == NULL) {
230 set_void_preview (preview);
231 return;
232 }
233
234 preview->priv->uri = g_strdup (uri);
235 file = g_file_new_for_uri (uri);
236 info = g_file_query_info (file, "time::*,standard::content-type,standard::size", G_FILE_QUERY_INFO_NONE, NULL, NULL);
237 if (info == NULL) {
238 set_void_preview (preview);
239 g_object_unref (file);
240 return;
241 }
242
243 g_file_info_get_modification_time (info, &timeval);
244
245 thumb_uri = gnome_desktop_thumbnail_factory_lookup (preview->priv->thumb_factory,
246 uri,
247 timeval.tv_sec);
248 if (thumb_uri != NULL) {
249 pixbuf = gdk_pixbuf_new_from_file (thumb_uri, NULL);
250 }
251 else {
252 pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (preview->priv->thumb_factory, uri, g_file_info_get_content_type (info));
253 if (pixbuf != NULL)
254 gnome_desktop_thumbnail_factory_save_thumbnail (preview->priv->thumb_factory, pixbuf, uri, timeval.tv_sec);
255 else
256 gnome_desktop_thumbnail_factory_create_failed_thumbnail (preview->priv->thumb_factory, uri, timeval.tv_sec);
257 }
258
259 if (pixbuf != NULL) {
260 const char *w, *h;
261 char *size_text, *text;
262
263 w = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Width");
264 h = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Height");
265 size_text = g_format_size (g_file_info_get_size (info));
266 text = g_strconcat (size_text,
267 ((w == NULL)?NULL:"\n"),
268 w, " x ", h, " ", _("pixels"),
269 NULL);
270 g_free (size_text);
271
272 gtk_label_set_markup (GTK_LABEL (preview->priv->image_info), text);
273 g_free (text);
274
275 gtk_image_set_from_pixbuf (GTK_IMAGE (preview->priv->image), pixbuf);
276
277 g_object_unref (pixbuf);
278 gtk_widget_show (preview->priv->image);
279 gtk_widget_show (preview->priv->image_info);
280
281 gtk_widget_set_sensitive (gtk_bin_get_child (GTK_BIN (preview)), TRUE);
282 }
283 else
284 set_void_preview (preview);
285
286 g_object_unref (info);
287 }
288
289
290 const char *
gtk_file_chooser_preview_get_uri(GtkFileChooserPreview * preview)291 gtk_file_chooser_preview_get_uri (GtkFileChooserPreview *preview)
292 {
293 return preview->priv->uri;
294 }
295