[evolution] Bug 624913 - Disallow drag-and-drop within the same attachment bar



commit 4032075425d7251642e3f81b9c4732e9a2a23e85
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Aug 13 08:09:37 2010 -0400

    Bug 624913 - Disallow drag-and-drop within the same attachment bar
    
    Adds a boolean "dragging" property to the EAttachmentView interface,
    which becomes TRUE when the user start a drag from the attachment view.
    e_attachment_view_drag_motion() and e_attachment_view_drag_drop() both
    return FALSE when this property is set.
    
    Also, do not register the entire EMsgComposer window as a drag
    destination.  Just intercept drag signals from the GtkHTML widget.
    
    Requires gtkhtml commit 344eb5e to fully work correctly.

 composer/e-msg-composer.c             |  126 ++++++++++++---------------------
 mail/e-mail-attachment-bar.c          |   25 +++++++
 widgets/misc/e-attachment-icon-view.c |   16 ++++
 widgets/misc/e-attachment-paned.c     |   24 ++++++
 widgets/misc/e-attachment-tree-view.c |   16 ++++
 widgets/misc/e-attachment-view.c      |   55 ++++++++++++--
 widgets/misc/e-attachment-view.h      |    4 +
 7 files changed, 178 insertions(+), 88 deletions(-)
---
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index 11c20e2..e56bab9 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -113,14 +113,6 @@ static void	handle_multipart_signed		(EMsgComposer *composer,
 						 CamelMultipart *multipart,
 						 gint depth);
 
-static void	msg_composer_drag_data_received	(GtkWidget *widget,
-						 GdkDragContext *context,
-						 gint x,
-						 gint y,
-						 GtkSelectionData *selection,
-						 guint info,
-						 guint time);
-
 /**
  * emcu_part_to_html:
  * @part:
@@ -1663,17 +1655,49 @@ msg_composer_realize_gtkhtml_cb (GtkWidget *widget,
 	gtk_target_table_free (targets, n_targets);
 }
 
-struct _drop_data {
-	EMsgComposer *composer;
+static gboolean
+msg_composer_drag_motion_cb (GtkWidget *widget,
+                             GdkDragContext *context,
+                             gint x,
+                             gint y,
+                             guint time,
+                             EMsgComposer *composer)
+{
+	EAttachmentView *view;
 
-	GdkDragContext *context;
-	/* Only selection->data and selection->length are valid */
-	GtkSelectionData *selection;
+	view = e_msg_composer_get_attachment_view (composer);
 
-	guint32 action;
-	guint info;
-	guint time;
-};
+	/* Stop the signal from propagating to GtkHtml. */
+	g_signal_stop_emission_by_name (widget, "drag-motion");
+
+	return e_attachment_view_drag_motion (view, context, x, y, time);
+}
+
+static void
+msg_composer_drag_data_received_cb (GtkWidget *widget,
+                                    GdkDragContext *context,
+                                    gint x,
+                                    gint y,
+                                    GtkSelectionData *selection,
+                                    guint info,
+                                    guint time,
+                                    EMsgComposer *composer)
+{
+	EAttachmentView *view;
+
+	view = e_msg_composer_get_attachment_view (composer);
+
+	/* Forward the data to the attachment view.  Note that calling
+	 * e_attachment_view_drag_data_received() will not work because
+	 * that function only handles the case where all the other drag
+	 * handlers have failed. */
+	e_attachment_paned_drag_data_received (
+		E_ATTACHMENT_PANED (view),
+		context, x, y, selection, info, time);
+
+	/* Stop the signal from propagating to GtkHtml. */
+	g_signal_stop_emission_by_name (widget, "drag-data-received");
+}
 
 static void
 msg_composer_notify_header_cb (EMsgComposer *composer)
@@ -1792,9 +1816,6 @@ msg_composer_constructed (GObject *object)
 	EAttachmentView *view;
 	EAttachmentStore *store;
 	EComposerHeaderTable *table;
-	GdkDragAction drag_actions;
-	GtkTargetList *target_list;
-	GtkTargetEntry *targets;
 	GtkUIManager *ui_manager;
 	GtkToggleAction *action;
 	GtkHTML *html;
