diff options
Diffstat (limited to 'e-util/e-picture-gallery.c')
-rw-r--r-- | e-util/e-picture-gallery.c | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/e-util/e-picture-gallery.c b/e-util/e-picture-gallery.c new file mode 100644 index 0000000000..d95a0c907c --- /dev/null +++ b/e-util/e-picture-gallery.c @@ -0,0 +1,437 @@ +/* + * e-picture-gallery.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "e-picture-gallery.h" + +#include "e-icon-factory.h" + +#define E_PICTURE_GALLERY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_PICTURE_GALLERY, EPictureGalleryPrivate)) + +struct _EPictureGalleryPrivate { + gboolean initialized; + gchar *path; + GFileMonitor *monitor; +}; + +enum { + PROP_0, + PROP_PATH +}; + +enum { + COL_PIXBUF = 0, + COL_URI, + COL_FILENAME_TEXT +}; + +G_DEFINE_TYPE (EPictureGallery, e_picture_gallery, GTK_TYPE_ICON_VIEW) + +static gboolean +update_file_iter (GtkListStore *list_store, + GtkTreeIter *iter, + GFile *file, + gboolean force_thumbnail_update) +{ + GFileInfo *file_info; + gchar *uri; + gboolean res = FALSE; + + g_return_val_if_fail (list_store != NULL, FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (file != NULL, FALSE); + + uri = g_file_get_uri (file); + + file_info = g_file_query_info ( + file, + G_FILE_ATTRIBUTE_THUMBNAIL_PATH "," + G_FILE_ATTRIBUTE_THUMBNAILING_FAILED "," + G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," + G_FILE_ATTRIBUTE_STANDARD_SIZE, + G_FILE_QUERY_INFO_NONE, + NULL, + NULL); + + if (file_info != NULL) { + const gchar *existing_thumb = g_file_info_get_attribute_byte_string (file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH); + gchar *new_thumb = NULL; + + if (!existing_thumb || force_thumbnail_update) { + gchar *filename; + + filename = g_file_get_path (file); + if (filename) { + new_thumb = e_icon_factory_create_thumbnail (filename); + if (new_thumb) + existing_thumb = new_thumb; + g_free (filename); + } + } + + if (existing_thumb && !g_file_info_get_attribute_boolean (file_info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED)) { + GdkPixbuf * pixbuf; + + pixbuf = gdk_pixbuf_new_from_file (existing_thumb, NULL); + + if (pixbuf) { + const gchar *filename; + gchar *filename_text = NULL; + guint64 filesize; + + filename = g_file_info_get_attribute_string (file_info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME); + if (filename) { + filesize = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_STANDARD_SIZE); + if (filesize) { + gchar *tmp = g_format_size ((goffset) filesize); + filename_text = g_strdup_printf ("%s (%s)", filename, tmp); + g_free (tmp); + } + + res = TRUE; + gtk_list_store_set ( + list_store, iter, + COL_PIXBUF, pixbuf, + COL_URI, uri, + COL_FILENAME_TEXT, filename_text ? filename_text : filename, + -1); + } + + g_object_unref (pixbuf); + g_free (filename_text); + } + } + + g_free (new_thumb); + } + + g_free (uri); + + return res; +} + +static void +add_file (GtkListStore *list_store, + GFile *file) +{ + GtkTreeIter iter; + + g_return_if_fail (list_store != NULL); + g_return_if_fail (file != NULL); + + gtk_list_store_append (list_store, &iter); + if (!update_file_iter (list_store, &iter, file, FALSE)) + gtk_list_store_remove (list_store, &iter); +} + +static gboolean +find_file_uri (GtkListStore *list_store, + const gchar *uri, + GtkTreeIter *iter) +{ + GtkTreeModel *model; + + g_return_val_if_fail (list_store != NULL, FALSE); + g_return_val_if_fail (uri != NULL, FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + model = GTK_TREE_MODEL (list_store); + g_return_val_if_fail (model != NULL, FALSE); + + if (!gtk_tree_model_get_iter_first (model, iter)) + return FALSE; + + do { + gchar *iter_uri = NULL; + + gtk_tree_model_get ( + model, iter, + COL_URI, &iter_uri, + -1); + + if (iter_uri && g_ascii_strcasecmp (uri, iter_uri) == 0) { + g_free (iter_uri); + return TRUE; + } + + g_free (iter_uri); + } while (gtk_tree_model_iter_next (model, iter)); + + return FALSE; +} + +static void +picture_gallery_dir_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + EPictureGallery *gallery) +{ + gchar *uri; + GtkListStore *list_store; + GtkTreeIter iter; + + g_return_if_fail (file != NULL); + + list_store = GTK_LIST_STORE (gtk_icon_view_get_model (GTK_ICON_VIEW (gallery))); + g_return_if_fail (list_store != NULL); + + uri = g_file_get_uri (file); + if (!uri) + return; + + switch (event_type) { + case G_FILE_MONITOR_EVENT_CREATED: + if (find_file_uri (list_store, uri, &iter)) { + if (!update_file_iter (list_store, &iter, file, TRUE)) + gtk_list_store_remove (list_store, &iter); + } else { + add_file (list_store, file); + } + break; + case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: + if (find_file_uri (list_store, uri, &iter)) { + if (!update_file_iter (list_store, &iter, file, TRUE)) + gtk_list_store_remove (list_store, &iter); + } + break; + case G_FILE_MONITOR_EVENT_DELETED: + if (find_file_uri (list_store, uri, &iter)) + gtk_list_store_remove (list_store, &iter); + break; + default: + break; + } + + g_free (uri); +} + +static gboolean +picture_gallery_start_loading_cb (EPictureGallery *gallery) +{ + GtkIconView *icon_view; + GtkListStore *list_store; + GDir *dir; + const gchar *dirname; + + icon_view = GTK_ICON_VIEW (gallery); + list_store = GTK_LIST_STORE (gtk_icon_view_get_model (icon_view)); + g_return_val_if_fail (list_store != NULL, FALSE); + + dirname = e_picture_gallery_get_path (gallery); + if (!dirname) + return FALSE; + + dir = g_dir_open (dirname, 0, NULL); + if (dir) { + GFile *file; + const gchar *basename; + + while ((basename = g_dir_read_name (dir)) != NULL) { + gchar *filename; + + filename = g_build_filename (dirname, basename, NULL); + file = g_file_new_for_path (filename); + + add_file (list_store, file); + + g_free (filename); + g_object_unref (file); + } + + g_dir_close (dir); + + file = g_file_new_for_path (dirname); + gallery->priv->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + + if (gallery->priv->monitor) + g_signal_connect ( + gallery->priv->monitor, "changed", + G_CALLBACK (picture_gallery_dir_changed_cb), + gallery); + } + + g_object_unref (icon_view); + + return FALSE; +} + +const gchar * +e_picture_gallery_get_path (EPictureGallery *gallery) +{ + g_return_val_if_fail (gallery != NULL, NULL); + g_return_val_if_fail (E_IS_PICTURE_GALLERY (gallery), NULL); + g_return_val_if_fail (gallery->priv != NULL, NULL); + + return gallery->priv->path; +} + +static void +picture_gallery_set_path (EPictureGallery *gallery, + const gchar *path) +{ + g_return_if_fail (E_IS_PICTURE_GALLERY (gallery)); + g_return_if_fail (gallery->priv != NULL); + + g_free (gallery->priv->path); + + if (!path || !*path || !g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) + gallery->priv->path = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)); + else + gallery->priv->path = g_strdup (path); +} + +static void +picture_gallery_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_PATH: + g_value_set_string (value, e_picture_gallery_get_path (E_PICTURE_GALLERY (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +picture_gallery_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_PATH: + picture_gallery_set_path (E_PICTURE_GALLERY (object), g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +visible_cb (EPictureGallery *gallery) +{ + if (!gallery->priv->initialized && gtk_widget_get_visible (GTK_WIDGET (gallery))) { + gallery->priv->initialized = TRUE; + + g_idle_add ((GSourceFunc) picture_gallery_start_loading_cb, gallery); + } +} + +static void +picture_gallery_constructed (GObject *object) +{ + GtkIconView *icon_view; + GtkListStore *list_store; + GtkTargetEntry *targets; + GtkTargetList *list; + gint n_targets; + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_picture_gallery_parent_class)->constructed (object); + + icon_view = GTK_ICON_VIEW (object); + + list_store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); + gtk_icon_view_set_model (icon_view, GTK_TREE_MODEL (list_store)); + g_object_unref (list_store); + + gtk_icon_view_set_pixbuf_column (icon_view, COL_PIXBUF); + gtk_icon_view_set_text_column (icon_view, COL_FILENAME_TEXT); + gtk_icon_view_set_tooltip_column (icon_view, -1); + + list = gtk_target_list_new (NULL, 0); + gtk_target_list_add_uri_targets (list, 0); + targets = gtk_target_table_new_from_list (list, &n_targets); + + gtk_icon_view_enable_model_drag_source ( + icon_view, GDK_BUTTON1_MASK, + targets, n_targets, GDK_ACTION_COPY); + + gtk_target_table_free (targets, n_targets); + gtk_target_list_unref (list); + + g_signal_connect (object, "notify::visible", G_CALLBACK (visible_cb), NULL); +} + +static void +picture_gallery_dispose (GObject *object) +{ + EPictureGallery *gallery; + + gallery = E_PICTURE_GALLERY (object); + + if (gallery->priv->monitor) { + g_object_unref (gallery->priv->monitor); + gallery->priv->monitor = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_picture_gallery_parent_class)->dispose (object); +} + +static void +e_picture_gallery_class_init (EPictureGalleryClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EPictureGalleryPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->get_property = picture_gallery_get_property; + object_class->set_property = picture_gallery_set_property; + object_class->constructed = picture_gallery_constructed; + object_class->dispose = picture_gallery_dispose; + + g_object_class_install_property ( + object_class, + PROP_PATH, + g_param_spec_string ( + "path", + "Gallery path", + NULL, + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +e_picture_gallery_init (EPictureGallery *gallery) +{ + gallery->priv = E_PICTURE_GALLERY_GET_PRIVATE (gallery); + gallery->priv->initialized = FALSE; + gallery->priv->monitor = NULL; + picture_gallery_set_path (gallery, NULL); +} + +GtkWidget * +e_picture_gallery_new (const gchar *path) +{ + return g_object_new (E_TYPE_PICTURE_GALLERY, "path", path, NULL); +} |