[evolution] Simplify clipboard handling in addressbook.



commit c12e485e47f5ac99f0ddd7f7e90b9ab28b077c3d
Author: Matthew Barnes <mbarnes redhat com>
Date:   Wed Nov 11 23:52:08 2009 -0500

    Simplify clipboard handling in addressbook.

 addressbook/gui/widgets/e-addressbook-view.c       |  152 ++----
 calendar/gui/Makefile.am                           |    3 -
 calendar/gui/e-cal-selection.c                     |  323 ------------
 calendar/gui/e-calendar-table.c                    |    2 +-
 calendar/gui/e-calendar-view.c                     |    2 +-
 calendar/gui/e-memo-table.c                        |    2 +-
 e-util/Makefile.am                                 |    6 +-
 e-util/e-selection.c                               |  536 ++++++++++++++++++++
 .../gui/e-cal-selection.h => e-util/e-selection.h  |   41 ++-
 modules/addressbook/e-book-shell-content.c         |    6 +
 modules/addressbook/e-book-shell-content.h         |    3 +-
 modules/addressbook/e-book-shell-view.c            |    5 +-
 modules/calendar/e-cal-shell-view-private.h        |    2 +-
 13 files changed, 627 insertions(+), 456 deletions(-)
---
diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c
index 280c4d3..cfff431 100644
--- a/addressbook/gui/widgets/e-addressbook-view.c
+++ b/addressbook/gui/widgets/e-addressbook-view.c
@@ -37,6 +37,7 @@
 #include "ea-addressbook.h"
 
 #include "e-util/e-print.h"
+#include "e-util/e-selection.h"
 #include "e-util/e-util.h"
 #include "libedataserver/e-sexp.h"
 #include <libedataserver/e-categories.h>
@@ -78,15 +79,12 @@ struct _EAddressbookViewPrivate {
 	EAddressbookModel *model;
 	EActivity *activity;
 
-	GList *clipboard_contacts;
 	ESource *source;
 
 	GObject *object;
 	GtkWidget *widget;
 
 	GalViewInstance *view_instance;
-
-	GtkWidget *invisible;
 };
 
 enum {
@@ -116,7 +114,6 @@ static GtkTargetEntry drag_types[] = {
 
 static gpointer parent_class;
 static guint signals[LAST_SIGNAL];
-static GdkAtom clipboard_atom = GDK_NONE;
 
 static void
 addressbook_view_emit_open_contact (EAddressbookView *view,
@@ -402,77 +399,6 @@ addressbook_view_display_view_cb (EAddressbookView *view,
 }
 
 static void
-addressbook_view_selection_get_cb (EAddressbookView *view,
-                                   GtkSelectionData *selection_data,
-                                   guint info,
-                                   guint time_stamp)
-{
-	gchar *string;
-
-	string = eab_contact_list_to_string (view->priv->clipboard_contacts);
-
-	gtk_selection_data_set (
-		selection_data, GDK_SELECTION_TYPE_STRING,
-		8, (guchar *) string, strlen (string));
-
-	g_free (string);
-}
-
-static void
-addressbook_view_selection_clear_event_cb (EAddressbookView *view,
-                                           GdkEventSelection *event)
-{
-	GList *list;
-
-	list = view->priv->clipboard_contacts;
-	view->priv->clipboard_contacts = NULL;
-
-	g_list_foreach (list, (GFunc) g_object_unref, NULL);
-	g_list_free (list);
-}
-
-static void
-addressbook_view_selection_received_cb (EAddressbookView *view,
-                                        GtkSelectionData *selection_data,
-                                        guint time)
-{
-	EAddressbookModel *model;
-	GList *list, *iter;
-	EBook *book;
-
-	model = e_addressbook_view_get_model (view);
-	book = e_addressbook_model_get_book (model);
-
-	if (selection_data->length <= 0)
-		return;
-
-	if (selection_data->type != GDK_SELECTION_TYPE_STRING)
-		return;
-
-	if (selection_data->data[selection_data->length - 1] != 0) {
-		gchar *string;
-
-		string = g_malloc0 (selection_data->length + 1);
-		memcpy (string, selection_data->data, selection_data->length);
-		list = eab_contact_list_from_string (string);
-		g_free (string);
-	} else
-		list = eab_contact_list_from_string (
-			(gchar *) selection_data->data);
-
-	for (iter = list; iter != NULL; iter = iter->next) {
-		EContact *contact = iter->data;
-
-		/* XXX NULL for a callback /sigh */
-		eab_merging_book_add_contact (
-			book, contact, NULL /* XXX */, NULL);
-	}
-
-	g_list_foreach (list, (GFunc) g_object_unref, NULL);
-	g_list_free (list);
-}
-
-static void
 addressbook_view_set_shell_view (EAddressbookView *view,
                                  EShellView *shell_view)
 {
@@ -575,11 +501,6 @@ addressbook_view_dispose (GObject *object)
 		priv->activity = NULL;
 	}
 
-	if (priv->invisible != NULL) {
-		gtk_widget_destroy (priv->invisible);
-		priv->invisible = NULL;
-	}
-
 	if (priv->source != NULL) {
 		g_object_unref (priv->source);
 		priv->source = NULL;
@@ -590,12 +511,6 @@ addressbook_view_dispose (GObject *object)
 		priv->view_instance = NULL;
 	}
 
-	g_list_foreach (
-		priv->clipboard_contacts,
-		(GFunc) g_object_unref, NULL);
-	g_list_free (priv->clipboard_contacts);
-	priv->clipboard_contacts = NULL;
-
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -708,9 +623,6 @@ addressbook_view_class_init (EAddressbookViewClass *class)
 		g_cclosure_marshal_VOID__VOID,
 		G_TYPE_NONE, 0);
 
-	if (clipboard_atom == NULL)
-		clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
-
 	/* init the accessibility support for e_addressbook_view */
 	eab_view_a11y_init ();
 }
@@ -721,22 +633,6 @@ addressbook_view_init (EAddressbookView *view)
 	view->priv = E_ADDRESSBOOK_VIEW_GET_PRIVATE (view);
 
 	view->priv->model = e_addressbook_model_new ();
-
-	view->priv->invisible = gtk_invisible_new ();
-
-	gtk_selection_add_target (
-		view->priv->invisible, clipboard_atom,
-		GDK_SELECTION_TYPE_STRING, 0);
-
-	g_signal_connect_swapped (
-		view->priv->invisible, "selection-get",
-		G_CALLBACK (addressbook_view_selection_get_cb), view);
-	g_signal_connect_swapped (
-		view->priv->invisible, "selection-clear-event",
-		G_CALLBACK (addressbook_view_selection_clear_event_cb), view);
-	g_signal_connect_swapped (
-		view->priv->invisible, "selection-received",
-		G_CALLBACK (addressbook_view_selection_received_cb), view);
 }
 
 GType