@@ -1802,7 +1823,6 @@ msg_composer_constructed (GObject *object)
 	const gchar *id;
 	gboolean active;
 	guint binding_id;
-	gint n_targets;
 
 	editor = GTKHTML_EDITOR (object);
 	composer = E_MSG_COMPOSER (object);
@@ -1863,24 +1883,17 @@ msg_composer_constructed (GObject *object)
 
 	/* Drag-and-Drop Support */
 
-	target_list = e_attachment_view_get_target_list (view);
-	drag_actions = e_attachment_view_get_drag_actions (view);
-
-	targets = gtk_target_table_new_from_list (target_list, &n_targets);
-
-	gtk_drag_dest_set (
-		GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL,
-		targets, n_targets, drag_actions);
-
 	g_signal_connect (
 		html, "realize",
 		G_CALLBACK (msg_composer_realize_gtkhtml_cb), composer);
 
 	g_signal_connect (
-		html, "drag-data-received",
-		G_CALLBACK (msg_composer_drag_data_received), NULL);
+		html, "drag-motion",
+		G_CALLBACK (msg_composer_drag_motion_cb), composer);
 
-	gtk_target_table_free (targets, n_targets);
+	g_signal_connect (
+		html, "drag-data-received",
+		G_CALLBACK (msg_composer_drag_data_received_cb), composer);
 
 	/* Configure Headers */
 
@@ -2040,51 +2053,6 @@ msg_composer_key_press_event (GtkWidget *widget,
 	return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
 }
 
-static gboolean
-msg_composer_drag_motion (GtkWidget *widget,
-                          GdkDragContext *context,
-                          gint x,
-                          gint y,
-                          guint time)
-{
-	EMsgComposer *composer;
-	EAttachmentView *view;
-
-	/* Widget may be EMsgComposer or GtkHTML. */
-	composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget));
-	view = e_msg_composer_get_attachment_view (composer);
-
-	return e_attachment_view_drag_motion (view, context, x, y, time);
-}
-
-static void
-msg_composer_drag_data_received (GtkWidget *widget,
-                                 GdkDragContext *context,
-                                 gint x,
-                                 gint y,
-                                 GtkSelectionData *selection,
-                                 guint info,
-                                 guint time)
-{
-	EMsgComposer *composer;
-	EAttachmentView *view;
-
-	/* Widget may be EMsgComposer or GtkHTML. */
-	composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget));
-	view = e_msg_composer_get_attachment_view (composer);
-
-	/* Forward the data to the attachment view.  Note that calling
-	 * e_attachment_view_drag_data_received() will not work because
-	 * that function only handles the case where all the other drag
-	 * handlers have failed. */
-	e_attachment_paned_drag_data_received (
-		E_ATTACHMENT_PANED (view),
-		context, x, y, selection, info, time);
-
-	/* Stop the signal from propagating to GtkHtml. */
-	g_signal_stop_emission_by_name (widget, "drag-data-received");
-}
-
 static void
 msg_composer_cut_clipboard (GtkhtmlEditor *editor)
 {
@@ -2281,8 +2249,6 @@ msg_composer_class_init (EMsgComposerClass *class)
 	widget_class = GTK_WIDGET_CLASS (class);
 	widget_class->map = msg_composer_map;
 	widget_class->key_press_event = msg_composer_key_press_event;
-	widget_class->drag_motion = msg_composer_drag_motion;
-	widget_class->drag_data_received = msg_composer_drag_data_received;
 
 	editor_class = GTKHTML_EDITOR_CLASS (class);
 	editor_class->cut_clipboard = msg_composer_cut_clipboard;
diff --git a/mail/e-mail-attachment-bar.c b/mail/e-mail-attachment-bar.c
index c791b5f..b5a82db 100644
--- a/mail/e-mail-attachment-bar.c
+++ b/mail/e-mail-attachment-bar.c
@@ -57,6 +57,7 @@ struct _EMailAttachmentBarPrivate {
 enum {
 	PROP_0,
 	PROP_ACTIVE_VIEW,
+	PROP_DRAGGING,
 	PROP_EDITABLE,
 	PROP_EXPANDED
 };
@@ -120,6 +121,12 @@ mail_attachment_bar_set_property (GObject *object,
 				g_value_get_int (value));
 			return;
 
+		case PROP_DRAGGING:
+			e_attachment_view_set_dragging (
+				E_ATTACHMENT_VIEW (object),
+				g_value_get_boolean (value));
+			return;
+
 		case PROP_EDITABLE:
 			e_attachment_view_set_editable (
 				E_ATTACHMENT_VIEW (object),
@@ -150,6 +157,13 @@ mail_attachment_bar_get_property (GObject *object,
 				E_MAIL_ATTACHMENT_BAR (object)));
 			return;
 
+		case PROP_DRAGGING:
+			g_value_set_boolean (
+				value,
+				e_attachment_view_get_dragging (
+				E_ATTACHMENT_VIEW (object)));
+			return;
+
 		case PROP_EDITABLE:
 			g_value_set_boolean (
 				value,
@@ -257,6 +271,14 @@ mail_attachment_bar_constructed (GObject *object)
 		priv->combo_box, "active");
 
 	e_mutual_binding_new (
+		object, "dragging",
+		priv->icon_view, "dragging");
+
+	e_mutual_binding_new (
+		object, "dragging",
+		priv->tree_view, "dragging");
+
+	e_mutual_binding_new (
 		object, "editable",
 		priv->icon_view, "editable");
 
@@ -460,6 +482,9 @@ mail_attachment_bar_class_init (EMailAttachmentBarClass *class)
 			G_PARAM_CONSTRUCT));
 
 	g_object_class_override_property (
+		object_class, PROP_DRAGGING, "dragging");
+
+	g_object_class_override_property (
 		object_class, PROP_EDITABLE, "editable");
 }
 
