evolution-3.6.4/widgets/misc/e-picture-gallery.c

No issues found

  1 /*
  2  * e-picture-gallery.c
  3  *
  4  * This program is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) version 3.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 16  *
 17  *
 18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 19  *
 20  */
 21 
 22 #ifdef HAVE_CONFIG_H
 23 #include <config.h>
 24 #endif
 25 
 26 #include "e-util/e-icon-factory.h"
 27 
 28 #include "e-picture-gallery.h"
 29 
 30 #define E_PICTURE_GALLERY_GET_PRIVATE(obj) \
 31 	(G_TYPE_INSTANCE_GET_PRIVATE \
 32 	((obj), E_TYPE_PICTURE_GALLERY, EPictureGalleryPrivate))
 33 
 34 struct _EPictureGalleryPrivate {
 35 	gboolean initialized;
 36 	gchar *path;
 37 	GFileMonitor *monitor;
 38 };
 39 
 40 enum {
 41 	PROP_0,
 42 	PROP_PATH
 43 };
 44 
 45 enum {
 46 	COL_PIXBUF = 0,
 47 	COL_URI,
 48 	COL_FILENAME_TEXT
 49 };
 50 
 51 G_DEFINE_TYPE (EPictureGallery, e_picture_gallery, GTK_TYPE_ICON_VIEW)
 52 
 53 static gboolean
 54 update_file_iter (GtkListStore *list_store,
 55                   GtkTreeIter *iter,
 56                   GFile *file,
 57                   gboolean force_thumbnail_update)
 58 {
 59 	GFileInfo *file_info;
 60 	gchar *uri;
 61 	gboolean res = FALSE;
 62 
 63 	g_return_val_if_fail (list_store != NULL, FALSE);
 64 	g_return_val_if_fail (iter != NULL, FALSE);
 65 	g_return_val_if_fail (file != NULL, FALSE);
 66 
 67 	uri = g_file_get_uri (file);
 68 
 69 	file_info = g_file_query_info (
 70 		file,
 71 		G_FILE_ATTRIBUTE_THUMBNAIL_PATH ","
 72 		G_FILE_ATTRIBUTE_THUMBNAILING_FAILED ","
 73 		G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
 74 		G_FILE_ATTRIBUTE_STANDARD_SIZE,
 75 		G_FILE_QUERY_INFO_NONE,
 76 		NULL,
 77 		NULL);
 78 
 79 	if (file_info != NULL) {
 80 		const gchar *existing_thumb = g_file_info_get_attribute_byte_string (file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
 81 		gchar *new_thumb = NULL;
 82 
 83 		if (!existing_thumb || force_thumbnail_update) {
 84 			gchar *filename;
 85 
 86 			filename = g_file_get_path (file);
 87 			if (filename) {
 88 				new_thumb = e_icon_factory_create_thumbnail (filename);
 89 				if (new_thumb)
 90 					existing_thumb = new_thumb;
 91 				g_free (filename);
 92 			}
 93 		}
 94 
 95 		if (existing_thumb && !g_file_info_get_attribute_boolean (file_info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED)) {
 96 			GdkPixbuf * pixbuf;
 97 
 98 			pixbuf = gdk_pixbuf_new_from_file (existing_thumb, NULL);
 99 
100 			if (pixbuf) {
101 				const gchar *filename;
102 				gchar *filename_text = NULL;
103 				guint64 filesize;
104 
105 				filename = g_file_info_get_attribute_string (file_info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
106 				if (filename) {
107 					filesize = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_STANDARD_SIZE);
108 					if (filesize) {
109 						gchar *tmp = g_format_size_for_display ((goffset) filesize);
110 						filename_text = g_strdup_printf ("%s (%s)", filename, tmp);
111 						g_free (tmp);
112 					}
113 
114 					res = TRUE;
115 					gtk_list_store_set (
116 						list_store, iter,
117 						COL_PIXBUF, pixbuf,
118 						COL_URI, uri,
119 						COL_FILENAME_TEXT, filename_text ? filename_text : filename,
120 						-1);
121 				}
122 
123 				g_object_unref (pixbuf);
124 				g_free (filename_text);
125 			}
126 		}
127 
128 		g_free (new_thumb);
129 	}
130 
131 	g_free (uri);
132 
133 	return res;
134 }
135 
136 static void
137 add_file (GtkListStore *list_store,
138           GFile *file)
139 {
140 	GtkTreeIter iter;
141 
142 	g_return_if_fail (list_store != NULL);
143 	g_return_if_fail (file != NULL);
144 
145 	gtk_list_store_append (list_store, &iter);
146 	if (!update_file_iter (list_store, &iter, file, FALSE))
147 		gtk_list_store_remove (list_store, &iter);
148 }
149 
150 static gboolean
151 find_file_uri (GtkListStore *list_store,
152                const gchar *uri,
153                GtkTreeIter *iter)
154 {
155 	GtkTreeModel *model;
156 
157 	g_return_val_if_fail (list_store != NULL, FALSE);
158 	g_return_val_if_fail (uri != NULL, FALSE);
159 	g_return_val_if_fail (iter != NULL, FALSE);
160 
161 	model = GTK_TREE_MODEL (list_store);
162 	g_return_val_if_fail (model != NULL, FALSE);
163 
164 	if (!gtk_tree_model_get_iter_first (model, iter))
165 		return FALSE;
166 
167 	do {
168 		gchar *iter_uri = NULL;
169 
170 		gtk_tree_model_get (
171 			model, iter,
172 			COL_URI, &iter_uri,
173 			-1);
174 
175 		if (iter_uri && g_ascii_strcasecmp (uri, iter_uri) == 0) {
176 			g_free (iter_uri);
177 			return TRUE;
178 		}
179 
180 		g_free (iter_uri);
181 	} while (gtk_tree_model_iter_next (model, iter));
182 
183 	return FALSE;
184 }
185 
186 static void
187 picture_gallery_dir_changed_cb (GFileMonitor *monitor,
188                                 GFile *file,
189                                 GFile *other_file,
190                                 GFileMonitorEvent event_type,
191                                 EPictureGallery *gallery)
192 {
193 	gchar *uri;
194 	GtkListStore *list_store;
195 	GtkTreeIter iter;
196 
197 	g_return_if_fail (file != NULL);
198 
199 	list_store = GTK_LIST_STORE (gtk_icon_view_get_model (GTK_ICON_VIEW (gallery)));
200 	g_return_if_fail (list_store != NULL);
201 
202 	uri = g_file_get_uri (file);
203 	if (!uri)
204 		return;
205 
206 	switch (event_type) {
207 	case G_FILE_MONITOR_EVENT_CREATED:
208 		if (find_file_uri (list_store, uri, &iter)) {
209 			if (!update_file_iter (list_store, &iter, file, TRUE))
210 				gtk_list_store_remove (list_store, &iter);
211 		} else {
212 			add_file (list_store, file);
213 		}
214 		break;
215 	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
216 		if (find_file_uri (list_store, uri, &iter)) {
217 			if (!update_file_iter (list_store, &iter, file, TRUE))
218 				gtk_list_store_remove (list_store, &iter);
219 		}
220 		break;
221 	case G_FILE_MONITOR_EVENT_DELETED:
222 		if (find_file_uri (list_store, uri, &iter))
223 			gtk_list_store_remove (list_store, &iter);
224 		break;
225 	default:
226 		break;
227 	}
228 
229 	g_free (uri);
230 }
231 
232 static gboolean
233 picture_gallery_start_loading_cb (EPictureGallery *gallery)
234 {
235 	GtkIconView *icon_view;
236 	GtkListStore *list_store;
237 	GDir *dir;
238 	const gchar *dirname;
239 
240 	icon_view = GTK_ICON_VIEW (gallery);
241 	list_store = GTK_LIST_STORE (gtk_icon_view_get_model (icon_view));
242 	g_return_val_if_fail (list_store != NULL, FALSE);
243 
244 	dirname = e_picture_gallery_get_path (gallery);
245 	if (!dirname)
246 		return FALSE;
247 
248 	dir = g_dir_open (dirname, 0, NULL);
249 	if (dir) {
250 		GFile *file;
251 		const gchar *basename;
252 
253 		while ((basename = g_dir_read_name (dir)) != NULL) {
254 			gchar *filename;
255 
256 			filename = g_build_filename (dirname, basename, NULL);
257 			file = g_file_new_for_path (filename);
258 
259 			add_file (list_store, file);
260 
261 			g_free (filename);
262 			g_object_unref (file);
263 		}
264 
265 		g_dir_close (dir);
266 
267 		file = g_file_new_for_path (dirname);
268 		gallery->priv->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
269 		g_object_unref (file);
270 
271 		if (gallery->priv->monitor)
272 			g_signal_connect (
273 				gallery->priv->monitor, "changed",
274 				G_CALLBACK (picture_gallery_dir_changed_cb),
275 				gallery);
276 	}
277 
278 	g_object_unref (icon_view);
279 
280 	return FALSE;
281 }
282 
283 const gchar *
284 e_picture_gallery_get_path (EPictureGallery *gallery)
285 {
286 	g_return_val_if_fail (gallery != NULL, NULL);
287 	g_return_val_if_fail (E_IS_PICTURE_GALLERY (gallery), NULL);
288 	g_return_val_if_fail (gallery->priv != NULL, NULL);
289 
290 	return gallery->priv->path;
291 }
292 
293 static void
294 picture_gallery_set_path (EPictureGallery *gallery,
295                           const gchar *path)
296 {
297 	g_return_if_fail (E_IS_PICTURE_GALLERY (gallery));
298 	g_return_if_fail (gallery->priv != NULL);
299 
300 	g_free (gallery->priv->path);
301 
302 	if (!path || !*path || !g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
303 		gallery->priv->path = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
304 	else
305 		gallery->priv->path = g_strdup (path);
306 }
307 
308 static void
309 picture_gallery_get_property (GObject *object,
310                               guint property_id,
311                               GValue *value,
312                               GParamSpec *pspec)
313 {
314 	switch (property_id) {
315 	case PROP_PATH:
316 		g_value_set_string (value, e_picture_gallery_get_path (E_PICTURE_GALLERY (object)));
317 		return;
318 	}
319 
320 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
321 }
322 
323 static void
324 picture_gallery_set_property (GObject *object,
325                               guint property_id,
326                               const GValue *value,
327                               GParamSpec *pspec)
328 {
329 	switch (property_id) {
330 	case PROP_PATH:
331 		picture_gallery_set_path (E_PICTURE_GALLERY (object), g_value_get_string (value));
332 		return;
333 	}
334 
335 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
336 }
337 
338 static void
339 visible_cb (EPictureGallery *gallery)
340 {
341 	if (!gallery->priv->initialized && gtk_widget_get_visible (GTK_WIDGET (gallery))) {
342 		gallery->priv->initialized = TRUE;
343 
344 		g_idle_add ((GSourceFunc) picture_gallery_start_loading_cb, gallery);
345 	}
346 }
347 
348 static void
349 picture_gallery_constructed (GObject *object)
350 {
351 	GtkIconView *icon_view;
352 	GtkListStore *list_store;
353 	GtkTargetEntry *targets;
354 	GtkTargetList *list;
355 	gint n_targets;
356 
357 	/* Chain up to parent's constructed() method. */
358 	G_OBJECT_CLASS (e_picture_gallery_parent_class)->constructed (object);
359 
360 	icon_view = GTK_ICON_VIEW (object);
361 
362 	list_store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
363 	gtk_icon_view_set_model (icon_view, GTK_TREE_MODEL (list_store));
364 	g_object_unref (list_store);
365 
366 	gtk_icon_view_set_pixbuf_column (icon_view, COL_PIXBUF);
367 	gtk_icon_view_set_text_column (icon_view, COL_FILENAME_TEXT);
368 	gtk_icon_view_set_tooltip_column (icon_view, -1);
369 
370 	list = gtk_target_list_new (NULL, 0);
371 	gtk_target_list_add_uri_targets (list, 0);
372 	targets = gtk_target_table_new_from_list (list, &n_targets);
373 
374 	gtk_icon_view_enable_model_drag_source (
375 		icon_view, GDK_BUTTON1_MASK,
376 		targets, n_targets, GDK_ACTION_COPY);
377 
378 	gtk_target_table_free (targets, n_targets);
379 	gtk_target_list_unref (list);
380 
381 	g_signal_connect (object, "notify::visible", G_CALLBACK (visible_cb), NULL);
382 }
383 
384 static void
385 picture_gallery_dispose (GObject *object)
386 {
387 	EPictureGallery *gallery;
388 
389 	gallery = E_PICTURE_GALLERY (object);
390 
391 	if (gallery->priv->monitor) {
392 		g_object_unref (gallery->priv->monitor);
393 		gallery->priv->monitor = NULL;
394 	}
395 
396 	/* Chain up to parent's dispose() method. */
397 	G_OBJECT_CLASS (e_picture_gallery_parent_class)->dispose (object);
398 }
399 
400 static void
401 e_picture_gallery_class_init (EPictureGalleryClass *class)
402 {
403 	GObjectClass *object_class;
404 
405 	g_type_class_add_private (class, sizeof (EPictureGalleryPrivate));
406 
407 	object_class = G_OBJECT_CLASS (class);
408 	object_class->get_property = picture_gallery_get_property;
409 	object_class->set_property = picture_gallery_set_property;
410 	object_class->constructed = picture_gallery_constructed;
411 	object_class->dispose = picture_gallery_dispose;
412 
413 	g_object_class_install_property (
414 		object_class,
415 		PROP_PATH,
416 		g_param_spec_string (
417 			"path",
418 			"Gallery path",
419 			NULL,
420 			NULL,
421 			G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
422 }
423 
424 static void
425 e_picture_gallery_init (EPictureGallery *gallery)
426 {
427 	gallery->priv = E_PICTURE_GALLERY_GET_PRIVATE (gallery);
428 	gallery->priv->initialized = FALSE;
429 	gallery->priv->monitor = NULL;
430 	picture_gallery_set_path (gallery, NULL);
431 }
432 
433 GtkWidget *
434 e_picture_gallery_new (const gchar *path)
435 {
436 	return g_object_new (E_TYPE_PICTURE_GALLERY, "path", path, NULL);
437 }