@@ -1348,23 +1244,55 @@ e_addressbook_view_cut (EAddressbookView *view)
 void
 e_addressbook_view_copy (EAddressbookView *view)
 {
+	GtkClipboard *clipboard;
+	GList *contact_list;
+	gchar *string;
+
 	g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view));
 
-	view->priv->clipboard_contacts = e_addressbook_view_get_selected (view);
+	clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
 
-	gtk_selection_owner_set (
-		view->priv->invisible,
-		clipboard_atom, GDK_CURRENT_TIME);
+	contact_list = e_addressbook_view_get_selected (view);
+
+	string = eab_contact_list_to_string (contact_list);
+	e_clipboard_set_directory (clipboard, string, -1);
+	g_free (string);
+
+	g_list_foreach (contact_list, (GFunc) g_object_unref, NULL);
+	g_list_free (contact_list);
 }
 
 void
 e_addressbook_view_paste (EAddressbookView *view)
 {
+	EBook *book;
+	EAddressbookModel *model;
+	GtkClipboard *clipboard;
+	GList *contact_list, *iter;
+	gchar *string;
+
 	g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view));
 
-	gtk_selection_convert (
-		view->priv->invisible, clipboard_atom,
-		GDK_SELECTION_TYPE_STRING, GDK_CURRENT_TIME);
+	clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+
+	if (!e_clipboard_wait_is_directory_available (clipboard))
+		return;
+
+	model = e_addressbook_view_get_model (view);
+	book = e_addressbook_model_get_book (model);
+
+	string = e_clipboard_wait_for_directory (clipboard);
+	contact_list = eab_contact_list_from_string (string);
+	g_free (string);
+
+	for (iter = contact_list; iter != NULL; iter = iter->next) {
+		EContact *contact = iter->data;
+
+		eab_merging_book_add_contact (book, contact, NULL, NULL);
+	}
+
+	g_list_foreach (contact_list, (GFunc) g_object_unref, NULL);
+	g_list_free (contact_list);
 }
 
 void
diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am
index fc9c910..dd1357c 100644
--- a/calendar/gui/Makefile.am
+++ b/calendar/gui/Makefile.am
@@ -18,7 +18,6 @@ ecalendarinclude_HEADERS =			\
 	e-cal-event.h				\
 	e-cal-model-calendar.h			\
 	e-cal-model.h				\