diff --git a/widgets/misc/e-attachment-icon-view.c b/widgets/misc/e-attachment-icon-view.c
index 5730121..35b5d1e 100644
--- a/widgets/misc/e-attachment-icon-view.c
+++ b/widgets/misc/e-attachment-icon-view.c
@@ -37,6 +37,7 @@ struct _EAttachmentIconViewPrivate {
 
 enum {
 	PROP_0,
+	PROP_DRAGGING,
 	PROP_EDITABLE
 };
 
@@ -56,6 +57,12 @@ attachment_icon_view_set_property (GObject *object,
                                    GParamSpec *pspec)
 {
 	switch (property_id) {
+		case PROP_DRAGGING:
+			e_attachment_view_set_dragging (
+				E_ATTACHMENT_VIEW (object),
+				g_value_get_boolean (value));
+			return;
+
 		case PROP_EDITABLE:
 			e_attachment_view_set_editable (
 				E_ATTACHMENT_VIEW (object),
@@ -73,6 +80,12 @@ attachment_icon_view_get_property (GObject *object,
                                    GParamSpec *pspec)
 {
 	switch (property_id) {
+		case PROP_DRAGGING:
+			g_value_set_boolean (
+				value, e_attachment_view_get_dragging (
+				E_ATTACHMENT_VIEW (object)));
+			return;
+
 		case PROP_EDITABLE:
 			g_value_set_boolean (
 				value, e_attachment_view_get_editable (
@@ -436,6 +449,9 @@ attachment_icon_view_class_init (EAttachmentIconViewClass *class)
 	icon_view_class->item_activated = attachment_icon_view_item_activated;
 
 	g_object_class_override_property (
+		object_class, PROP_DRAGGING, "dragging");
+
+	g_object_class_override_property (
 		object_class, PROP_EDITABLE, "editable");
 }
 
diff --git a/widgets/misc/e-attachment-paned.c b/widgets/misc/e-attachment-paned.c
index 83a0069..64d97ab 100644
--- a/widgets/misc/e-attachment-paned.c
+++ b/widgets/misc/e-attachment-paned.c
@@ -60,6 +60,7 @@ struct _EAttachmentPanedPrivate {
 enum {
 	PROP_0,
 	PROP_ACTIVE_VIEW,
+	PROP_DRAGGING,
 	PROP_EDITABLE,
 	PROP_EXPANDED
 };
@@ -150,6 +151,12 @@ attachment_paned_set_property (GObject *object,
 				g_value_get_int (value));
 			return;
 
+		case PROP_DRAGGING:
+			e_attachment_view_set_dragging (
+				E_ATTACHMENT_VIEW (object),
+				g_value_get_boolean (value));
+			return;
+
 		case PROP_EDITABLE:
 			e_attachment_view_set_editable (
 				E_ATTACHMENT_VIEW (object),
@@ -179,6 +186,12 @@ attachment_paned_get_property (GObject *object,
 				E_ATTACHMENT_PANED (object)));
 			return;
 
+		case PROP_DRAGGING:
+			g_value_set_boolean (
+				value, e_attachment_view_get_dragging (
+				E_ATTACHMENT_VIEW (object)));
+			return;
+
 		case PROP_EDITABLE:
 			g_value_set_boolean (
 				value, e_attachment_view_get_editable (
@@ -278,6 +291,14 @@ attachment_paned_constructed (GObject *object)
 		priv->notebook, "page");
 
 	e_mutual_binding_new (
+		object, "dragging",
+		priv->icon_view, "dragging");
+
+	e_mutual_binding_new (
+		object, "dragging",
+		priv->tree_view, "dragging");
+
+	e_mutual_binding_new (
 		object, "editable",
 		priv->icon_view, "editable");
 
@@ -457,6 +478,9 @@ attachment_paned_class_init (EAttachmentPanedClass *class)
 			G_PARAM_CONSTRUCT));
 
 	g_object_class_override_property (
+		object_class, PROP_DRAGGING, "dragging");
+
+	g_object_class_override_property (
 		object_class, PROP_EDITABLE, "editable");
 }
 
diff --git a/widgets/misc/e-attachment-tree-view.c b/widgets/misc/e-attachment-tree-view.c
index 09602ca..8e597ad 100644
--- a/widgets/misc/e-attachment-tree-view.c
+++ b/widgets/misc/e-attachment-tree-view.c
@@ -37,6 +37,7 @@ struct _EAttachmentTreeViewPrivate {
 
 enum {
 	PROP_0,
+	PROP_DRAGGING,
 	PROP_EDITABLE
 };
 
@@ -49,6 +50,12 @@ attachment_tree_view_set_property (GObject *object,
                                    GParamSpec *pspec)
 {
 	switch (property_id) {
+		case PROP_DRAGGING:
+			e_attachment_view_set_dragging (
+				E_ATTACHMENT_VIEW (object),
+				g_value_get_boolean (value));
+			return;
+
 		case PROP_EDITABLE:
 			e_attachment_view_set_editable (
 				E_ATTACHMENT_VIEW (object),
@@ -66,6 +73,12 @@ attachment_tree_view_get_property (GObject *object,
                                    GParamSpec *pspec)
 {
 	switch (property_id) {
+		case PROP_DRAGGING:
+			g_value_set_boolean (
+				value, e_attachment_view_get_dragging (
+				E_ATTACHMENT_VIEW (object)));
+			return;
+
 		case PROP_EDITABLE:
 			g_value_set_boolean (
 				value, e_attachment_view_get_editable (
@@ -468,6 +481,9 @@ attachment_tree_view_class_init (EAttachmentTreeViewClass *class)
 	tree_view_class->row_activated = attachment_tree_view_row_activated;
 
 	g_object_class_override_property (
+		object_class, PROP_DRAGGING, "dragging");
+
+	g_object_class_override_property (
 		object_class, PROP_EDITABLE, "editable");
 }
 
diff --git a/widgets/misc/e-attachment-view.c b/widgets/misc/e-attachment-view.c
index 60ce098..cc587bf 100644
--- a/widgets/misc/e-attachment-view.c
+++ b/widgets/misc/e-attachment-view.c
@@ -824,6 +824,15 @@ attachment_view_class_init (EAttachmentViewIface *iface)
 	g_object_interface_install_property (
 		iface,
 		g_param_spec_boolean (
+			"dragging",
+			"Dragging",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE));
+
+	g_object_interface_install_property (
+		iface,
+		g_param_spec_boolean (
 			"editable",
 			"Editable",
 			NULL,
@@ -1025,6 +1034,7 @@ e_attachment_view_set_editable (EAttachmentView *view,
 	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
 
 	priv = e_attachment_view_get_private (view);
+
 	priv->editable = editable;
 
 	if (editable)
@@ -1035,6 +1045,33 @@ e_attachment_view_set_editable (EAttachmentView *view,
 	g_object_notify (G_OBJECT (view), "editable");
 }
 
+gboolean
+e_attachment_view_get_dragging (EAttachmentView *view)
+{
+	EAttachmentViewPrivate *priv;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE);
+
+	priv = e_attachment_view_get_private (view);
+
+	return priv->dragging;
+}
+
+void
+e_attachment_view_set_dragging (EAttachmentView *view,
+                                gboolean dragging)
+{
+	EAttachmentViewPrivate *priv;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+	priv = e_attachment_view_get_private (view);
+
+	priv->dragging = dragging;
+
+	g_object_notify (G_OBJECT (view), "dragging");
+}
+
 GtkTargetList *
 e_attachment_view_get_target_list (EAttachmentView *view)
 {
@@ -1507,10 +1544,7 @@ e_attachment_view_drag_begin (EAttachmentView *view,
 
 	priv = e_attachment_view_get_private (view);
 
-	/* Prevent the user from dragging and dropping to
-	 * the same attachment view, which would duplicate
-	 * the attachment. */
-	e_attachment_view_drag_dest_unset (view);
+	e_attachment_view_set_dragging (view, TRUE);
 
 	g_warn_if_fail (priv->selected == NULL);
 	priv->selected = e_attachment_view_get_selected_attachments (view);
@@ -1569,9 +1603,7 @@ e_attachment_view_drag_end (EAttachmentView *view,
 
 	priv = e_attachment_view_get_private (view);
 
-	/* Restore the previous drag destination state. */
-	if (e_attachment_view_get_editable (view))
-		e_attachment_view_drag_dest_set (view);
+	e_attachment_view_set_dragging (view, FALSE);
 
 	g_list_foreach (priv->selected, (GFunc) g_object_unref, NULL);
 	g_list_free (priv->selected);
@@ -1698,6 +1730,11 @@ e_attachment_view_drag_motion (EAttachmentView *view,
 	if (!e_attachment_view_get_editable (view))
 		return FALSE;
 
+	/* Disallow drops if we initiated the drag.
+	 * This helps prevent duplicate attachments. */
+	if (e_attachment_view_get_dragging (view))
+		return FALSE;
+
 	actions = gdk_drag_context_get_actions (context);
 	actions &= priv->drag_actions;
 	chosen_action = gdk_drag_context_get_suggested_action (context);
@@ -1725,7 +1762,9 @@ e_attachment_view_drag_drop (EAttachmentView *view,
 	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE);
 	g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), FALSE);
 
-	return TRUE;
+	/* Disallow drops if we initiated the drag.
+	 * This helps prevent duplicate attachments. */
+	return !e_attachment_view_get_dragging (view);
 }
 
 void
diff --git a/widgets/misc/e-attachment-view.h b/widgets/misc/e-attachment-view.h
index 071de07..79dbacb 100644
--- a/widgets/misc/e-attachment-view.h
+++ b/widgets/misc/e-attachment-view.h
@@ -109,6 +109,7 @@ struct _EAttachmentViewPrivate {
 	gint start_x;
 	gint start_y;
 
+	guint dragging : 1;
 	guint editable : 1;
 };
 
@@ -122,6 +123,9 @@ EAttachmentViewPrivate *
 		e_attachment_view_get_private	(EAttachmentView *view);
 EAttachmentStore *
 		e_attachment_view_get_store	(EAttachmentView *view);
+gboolean	e_attachment_view_get_dragging	(EAttachmentView *view);
+void		e_attachment_view_set_dragging	(EAttachmentView *view,
+						 gboolean dragging);
 gboolean	e_attachment_view_get_editable	(EAttachmentView *view);
 void		e_attachment_view_set_editable	(EAttachmentView *view,
 						 gboolean editable);



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