[evolution/wip/gsettings] Bug #567879 - Add View >> Gallery Option In Email Composer



commit 97fac153c5e0099774de9960ae14a0dced8d7cab
Author: Milan Crha <mcrha redhat com>
Date:   Tue Dec 21 21:11:10 2010 +0100

    Bug #567879 - Add View >> Gallery Option In Email Composer

 composer/e-composer-actions.c        |   16 ++
 composer/e-composer-actions.h        |    2 +
 composer/e-composer-private.c        |   81 ++++++-
 composer/e-composer-private.h        |    5 +-
 composer/e-msg-composer.c            |   32 +++
 composer/evolution-composer.ui       |    6 +
 mail/evolution-mail.schemas.in       |   14 ++
 modules/mail/e-mail-shell-settings.c |    4 +
 widgets/misc/Makefile.am             |    2 +
 widgets/misc/e-picture-gallery.c     |  419 ++++++++++++++++++++++++++++++++++
 widgets/misc/e-picture-gallery.h     |   67 ++++++
 11 files changed, 641 insertions(+), 7 deletions(-)
---
diff --git a/composer/e-composer-actions.c b/composer/e-composer-actions.c
index 3b2aabf..1f1cb44 100644
--- a/composer/e-composer-actions.c
+++ b/composer/e-composer-actions.c
@@ -353,6 +353,14 @@ static GtkToggleActionEntry toggle_entries[] = {
 	  G_CALLBACK (action_pgp_sign_cb),
 	  FALSE },
 
+	{ "picture-gallery",
+	  "emblem-photos",
+	  N_("_Picture Gallery"),
+	  NULL,
+	  N_("Show a collection of pictures that you can drag to your message"),
+	  NULL,  /* no callback */
+	  FALSE },
+
 	{ "prioritize-message",
 	  NULL,
 	  N_("_Prioritize Message"),
@@ -461,9 +469,17 @@ e_composer_actions_init (EMsgComposer *composer)
 		ACTION (ATTACH), "short-label", _("Attach"), NULL);
 
 	g_object_set (
+		ACTION (PICTURE_GALLERY), "is-important", TRUE, NULL);
+
+	g_object_set (
 		ACTION (SAVE_DRAFT), "short-label", _("Save Draft"), NULL);
 
 	g_object_bind_property (
+		composer, "html-mode",
+		ACTION (PICTURE_GALLERY), "sensitive",
+		G_BINDING_SYNC_CREATE);
+
+	g_object_bind_property (
 		web_view, "editable",
 		GTKHTML_EDITOR_ACTION_EDIT_MENU (editor), "sensitive",
 		G_BINDING_SYNC_CREATE);
diff --git a/composer/e-composer-actions.h b/composer/e-composer-actions.h
index 80147a8..4aed102 100644
--- a/composer/e-composer-actions.h
+++ b/composer/e-composer-actions.h
@@ -29,6 +29,8 @@
 	E_COMPOSER_ACTION ((composer), "pgp-encrypt")
 #define E_COMPOSER_ACTION_PGP_SIGN(composer) \
 	E_COMPOSER_ACTION ((composer), "pgp-sign")
+#define E_COMPOSER_ACTION_PICTURE_GALLERY(composer) \
+	E_COMPOSER_ACTION ((composer), "picture-gallery")
 #define E_COMPOSER_ACTION_PRINT(composer) \
 	E_COMPOSER_ACTION ((composer), "print")
 #define E_COMPOSER_ACTION_PRINT_PREVIEW(composer) \
diff --git a/composer/e-composer-private.c b/composer/e-composer-private.c
index f9840bd..816ea10 100644
--- a/composer/e-composer-private.c
+++ b/composer/e-composer-private.c
@@ -20,6 +20,9 @@
 #include "e-composer-private.h"
 #include "e-util/e-util-private.h"
 