-	e-cal-selection.h			\
 	e-calendar-view.h			\
 	e-cell-date-edit-text.h			\
 	e-date-time-list.h                      \
@@ -113,8 +112,6 @@ libevolution_calendar_la_SOURCES = \
 	e-cal-model-memos.h			\
 	e-cal-model-tasks.c			\
 	e-cal-model-tasks.h			\
-	e-cal-selection.c			\
-	e-cal-selection.h			\
 	e-calendar-selector.c			\
 	e-calendar-selector.h			\
 	e-calendar-table.c			\
diff --git a/calendar/gui/e-calendar-table.c b/calendar/gui/e-calendar-table.c
index 3903c58..4ea57c2 100644
--- a/calendar/gui/e-calendar-table.c
+++ b/calendar/gui/e-calendar-table.c
@@ -43,6 +43,7 @@
 #include <table/e-cell-combo.h>
 #include <table/e-cell-date.h>
 #include <e-util/e-binding.h>
+#include <e-util/e-selection.h>
 #include <e-util/e-dialog-utils.h>
 #include <e-util/e-util-private.h>
 #include <table/e-cell-date-edit.h>
@@ -55,7 +56,6 @@
 #include "dialogs/delete-error.h"
 #include "dialogs/task-editor.h"
 #include "e-cal-model-tasks.h"
-#include "e-cal-selection.h"
 #include "e-calendar-table.h"
 #include "e-calendar-view.h"
 #include "e-cell-date-edit-text.h"
diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c
index 0ea84e1..84812d6 100644
--- a/calendar/gui/e-calendar-view.c
+++ b/calendar/gui/e-calendar-view.c
@@ -33,6 +33,7 @@
 #include <libedataserver/e-time-utils.h>
 #include <e-util/e-util.h>
 #include <e-util/e-error.h>
+#include <e-util/e-selection.h>
 #include <e-util/e-datetime-format.h>
 #include <e-util/e-dialog-utils.h>
 #include <e-util/e-icon-factory.h>
@@ -45,7 +46,6 @@
 #include "comp-util.h"
 #include "ea-calendar.h"
 #include "e-cal-model-calendar.h"
-#include "e-cal-selection.h"
 #include "e-calendar-view.h"
 #include "itip-utils.h"
 #include "dialogs/comp-editor-util.h"
diff --git a/calendar/gui/e-memo-table.c b/calendar/gui/e-memo-table.c
index c111bd6..fc4b2c8 100644
--- a/calendar/gui/e-memo-table.c
+++ b/calendar/gui/e-memo-table.c
@@ -42,6 +42,7 @@
 #include <table/e-cell-text.h>
 #include <table/e-cell-combo.h>
 #include <table/e-cell-date.h>
+#include <e-util/e-selection.h>
 #include <e-util/e-dialog-utils.h>
 #include <e-util/e-util-private.h>
 #include <table/e-cell-date-edit.h>
@@ -53,7 +54,6 @@
 #include "dialogs/delete-error.h"
 #include "dialogs/memo-editor.h"
 #include "e-cal-model-memos.h"
-#include "e-cal-selection.h"
 #include "e-memo-table.h"
 #include "e-calendar-view.h"
 #include "e-cell-date-edit-text.h"
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 688c7e7..3014458 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -15,6 +15,7 @@ eutilinclude_HEADERS = 				\
 	e-alert-activity.h			\
 	e-bconf-map.h				\
 	e-binding.h				\
+	e-bit-array.h				\
 	e-categories-config.h			\
 	e-charset.h				\
 	e-config.h				\
@@ -38,10 +39,10 @@ eutilinclude_HEADERS = 				\
 	e-plugin.h				\
 	e-plugin-ui.h				\
 	e-profile-event.h			\
+	e-selection.h				\
 	e-signature.h				\
 	e-signature-list.h			\
 	e-signature-utils.h			\
-	e-bit-array.h				\
 	e-sorter.h				\
 	e-sorter-array.h			\
 	e-text-event-processor-emacs-like.h	\
@@ -88,6 +89,7 @@ libeutil_la_SOURCES =				\
 	e-alert-activity.c			\
 	e-bconf-map.c				\
 	e-binding.c				\
+	e-bit-array.c				\
 	e-categories-config.c			\
 	e-charset.c				\
 	e-config.c				\
@@ -111,10 +113,10 @@ libeutil_la_SOURCES =				\
 	e-plugin.c				\
 	e-print.c				\
 	e-profile-event.c			\
+	e-selection.c				\
 	e-signature.c				\
 	e-signature-list.c			\
 	e-signature-utils.c			\
-	e-bit-array.c				\
 	e-sorter.c				\
 	e-sorter-array.c			\
 	e-text-event-processor-emacs-like.c	\
