From 4032075425d7251642e3f81b9c4732e9a2a23e85 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Fri, 13 Aug 2010 08:09:37 -0400 Subject: 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 11c20e2adc..e56bab9362 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 c791b5fba3..b5a82dbcc1 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, @@ -256,6 +270,14 @@ mail_attachment_bar_constructed (GObject *object) object, "active-view", 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"); @@ -459,6 +481,9 @@ mail_attachment_bar_class_init (EMailAttachmentBarClass *class) G_PARAM_READWRITE | 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 57301213dd..35b5d1ed18 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 ( @@ -435,6 +448,9 @@ attachment_icon_view_class_init (EAttachmentIconViewClass *class) icon_view_class = GTK_ICON_VIEW_CLASS (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 83a00692d8..64d97ab81f 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 ( @@ -277,6 +290,14 @@ attachment_paned_constructed (GObject *object) object, "active-view", 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"); @@ -456,6 +477,9 @@ attachment_paned_class_init (EAttachmentPanedClass *class) G_PARAM_READWRITE | 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 09602ca186..8e597adebb 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 ( @@ -467,6 +480,9 @@ attachment_tree_view_class_init (EAttachmentTreeViewClass *class) tree_view_class = GTK_TREE_VIEW_CLASS (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 60ce09860d..cc587bf80b 100644 --- a/widgets/misc/e-attachment-view.c +++ b/widgets/misc/e-attachment-view.c @@ -821,6 +821,15 @@ attachment_view_class_init (EAttachmentViewIface *iface) { iface->update_actions = attachment_view_update_actions; + 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 ( @@ -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 071de0705a..79dbacb151 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); -- cgit v1.2.3