+/* Initial height of the picture gallery. */
+#define GALLERY_INITIAL_HEIGHT 150
+
 static void
 composer_setup_charset_menu (EMsgComposer *composer)
 {
@@ -124,12 +127,36 @@ msg_composer_url_requested_cb (GtkHTML *html,
 	g_signal_stop_emission_by_name (html, "url-requested");
 }
 
+static void
+composer_update_gallery_visibility (EMsgComposer *composer)
+{
+	GtkhtmlEditor *editor;
+	GtkToggleAction *toggle_action;
+	gboolean gallery_active;
+	gboolean html_mode;
+
+	editor = GTKHTML_EDITOR (composer);
+	html_mode = gtkhtml_editor_get_html_mode (editor);
+
+	toggle_action = GTK_TOGGLE_ACTION (ACTION (PICTURE_GALLERY));
+	gallery_active = gtk_toggle_action_get_active (toggle_action);
+
+	if (html_mode && gallery_active) {
+		gtk_widget_show (composer->priv->gallery_scrolled_window);
+		gtk_widget_show (composer->priv->gallery_icon_view);
+	} else {
+		gtk_widget_hide (composer->priv->gallery_scrolled_window);
+		gtk_widget_hide (composer->priv->gallery_icon_view);
+	}
+}
+
 void
 e_composer_private_constructed (EMsgComposer *composer)
 {
 	EMsgComposerPrivate *priv = composer->priv;
 	EFocusTracker *focus_tracker;
 	EShell *shell;
+	EShellSettings *shell_settings;
 	EWebView *web_view;
 	GtkhtmlEditor *editor;
 	GtkUIManager *ui_manager;
@@ -140,7 +167,7 @@ e_composer_private_constructed (EMsgComposer *composer)
 	GtkWindow *window;
 	const gchar *path;
 	gboolean small_screen_mode;
-	gchar *filename;
+	gchar *filename, *gallery_path;
 	gint ii;
 	GError *error = NULL;
 
@@ -148,6 +175,7 @@ e_composer_private_constructed (EMsgComposer *composer)
 	ui_manager = gtkhtml_editor_get_ui_manager (editor);
 
 	shell = e_msg_composer_get_shell (composer);
+	shell_settings = e_shell_get_shell_settings (shell);
 	web_view = e_msg_composer_get_web_view (composer);
 	small_screen_mode = e_shell_get_small_screen_mode (shell);
 
@@ -289,6 +317,7 @@ e_composer_private_constructed (EMsgComposer *composer)
 		e_attachment_paned_set_default_height (75); /* short attachment bar for Anjal */
 		e_attachment_icon_view_set_default_icon_size (GTK_ICON_SIZE_BUTTON);
 	}
+
 	widget = e_attachment_paned_new ();
 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 	priv->attachment_paned = g_object_ref (widget);
@@ -354,18 +383,53 @@ e_composer_private_constructed (EMsgComposer *composer)
 		gtk_box_pack_end (GTK_BOX (container), tmp_box, FALSE, FALSE, 3);
 	}
 