diff --git a/e-util/e-selection.c b/e-util/e-selection.c
new file mode 100644
index 0000000..8d2efff
--- /dev/null
+++ b/e-util/e-selection.c
@@ -0,0 +1,536 @@
+/*
+ * e-selection.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-selection.h"
+
+#include <string.h>
+
+typedef struct _RequestTextInfo RequestTextInfo;
+typedef struct _WaitForDataResults WaitForDataResults;
+
+struct _RequestTextInfo {
+	GtkClipboardTextReceivedFunc callback;
+	gpointer user_data;
+};
+
+struct _WaitForDataResults {
+	GMainLoop *loop;
+	gpointer data;
+};
+
+enum {
+	ATOM_CALENDAR,
+	ATOM_X_VCALENDAR,
+	NUM_CALENDAR_ATOMS
+};
+
+enum {
+	ATOM_DIRECTORY,
+	ATOM_X_VCARD,
+	NUM_DIRECTORY_ATOMS
+};
+
+static GdkAtom calendar_atoms[NUM_CALENDAR_ATOMS];
+static GdkAtom directory_atoms[NUM_DIRECTORY_ATOMS];
+
+static void
+init_atoms (void)
+{
+	static gboolean initialized = FALSE;
+
+	if (initialized)
+		return;
+
+	/* Calendar Atoms */
+
+	calendar_atoms[ATOM_CALENDAR] =
+		gdk_atom_intern_static_string ("text/calendar");
+
+	calendar_atoms[ATOM_X_VCALENDAR] =
+		gdk_atom_intern_static_string ("text/x-vcalendar");
+
+	/* Directory Atoms */
+
+	directory_atoms[ATOM_DIRECTORY] =
+		gdk_atom_intern_static_string ("text/directory");
+
+	directory_atoms[ATOM_X_VCARD] =
+		gdk_atom_intern_static_string ("text/x-vcard");
+
+	initialized = TRUE;
+}
+
+static void
+clipboard_wait_for_text_cb (GtkClipboard *clipboard,
+                            const gchar *source,
+                            WaitForDataResults *results)
+{
+	results->data = g_strdup (source);
+	g_main_loop_quit (results->loop);
+}
+
+void
+e_target_list_add_calendar_targets (GtkTargetList *list,
+                                    guint info)
+{
+	gint ii;
+
+	g_return_if_fail (list != NULL);
+
+	init_atoms ();
+
+	for (ii = 0; ii < NUM_CALENDAR_ATOMS; ii++)
+		gtk_target_list_add (list, calendar_atoms[ii], 0, info);
+}
+
+void
+e_target_list_add_directory_targets (GtkTargetList *list,
+                                     guint info)
+{
+	gint ii;
+
+	g_return_if_fail (list != NULL);
+
+	init_atoms ();
+
+	for (ii = 0; ii < NUM_DIRECTORY_ATOMS; ii++)
+		gtk_target_list_add (list, directory_atoms[ii], 0, info);
+}
+
+gboolean
+e_selection_data_set_calendar (GtkSelectionData *selection_data,
+                               const gchar *source,
+                               gint length)
+{
+	GdkAtom atom;
+	gint ii;
+
+	g_return_val_if_fail (selection_data != NULL, FALSE);
+
+	if (length < 0)
+		length = strlen (source);
+
+	init_atoms ();
+
+	atom = gtk_selection_data_get_target (selection_data);
+
+	/* All calendar atoms are treated the same. */
+	for (ii = 0; ii < NUM_CALENDAR_ATOMS; ii++) {
+		if (atom == calendar_atoms[ii]) {
+			gtk_selection_data_set (
+				selection_data, atom, 8,
+				(guchar *) source, length);
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+gboolean
+e_selection_data_set_directory (GtkSelectionData *selection_data,
+                                const gchar *source,
+                                gint length)
+{
+	GdkAtom atom;
+	gint ii;
+
+	g_return_val_if_fail (selection_data != NULL, FALSE);
+
+	if (length < 0)
+		length = strlen (source);
+
+	init_atoms ();
+
+	atom = gtk_selection_data_get_target (selection_data);
+
+	/* All directory atoms are treated the same. */
+	for (ii = 0; ii < NUM_DIRECTORY_ATOMS; ii++) {
+		if (atom == directory_atoms[ii]) {
+			gtk_selection_data_set (
+				selection_data, atom, 8,
+				(guchar *) source, length);
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+gchar *
+e_selection_data_get_calendar (GtkSelectionData *selection_data)
+{
+	GdkAtom data_type;
+	const guchar *data = NULL;
+	gint ii;
+
+	/* XXX May need to do encoding and line ending conversions
+	 *     here.  Not worrying about it for now. */
+
+	g_return_val_if_fail (selection_data != NULL, NULL);
+
+	data = gtk_selection_data_get_data (selection_data);
+	data_type = gtk_selection_data_get_data_type (selection_data);
+
+	/* All calendar atoms are treated the same. */
+	for (ii = 0; ii < NUM_CALENDAR_ATOMS; ii++)
+		if (data_type == calendar_atoms[ii])
+			return g_strdup ((gchar *) data);
+
+	return NULL;
+}
+
+gchar *
+e_selection_data_get_directory (GtkSelectionData *selection_data)
+{
+	GdkAtom data_type;
+	const guchar *data = NULL;
+	gint ii;
+
+	/* XXX May need to do encoding and line ending conversions
+	 *     here.  Not worrying about it for now. */
+
+	g_return_val_if_fail (selection_data != NULL, NULL);
+
+	data = gtk_selection_data_get_data (selection_data);
+	data_type = gtk_selection_data_get_data_type (selection_data);
+
+	/* All directory atoms are treated the same. */
+	for (ii = 0; ii < NUM_DIRECTORY_ATOMS; ii++)
+		if (data_type == directory_atoms[ii])
+			return g_strdup ((gchar *) data);
+
+	return NULL;
+}
+
+gboolean
+e_selection_data_targets_include_calendar (GtkSelectionData *selection_data)
+{
+	GdkAtom *targets;
+	gint n_targets;
+	gboolean result = FALSE;
+
+	g_return_val_if_fail (selection_data != NULL, FALSE);
+
+	if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) {
+		result = e_targets_include_calendar (targets, n_targets);
+		g_free (targets);
+	}
+
+	return result;
+}
+
+gboolean
+e_selection_data_targets_include_directory (GtkSelectionData *selection_data)
+{
+	GdkAtom *targets;
+	gint n_targets;
+	gboolean result = FALSE;
+
+	g_return_val_if_fail (selection_data != NULL, FALSE);
+
+	if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) {
+		result = e_targets_include_directory (targets, n_targets);
+		g_free (targets);
+	}
+
+	return result;
+}
+
+gboolean
+e_targets_include_calendar (GdkAtom *targets,
+                            gint n_targets)
+{
+	gint ii, jj;
+
+	g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
+
+	init_atoms ();
+
+	for (ii = 0; ii < n_targets; ii++)
+		for (jj = 0; jj < NUM_CALENDAR_ATOMS; jj++)
+			if (targets[ii] == calendar_atoms[jj])
+				return TRUE;
+
+	return FALSE;
+}
+
+gboolean
+e_targets_include_directory (GdkAtom *targets,
+                             gint n_targets)
+{
+	gint ii, jj;
+
+	g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
+
+	init_atoms ();
+
+	for (ii = 0; ii < n_targets; ii++)
+		for (jj = 0; jj < NUM_DIRECTORY_ATOMS; jj++)
+			if (targets[ii] == directory_atoms[jj])
+				return TRUE;
+
+	return FALSE;
+}
+
+static void
+clipboard_get_calendar (GtkClipboard *clipboard,
+                        GtkSelectionData *selection_data,
+                        guint info,
+                        gchar *source)
+{
+	e_selection_data_set_calendar (selection_data, source, -1);
+}
+
+static void
+clipboard_clear_calendar (GtkClipboard *clipboard,
+                          gchar *source)
+{
+	g_free (source);
+}
+
+void
+e_clipboard_set_calendar (GtkClipboard *clipboard,
+                          const gchar *source,
+                          gint length)
+{
+	GtkTargetList *list;
+	GtkTargetEntry *targets;
+	gint n_targets;
+
+	g_return_if_fail (clipboard != NULL);
+	g_return_if_fail (source != NULL);
+
+	list = gtk_target_list_new (NULL, 0);
+	e_target_list_add_calendar_targets (list, 0);
+
+	targets = gtk_target_table_new_from_list (list, &n_targets);
+
+	if (length < 0)
+		length = strlen (source);
+
+	gtk_clipboard_set_with_data (
+		clipboard, targets, n_targets,
+		(GtkClipboardGetFunc) clipboard_get_calendar,
+		(GtkClipboardClearFunc) clipboard_clear_calendar,
+		g_strndup (source, length));
+
+	gtk_clipboard_set_can_store (clipboard, NULL, 0);
+
+	gtk_target_table_free (targets, n_targets);
+	gtk_target_list_unref (list);
+}
+
+static void
+clipboard_get_directory (GtkClipboard *clipboard,
+                         GtkSelectionData *selection_data,
+                         guint info,
+                         gchar *source)
+{
+	e_selection_data_set_directory (selection_data, source, -1);
+}
+
+static void
+clipboard_clear_directory (GtkClipboard *clipboard,
+                           gchar *source)
+{
+	g_free (source);
+}
+
+void
+e_clipboard_set_directory (GtkClipboard *clipboard,
+                           const gchar *source,
+                           gint length)
+{
+	GtkTargetList *list;
+	GtkTargetEntry *targets;
+	gint n_targets;
+
+	g_return_if_fail (clipboard != NULL);
+	g_return_if_fail (source != NULL);
+
+	list = gtk_target_list_new (NULL, 0);
+	e_target_list_add_directory_targets (list, 0);
+
+	targets = gtk_target_table_new_from_list (list, &n_targets);
+
+	if (length < 0)
+		length = strlen (source);
+
+	gtk_clipboard_set_with_data (
+		clipboard, targets, n_targets,
+		(GtkClipboardGetFunc) clipboard_get_directory,
+		(GtkClipboardClearFunc) clipboard_clear_directory,
+		g_strndup (source, length));
+
+	gtk_clipboard_set_can_store (clipboard, NULL, 0);
+
+	gtk_target_table_free (targets, n_targets);
+	gtk_target_list_unref (list);
+}
+
+static void
+clipboard_request_calendar_cb (GtkClipboard *clipboard,
+                               GtkSelectionData *selection_data,
+                               RequestTextInfo *info)
+{
+	gchar *source;
+
+	source = e_selection_data_get_calendar (selection_data);
+	info->callback (clipboard, source, info->user_data);
+	g_free (source);
+
+	g_slice_free (RequestTextInfo, info);
+}
+
+void
+e_clipboard_request_calendar (GtkClipboard *clipboard,
+                              GtkClipboardTextReceivedFunc callback,
+                              gpointer user_data)
+{
+	RequestTextInfo *info;
+
+	g_return_if_fail (clipboard != NULL);
+	g_return_if_fail (callback != NULL);
+
+	info = g_slice_new (RequestTextInfo);
+	info->callback = callback;
+	info->user_data = user_data;
+
+	gtk_clipboard_request_contents (
+		clipboard, calendar_atoms[ATOM_CALENDAR],
+		(GtkClipboardReceivedFunc)
+		clipboard_request_calendar_cb, info);
+}
+
+static void
+clipboard_request_directory_cb (GtkClipboard *clipboard,
+                                GtkSelectionData *selection_data,
+                                RequestTextInfo *info)
+{
+	gchar *source;
+
+	source = e_selection_data_get_directory (selection_data);
+	info->callback (clipboard, source, info->user_data);
+	g_free (source);
+
+	g_slice_free (RequestTextInfo, info);
+}
+
+void
+e_clipboard_request_directory (GtkClipboard *clipboard,
+                               GtkClipboardTextReceivedFunc callback,
+                               gpointer user_data)
+{
+	RequestTextInfo *info;
+
+	g_return_if_fail (clipboard != NULL);
+	g_return_if_fail (callback != NULL);
+
+	info = g_slice_new (RequestTextInfo);
+	info->callback = callback;
+	info->user_data = user_data;
+
+	gtk_clipboard_request_contents (
+		clipboard, directory_atoms[ATOM_DIRECTORY],
+		(GtkClipboardReceivedFunc)
+		clipboard_request_directory_cb, info);
+}
+
+gchar *
+e_clipboard_wait_for_calendar (GtkClipboard *clipboard)
+{
+	WaitForDataResults results;
+
+	g_return_val_if_fail (clipboard != NULL, NULL);
+
+	results.data = NULL;
+	results.loop = g_main_loop_new (NULL, TRUE);
+
+	e_clipboard_request_calendar (
+		clipboard, (GtkClipboardTextReceivedFunc)
+		clipboard_wait_for_text_cb, &results);
+
+	if (g_main_loop_is_running (results.loop)) {
+		GDK_THREADS_LEAVE ();
+		g_main_loop_run (results.loop);
+		GDK_THREADS_ENTER ();
+	}
+
+	g_main_loop_unref (results.loop);
+
+	return results.data;
+}
+
+gchar *
+e_clipboard_wait_for_directory (GtkClipboard *clipboard)
+{
+	WaitForDataResults results;
+
+	g_return_val_if_fail (clipboard != NULL, NULL);
+
+	results.data = NULL;
+	results.loop = g_main_loop_new (NULL, TRUE);
+
+	e_clipboard_request_directory (
+		clipboard, (GtkClipboardTextReceivedFunc)
+		clipboard_wait_for_text_cb, &results);
+
+	if (g_main_loop_is_running (results.loop)) {
+		GDK_THREADS_LEAVE ();
+		g_main_loop_run (results.loop);
+		GDK_THREADS_ENTER ();
+	}
+
+	g_main_loop_unref (results.loop);
+
+	return results.data;
+}
+
+gboolean
+e_clipboard_wait_is_calendar_available (GtkClipboard *clipboard)
+{
+	GdkAtom *targets;
+	gint n_targets;
+	gboolean result = FALSE;
+
+	if (gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets)) {
+		result = e_targets_include_calendar (targets, n_targets);
+		g_free (targets);
+	}
+
+	return result;
+}
+
+gboolean
+e_clipboard_wait_is_directory_available (GtkClipboard *clipboard)
+{
+	GdkAtom *targets;
+	gint n_targets;
+	gboolean result = FALSE;
+
+	if (gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets)) {
+		result = e_targets_include_directory (targets, n_targets);
+		g_free (targets);
+	}
+
+	return result;
+}
diff --git a/calendar/gui/e-cal-selection.h b/e-util/e-selection.h
similarity index 64%
rename from calendar/gui/e-cal-selection.h
rename to e-util/e-selection.h
index c79f1d6..b0b2d1f 100644
--- a/calendar/gui/e-cal-selection.h
+++ b/e-util/e-selection.h
@@ -20,13 +20,13 @@
  */
 
 /**
- * SECTION: e-cal-selection
- * @short_description: calendar selection utilities
- * @include: calendar/gui/e-cal-selection.h
+ * SECTION: e-selection
+ * @short_description: selection and clipboard utilities
+ * @include: e-util/e-selection.h
  **/
 
-#ifndef E_CAL_SELECTION_H
-#define E_CAL_SELECTION_H
+#ifndef E_SELECTION_H
+#define E_SELECTION_H
 
 #include <gtk/gtk.h>
 
@@ -39,37 +39,58 @@ G_BEGIN_DECLS
 void		e_target_list_add_calendar_targets
 					(GtkTargetList *list,
 					 guint info);
+void		e_target_list_add_directory_targets
+					(GtkTargetList *list,
+					 guint info);
 gboolean	e_selection_data_set_calendar
 					(GtkSelectionData *selection_data,
 					 const gchar *source,
 					 gint length);
+gboolean	e_selection_data_set_directory
+					(GtkSelectionData *selection_data,
+					 const gchar *source,
+					 gint length);
 gchar *		e_selection_data_get_calendar
 					(GtkSelectionData *selection_data);
+gchar *		e_selection_data_get_directory
+					(GtkSelectionData *selection_data);
 gboolean	e_selection_data_targets_include_calendar
 					(GtkSelectionData *selection_data);
+gboolean	e_selection_data_targets_include_directory
+					(GtkSelectionData *selection_data);
 gboolean	e_targets_include_calendar
 					(GdkAtom *targets,
 					 gint n_targets);
+gboolean	e_targets_include_directory
+					(GdkAtom *targets,
+					 gint n_targets);
 
 /* Clipboard Functions */
 
 void		e_clipboard_set_calendar(GtkClipboard *clipboard,
 					 const gchar *source,
 					 gint length);
+void		e_clipboard_set_directory
+					(GtkClipboard *clipboard,
+					 const gchar *source,
+					 gint length);
 void		e_clipboard_request_calendar
 					(GtkClipboard *clipboard,
 					 GtkClipboardTextReceivedFunc callback,
 					 gpointer user_data);
+void		e_clipboard_request_directory
+					(GtkClipboard *clipboard,
+					 GtkClipboardTextReceivedFunc callback,
+					 gpointer user_data);
 gchar *		e_clipboard_wait_for_calendar
 					(GtkClipboard *clipboard);
+gchar *		e_clipboard_wait_for_directory
+					(GtkClipboard *clipboard);
 gboolean	e_clipboard_wait_is_calendar_available
 					(GtkClipboard *clipboard);
-
-/* Debugging Functions */
-
-void		e_clipboard_print_targets
+gboolean	e_clipboard_wait_is_directory_available
 					(GtkClipboard *clipboard);
 
 G_END_DECLS
 
-#endif /* E_CAL_SELECTION_H */
+#endif /* E_SELECTION_H */
diff --git a/modules/addressbook/e-book-shell-content.c b/modules/addressbook/e-book-shell-content.c
index 898bd2d..4eccc97 100644
--- a/modules/addressbook/e-book-shell-content.c
+++ b/modules/addressbook/e-book-shell-content.c
@@ -24,6 +24,7 @@
 #include <glib/gi18n.h>
 
 #include "e-util/e-binding.h"
+#include "e-util/e-selection.h"
 #include "e-util/gconf-bridge.h"
 #include "widgets/misc/e-paned.h"
 
@@ -258,6 +259,7 @@ book_shell_content_check_state (EShellContent *shell_content)
 	ESelectionModel *selection_model;
 	EAddressbookModel *model;
 	EAddressbookView *view;
+	GtkClipboard *clipboard;
 	guint32 state = 0;
 	gint n_contacts;
 	gint n_selected;
@@ -272,6 +274,8 @@ book_shell_content_check_state (EShellContent *shell_content)
 	n_selected = (selection_model != NULL) ?
 		e_selection_model_selected_count (selection_model) : 0;
 
+	clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+
 	/* FIXME Finish the rest of the flags. */
 	if (n_selected == 1)
 		state |= E_BOOK_SHELL_CONTENT_SELECTION_SINGLE;
@@ -283,6 +287,8 @@ book_shell_content_check_state (EShellContent *shell_content)
 		state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE;
 	if (n_contacts == 0)
 		state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY;
+	if (e_clipboard_wait_is_directory_available (clipboard))
+		state |= E_BOOK_SHELL_CONTENT_CLIPBOARD_HAS_DIRECTORY;
 
 	return state;
 }
diff --git a/modules/addressbook/e-book-shell-content.h b/modules/addressbook/e-book-shell-content.h
index da78c01..31f8c35 100644
--- a/modules/addressbook/e-book-shell-content.h
+++ b/modules/addressbook/e-book-shell-content.h
@@ -64,7 +64,8 @@ enum {
 	E_BOOK_SHELL_CONTENT_SELECTION_HAS_MAILTO_URI	= 1 << 5,
 	E_BOOK_SHELL_CONTENT_SOURCE_IS_BUSY		= 1 << 6,
 	E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE		= 1 << 7,
-	E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY		= 1 << 8
+	E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY		= 1 << 8,
+	E_BOOK_SHELL_CONTENT_CLIPBOARD_HAS_DIRECTORY	= 1 << 9
 };
 
 struct _EBookShellContent {
diff --git a/modules/addressbook/e-book-shell-view.c b/modules/addressbook/e-book-shell-view.c
index 8ea97ca..88a503b 100644
--- a/modules/addressbook/e-book-shell-view.c
+++ b/modules/addressbook/e-book-shell-view.c
@@ -246,6 +246,7 @@ book_shell_view_update_actions (EShellView *shell_view)
 	gboolean source_is_busy;
 	gboolean source_is_editable;
 	gboolean source_is_empty;
+	gboolean clipboard_has_directory;
 
 	priv = E_BOOK_SHELL_VIEW_GET_PRIVATE (shell_view);
 
@@ -268,6 +269,8 @@ book_shell_view_update_actions (EShellView *shell_view)
 		(state & E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE);
 	source_is_empty =
 		(state & E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY);
+	clipboard_has_directory =
+		(state & E_BOOK_SHELL_CONTENT_CLIPBOARD_HAS_DIRECTORY);
 
 	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 	state = e_shell_sidebar_check_state (shell_sidebar);
@@ -301,7 +304,7 @@ book_shell_view_update_actions (EShellView *shell_view)
 	gtk_action_set_sensitive (action, sensitive);
 
 	action = ACTION (CONTACT_CLIPBOARD_PASTE);
-	sensitive = source_is_editable;
+	sensitive = source_is_editable && clipboard_has_directory;
 	gtk_action_set_sensitive (action, sensitive);
 
 	action = ACTION (CONTACT_COPY);
diff --git a/modules/calendar/e-cal-shell-view-private.h b/modules/calendar/e-cal-shell-view-private.h
index 7f6413c..1f447bc 100644
--- a/modules/calendar/e-cal-shell-view-private.h
+++ b/modules/calendar/e-cal-shell-view-private.h
@@ -32,6 +32,7 @@
 #include <libedataserver/e-sexp.h>
 
 #include "e-util/e-binding.h"
+#include "e-util/e-selection.h"
 #include "e-util/e-dialog-utils.h"
 #include "e-util/e-file-utils.h"
 #include "e-util/e-error.h"
@@ -44,7 +45,6 @@
 #include "calendar/gui/comp-util.h"
 #include "calendar/gui/e-cal-list-view.h"
 #include "calendar/gui/e-cal-model-tasks.h"
-#include "calendar/gui/e-cal-selection.h"
 #include "calendar/gui/e-calendar-view.h"
 #include "calendar/gui/e-day-view.h"
 #include "calendar/gui/e-week-view.h"



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