aboutsummaryrefslogblamecommitdiffstats
path: root/e-util/e-picture-gallery.c
blob: 71e48e01a0bfb4c9f8504d43c0b47401b715cef8 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11


                      


                                                                           
  



                                                                             
  

                                                                           





                                                        



                    

                              
                           
                         
 



                                                                



















                                                                      



                                                  










                                                         

                                       
























                                                                                                                                 
                                           











                                                                                                                                
                                                                                                




                                                                                                           

                                                                 



















                                                                                                            

                                   











                                                               


                                        















                                                         

                                    














                                                                          




                                                             




                                 










































































                                                                                                          



                                                                            

















                                                                    

                                                   
 











                                                                                                    



                                                










                                                                                                    



                                                  












                                                                                                  









                                                                                           





                                 

                                                                              
 




















                                                                                           
                                                                                           








                                             




                                                        

                                                                          




























                                                                          
                                                                


                                                 






                                                                         
/*
 * 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.
 *
 * 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 General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this 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"
#include "e-misc-utils.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);

    e_signal_connect_notify (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);
}