-	g_object_set_data ((GObject *)composer, "vbox", editor->vbox);
+	container = e_attachment_paned_get_content_area (
+		E_ATTACHMENT_PANED (priv->attachment_paned));
+
+	widget = gtk_vpaned_new ();
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (
+		GTK_SCROLLED_WINDOW (widget),
+		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (
+		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+	gtk_widget_set_size_request (widget, -1, GALLERY_INITIAL_HEIGHT);
+	gtk_paned_pack1 (GTK_PANED (container), widget, FALSE, FALSE);
+	priv->gallery_scrolled_window = g_object_ref (widget);
+	gtk_widget_show (widget);
 
 	/* Reparent the scrolled window containing the GtkHTML widget
 	 * into the content area of the top attachment pane. */
 
 	widget = GTK_WIDGET (web_view);
 	widget = gtk_widget_get_parent (widget);
-	container = e_attachment_paned_get_content_area (
-		E_ATTACHMENT_PANED (priv->attachment_paned));
 	gtk_widget_reparent (widget, container);
-	gtk_box_set_child_packing (
-		GTK_BOX (container), widget, TRUE, TRUE, 0, GTK_PACK_START);
+
+	/* Construct the picture gallery. */
+
+	container = priv->gallery_scrolled_window;
+
+	gallery_path = e_shell_settings_get_string (shell_settings, "composer-gallery-path");
+	widget = e_picture_gallery_new (gallery_path);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	priv->gallery_icon_view = g_object_ref (widget);
+	g_free (gallery_path);
+
+	g_signal_connect (
+		composer, "notify::html-mode",
+		G_CALLBACK (composer_update_gallery_visibility), NULL);
+
+	g_signal_connect_swapped (
+		ACTION (PICTURE_GALLERY), "toggled",
+		G_CALLBACK (composer_update_gallery_visibility), composer);
+
+	/* XXX What is this for? */
+	g_object_set_data (G_OBJECT (composer), "vbox", editor->vbox);
 
 	composer_setup_recent_menu (composer);
 
@@ -498,6 +562,11 @@ e_composer_private_dispose (EMsgComposer *composer)
 		composer->priv->composer_actions = NULL;
 	}
 
+	if (composer->priv->gallery_scrolled_window != NULL) {
+		g_object_unref (composer->priv->gallery_scrolled_window);
+		composer->priv->gallery_scrolled_window = NULL;
+	}
+
 	g_hash_table_remove_all (composer->priv->inline_images);
 	g_hash_table_remove_all (composer->priv->inline_images_by_url);
 
diff --git a/composer/e-composer-private.h b/composer/e-composer-private.h
index b4818d4..230d2f4 100644
--- a/composer/e-composer-private.h
+++ b/composer/e-composer-private.h
@@ -51,6 +51,7 @@
 #include "widgets/misc/e-attachment-icon-view.h"
 #include "widgets/misc/e-attachment-paned.h"
 #include "widgets/misc/e-attachment-store.h"
+#include "widgets/misc/e-picture-gallery.h"
 #include "widgets/misc/e-signature-combo-box.h"
 #include "widgets/misc/e-web-view.h"
 #include "shell/e-shell.h"
@@ -113,7 +114,6 @@ struct _EMsgComposerPrivate {
 
 	/*** UI Management ***/
 
-	GtkWidget *html_editor;
 	GtkWidget *header_table;
 	GtkWidget *activity_bar;
 	GtkWidget *alert_bar;
@@ -132,6 +132,9 @@ struct _EMsgComposerPrivate {
 
 	GtkWidget *focused_entry;
 
+	GtkWidget *gallery_icon_view;
+	GtkWidget *gallery_scrolled_window;
+
 	GtkWidget *address_dialog;
 
 	GHashTable *inline_images;
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index 227df24..b79eaa3 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -1976,6 +1976,34 @@ msg_composer_finalize (GObject *object)
 }
 
 static void
+msg_composer_gallery_drag_data_get (GtkIconView *icon_view,
+                                    GdkDragContext *context,
+                                    GtkSelectionData *selection_data,
+                                    guint target_type,
+                                    guint time)
+{
+	GtkTreePath *path;
+	GtkCellRenderer *cell;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gchar *str_data;
+
+	if (!gtk_icon_view_get_cursor (icon_view, &path, &cell))
+		return;
+
+	model = gtk_icon_view_get_model (icon_view);
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_model_get (model, &iter, 1, &str_data, -1);
+	gtk_tree_path_free (path);
+
+	/* only supports "text/uri-list" */
+	gtk_selection_data_set (
+		selection_data, selection_data->target, 8,
+		(guchar *) str_data, strlen (str_data));
+	g_free (str_data);
+}
+
+static void
 msg_composer_constructed (GObject *object)
 {
 	EShell *shell;
@@ -2072,6 +2100,10 @@ msg_composer_constructed (GObject *object)
 		web_view, "drag-data-received",
 		G_CALLBACK (msg_composer_drag_data_received_cb), composer);
 
+	g_signal_connect (
+		composer->priv->gallery_icon_view, "drag-data-get",
+		G_CALLBACK (msg_composer_gallery_drag_data_get), NULL);
+
 	/* Configure Headers */
 
 	e_composer_header_table_set_account_list (
diff --git a/composer/evolution-composer.ui b/composer/evolution-composer.ui
index f283d35..d1eb10c 100644
--- a/composer/evolution-composer.ui
+++ b/composer/evolution-composer.ui
@@ -25,6 +25,8 @@
         <menuitem action='view-reply-to'/>
         <menuitem action='view-cc'/>
         <menuitem action='view-bcc'/>
+        <separator/>
+        <menuitem action='picture-gallery'/>
       </menu>
     </placeholder>
     <menu action='insert-menu'>
@@ -56,4 +58,8 @@
       <separator/>
     </placeholder>
   </toolbar>
+  <toolbar name='html-toolbar'>
+    <separator/>
+    <toolitem action='picture-gallery'/>
+  </toolbar>
 </ui>
diff --git a/mail/evolution-mail.schemas.in b/mail/evolution-mail.schemas.in
index 4af7680..1503d7b 100644
--- a/mail/evolution-mail.schemas.in
+++ b/mail/evolution-mail.schemas.in
@@ -346,6 +346,20 @@
       </locale>
     </schema>
 
+    <schema>
+      <key>/schemas/apps/evolution/mail/composer/gallery_path</key>
+      <applyto>/apps/evolution/mail/composer/gallery_path</applyto>
+      <owner>evolution-mail</owner>
+      <type>string</type>
+      <default></default>
+      <locale name="C">
+         <short>Path where image gallery should search for its content</short>
+         <long>This value can be an empty string, which means it'll use
+	 the system Picture folder, usually set to ~/Pictures. This folder will
+	 be also used when the set path is not pointing to the existent folder.</long>
+      </locale>
+    </schema>
+
     <!-- Display Settings -->
 
     <schema>
diff --git a/modules/mail/e-mail-shell-settings.c b/modules/mail/e-mail-shell-settings.c
index 1b70289..18e8407 100644
--- a/modules/mail/e-mail-shell-settings.c
+++ b/modules/mail/e-mail-shell-settings.c
@@ -308,6 +308,10 @@ e_mail_shell_settings_init (EShellBackend *shell_backend)
 		"composer-no-signature-delim",
 		"/apps/evolution/mail/composer/no_signature_delim");
 
+	e_shell_settings_install_property_for_key (
+		"composer-gallery-path",
+		"/apps/evolution/mail/composer/gallery_path");
+
 	/* These properties use transform functions to convert
 	 * GConf values to forms more useful to Evolution.  We
 	 * have to use separate properties because GConfBridge
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am
index 4375c06..7e9ce9c 100644
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@ -44,6 +44,7 @@ widgetsinclude_HEADERS =			\
 	e-menu-tool-button.h			\
 	e-online-button.h			\
 	e-paned.h				\
+	e-picture-gallery.h			\
 	e-popup-action.h			\
 	e-popup-menu.h				\
 	e-preferences-window.h			\
@@ -122,6 +123,7 @@ libemiscwidgets_la_SOURCES =			\
 	e-menu-tool-button.c			\
 	e-online-button.c			\
 	e-paned.c				\
+	e-picture-gallery.c			\
 	e-popup-action.c			\
 	e-popup-menu.c				\
 	e-preferences-window.c			\
diff --git a/widgets/misc/e-picture-gallery.c b/widgets/misc/e-picture-gallery.c
new file mode 100644
index 0000000..163a160
--- /dev/null
+++ b/widgets/misc/e-picture-gallery.c
@@ -0,0 +1,419 @@
+/*
+ * 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)
+ *
+ */
+
+#include "e-util/e-icon-factory.h"
+
+#include "e-picture-gallery.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_for_display ((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 (gallery != NULL);
+	g_return_if_fail (gallery->priv != NULL);
+	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 (gallery != NULL);
+	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)
+{
+	g_return_if_fail (gallery != NULL);
+	g_return_if_fail (gallery->priv != NULL);
+
+	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)
+{
+	if (G_OBJECT_CLASS (e_picture_gallery_parent_class)->constructed)
+		G_OBJECT_CLASS (e_picture_gallery_parent_class)->constructed (object);
+
+	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);
+
+	g_return_if_fail (gallery != NULL);
+	g_return_if_fail (gallery->priv != NULL);
+
+	if (gallery->priv->monitor) {
+		g_object_unref (gallery->priv->monitor);
+		gallery->priv->monitor = NULL;
+	}
+
+	if (G_OBJECT_CLASS (e_picture_gallery_parent_class)->dispose)
+		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)
+{
+	GtkIconView *icon_view;
+	GtkListStore *list_store;
+	GtkTargetEntry *targets;
+	GtkTargetList *list;
+	gint n_targets;
+
+	gallery->priv = E_PICTURE_GALLERY_GET_PRIVATE (gallery);
+	gallery->priv->initialized = FALSE;
+	gallery->priv->monitor = NULL;
+	picture_gallery_set_path (gallery, NULL);
+
+	icon_view = GTK_ICON_VIEW (gallery);
+
+	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);
+}
+
+GtkWidget *
+e_picture_gallery_new (const gchar *path)
+{
+	return g_object_new (E_TYPE_PICTURE_GALLERY, "path", path, NULL);
+}
diff --git a/widgets/misc/e-picture-gallery.h b/widgets/misc/e-picture-gallery.h
new file mode 100644
index 0000000..6da2329
--- /dev/null
+++ b/widgets/misc/e-picture-gallery.h
@@ -0,0 +1,67 @@
+/*
+ * e-picture-gallery.h
+ *
+ * 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)
+ *
+ */
+
+#ifndef E_PICTURE_GALLERY_H
+#define E_PICTURE_GALLERY_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_PICTURE_GALLERY \
+	(e_picture_gallery_get_type ())
+#define E_PICTURE_GALLERY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_PICTURE_GALLERY, EPictureGallery))
+#define E_PICTURE_GALLERY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_PICTURE_GALLERY, EPictureGalleryClass))
+#define E_IS_PICTURE_GALLERY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_PICTURE_GALLERY))
+#define E_IS_PICTURE_GALLERY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_PICTURE_GALLERY))
+#define E_PICTURE_GALLERY_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_PICTURE_GALLERY, EPictureGalleryClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EPictureGallery EPictureGallery;
+typedef struct _EPictureGalleryClass EPictureGalleryClass;
+typedef struct _EPictureGalleryPrivate EPictureGalleryPrivate;
+
+struct _EPictureGallery {
+	GtkIconView parent;
+	EPictureGalleryPrivate *priv;
+};
+
+struct _EPictureGalleryClass {
+	GtkIconViewClass parent_class;
+};
+
+GType		e_picture_gallery_get_type	(void);
+GtkWidget *	e_picture_gallery_new		(const gchar *path);
+const gchar *	e_picture_gallery_get_path	(EPictureGallery *gallery);
+
+G_END_DECLS
+
+#endif /* E_PICTURE_GALLERY_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]