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