]> git.0d.be Git - empathy.git/commitdiff
Implemented file drags to contact list, along with row highlights
authorShaun McCance <Shaun McCance>
Thu, 17 Sep 2009 21:17:49 +0000 (16:17 -0500)
committerShaun McCance <shaunm@gnome.org>
Tue, 24 Nov 2009 20:43:07 +0000 (14:43 -0600)
libempathy-gtk/empathy-contact-list-view.c
src/empathy-chat-window.c

index c19ad32df2edcd59c49cff016d1eac44c9b6fd92..04a448817e4deca2b44f20c13c8ab5555eaa0d73 100644 (file)
@@ -88,17 +88,21 @@ enum {
 
 enum DndDragType {
        DND_DRAG_TYPE_CONTACT_ID,
-       DND_DRAG_TYPE_URL,
+       DND_DRAG_TYPE_URI_LIST,
        DND_DRAG_TYPE_STRING,
 };
 
 static const GtkTargetEntry drag_types_dest[] = {
+       { "text/uri-list",   0, DND_DRAG_TYPE_URI_LIST },
        { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
-       { "text/uri-list",   0, DND_DRAG_TYPE_URL },
        { "text/plain",      0, DND_DRAG_TYPE_STRING },
        { "STRING",          0, DND_DRAG_TYPE_STRING },
 };
 
+static const GtkTargetEntry drag_types_dest_file[] = {
+       { "text/uri-list",   0, DND_DRAG_TYPE_URI_LIST },
+};
+
 static const GtkTargetEntry drag_types_source[] = {
        { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
 };
@@ -244,102 +248,143 @@ contact_list_view_drag_data_received (GtkWidget         *view,
                                      guint              time_)
 {
        EmpathyContactListViewPriv *priv;
-       TpAccountManager           *account_manager;
-       EmpathyTpContactFactory    *factory = NULL;
-       TpAccount                  *account = NULL;
        GtkTreeModel               *model;
-       GtkTreeViewDropPosition     position;
-       GtkTreePath                *path;
-       const gchar                *id;
+       gboolean                    success = TRUE;
+       const gchar                *sel_data;
        gchar                     **strv = NULL;
-       const gchar                *account_id = NULL;
-       const gchar                *contact_id = NULL;
-       gchar                      *new_group = NULL;
-       gchar                      *old_group = NULL;
-       DndGetContactData          *data;
        gboolean                    is_row;
-       gboolean                    success = TRUE;
+       GtkTreeViewDropPosition     position;
+       GtkTreePath                *path;
 
        priv = GET_PRIV (view);
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
 
+       sel_data = (const gchar*) gtk_selection_data_get_data (selection);
+       DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'",
+              context->action == GDK_ACTION_MOVE ? "move" : "",
+              context->action == GDK_ACTION_COPY ? "copy" : "",
+              sel_data);
+
        /* Get destination group information. */
        is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (view),
                                                    x,
                                                    y,
                                                    &path,
                                                    &position);
+       if (!is_row) {
+               success = FALSE;
+               goto OUT;
+       }
 
-       if (is_row) {
+       if (info == DND_DRAG_TYPE_CONTACT_ID || info == DND_DRAG_TYPE_STRING) {
+               TpAccountManager           *account_manager;
+               EmpathyTpContactFactory    *factory = NULL;
+               TpAccount                  *account = NULL;
+               const gchar                *account_id = NULL;
+               const gchar                *contact_id = NULL;
+               gchar                      *new_group = NULL;
+               gchar                      *old_group = NULL;
+               DndGetContactData          *data;
                new_group = empathy_contact_list_store_get_parent_group (model,
-                       path, NULL);
+                                                                        path, NULL);
                gtk_tree_path_free (path);
-       }
+               path = NULL;
+
+               /* Get source group information. */
+               if (priv->drag_row) {
+                       path = gtk_tree_row_reference_get_path (priv->drag_row);
+                       if (path) {
+                               old_group = empathy_contact_list_store_get_parent_group (
+                                                                                        model, path, NULL);
+                               gtk_tree_path_free (path);
+                               path = NULL;
+                       }
+               }
 
-       /* Get source group information. */
-       if (priv->drag_row) {
-               path = gtk_tree_row_reference_get_path (priv->drag_row);
-               if (path) {
-                       old_group = empathy_contact_list_store_get_parent_group (
-                               model, path, NULL);
-                       gtk_tree_path_free (path);
+               if (!tp_strdiff (old_group, new_group)) {
+                       g_free (new_group);
+                       g_free (old_group);
+                       goto OUT;
                }
-       }
 
-       if (!tp_strdiff (old_group, new_group)) {
-               g_free (new_group);
-               g_free (old_group);
-               goto OUT;
-       }
+               /* FIXME: should probably make sure the account manager is prepared
+                * before calling _ensure_account on it. See bug 600115. */
+               account_manager = tp_account_manager_dup ();
+               strv = g_strsplit (sel_data, ":", 2);
+               if (g_strv_length (strv) == 2) {
+                       account_id = strv[0];
+                       contact_id = strv[1];
+                       account = tp_account_manager_ensure_account (account_manager, account_id);
+               }
+               if (account) {
+                       TpConnection *connection;
+
+                       connection = tp_account_get_connection (account);
+                       if (connection) {
+                               factory = empathy_tp_contact_factory_dup_singleton (connection);
+                       }
+                       g_object_unref (account_manager);
+
+                       if (!factory) {
+                               DEBUG ("Failed to get factory for account '%s'", account_id);
+                               success = FALSE;
+                               g_free (new_group);
+                               g_free (old_group);
+                               goto OUT;
+                       }
+               }
 
-       id = (const gchar*) gtk_selection_data_get_data (selection);
-       DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'",
-               context->action == GDK_ACTION_MOVE ? "move" : "",
-               context->action == GDK_ACTION_COPY ? "copy" : "",
-               id);
-
-       /* FIXME: should probably make sure the account manager is prepared
-        * before calling _ensure_account on it. See bug 600115. */
-       account_manager = tp_account_manager_dup ();
-       strv = g_strsplit (id, ":", 2);
-       if (g_strv_length (strv) == 2) {
-               account_id = strv[0];
-               contact_id = strv[1];
-               account = tp_account_manager_ensure_account (account_manager, account_id);
-       }
-       if (account) {
-               TpConnection *connection;
+               data = g_slice_new0 (DndGetContactData);
+               data->new_group = new_group;
+               data->old_group = old_group;
+               data->action = context->action;
 
-               connection = tp_account_get_connection (account);
-               if (connection) {
-                       factory = empathy_tp_contact_factory_dup_singleton (connection);
-               }
-       }
-       g_object_unref (account_manager);
+               /* FIXME: We should probably wait for the cb before calling
+                * gtk_drag_finish */
+               empathy_tp_contact_factory_get_from_id (factory, contact_id,
+                                                       contact_list_view_drag_got_contact,
+                                                       data, (GDestroyNotify) contact_list_view_dnd_get_contact_free,
+                                                       G_OBJECT (view));
 
-       if (!factory) {
-               DEBUG ("Failed to get factory for account '%s'", account_id);
-               success = FALSE;
-               g_free (new_group);
-               g_free (old_group);
-               goto OUT;
+               g_object_unref (factory);
        }
+       else if (info == DND_DRAG_TYPE_URI_LIST) {
+               GtkTreeIter iter;
+               const gchar  *nl;
+               gchar        *uri;
+               GFile        *file;
+               EmpathyContact *contact;
+
+               gtk_tree_model_get_iter (model, &iter, path);
+               gtk_tree_model_get (model, &iter,
+                                   EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact,
+                                   -1);
+               if (!contact) {
+                       success = FALSE;
+                       goto OUT;
+               }
 
-       data = g_slice_new0 (DndGetContactData);
-       data->new_group = new_group;
-       data->old_group = old_group;
-       data->action = context->action;
+               nl = strstr (sel_data, "\r\n");
+               if (!nl) {
+                       nl = strchr (sel_data, '\n');
+               }
+               if (nl) {
+                       uri = g_strndup (sel_data, nl - sel_data);
+                       file = g_file_new_for_uri (uri);
+                       g_free (uri);
+               }
+               else {
+                       file = g_file_new_for_uri (sel_data);
+               }
 
-       /* FIXME: We should probably wait for the cb before calling
-        * gtk_drag_finish */
-       empathy_tp_contact_factory_get_from_id (factory, contact_id,
-               contact_list_view_drag_got_contact,
-               data, (GDestroyNotify) contact_list_view_dnd_get_contact_free,
-               G_OBJECT (view));
+               empathy_send_file (contact, file);
 
-       g_object_unref (factory);
+               g_object_unref (file);
+               gtk_drag_finish (context, TRUE, FALSE, time_);
+       }
 
 OUT:
+       gtk_tree_path_free (path);
        g_strfreev (strv);
        gtk_drag_finish (context, success, FALSE, GDK_CURRENT_TIME);
 }
@@ -363,12 +408,25 @@ contact_list_view_drag_motion (GtkWidget      *widget,
                               gint            y,
                               guint           time_)
 {
+       EmpathyContactListViewPriv *priv;
+       GtkTreeModel               *model;
+       static GtkTargetList  *file_targets = NULL;
+       GdkAtom                target;
+       GtkTreeIter            iter;
        static DragMotionData *dm = NULL;
        GtkTreePath           *path;
        gboolean               is_row;
        gboolean               is_different = FALSE;
        gboolean               cleanup = TRUE;
-       int                    action = 0;
+       gboolean               retval = TRUE;
+
+       priv = GET_PRIV (EMPATHY_CONTACT_LIST_VIEW (widget));
+       model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+       if (file_targets == NULL) {
+               file_targets = gtk_target_list_new (drag_types_dest_file,
+                                                   G_N_ELEMENTS (drag_types_dest_file));
+       }
 
        is_row = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
                                                x,
@@ -387,15 +445,51 @@ contact_list_view_drag_motion (GtkWidget      *widget,
                cleanup &= FALSE;
        }
 
-       if (context->actions == GDK_ACTION_COPY) {
-               action = context->suggested_action;
-       } else if (context->actions & GDK_ACTION_MOVE) {
-               action = GDK_ACTION_MOVE;
+       if (path == NULL) {
+               gdk_drag_status (context, 0, time_);
+               gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), NULL, 0);
+               return FALSE;
+       }
+       target = gtk_drag_dest_find_target (widget, context, file_targets);
+       gtk_tree_model_get_iter (model, &iter, path);
+
+       if (target == GDK_NONE) {
+               gboolean    is_group;
+               gtk_tree_model_get (model, &iter,
+                                   EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+                                   -1);
+               if (is_group) {
+                       gdk_drag_status (context, GDK_ACTION_MOVE, time_);
+                       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
+                                                        path,
+                                                        GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
+               }
+               else {
+                       gdk_drag_status (context, 0, time_);
+                       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), NULL, 0);
+                       retval = FALSE;
+               }
+       }
+       else {
+               EmpathyContact *contact;
+               gtk_tree_model_get (model, &iter,
+                                   EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact,
+                                   -1);
+               if (contact) {
+                       gdk_drag_status (context, GDK_ACTION_COPY, time_);
+                       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
+                                                        path,
+                                                        GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
+               }
+               else {
+                       gdk_drag_status (context, 0, time_);
+                       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), NULL, 0);
+                       retval = FALSE;
+               }
        }
-       gdk_drag_status (context, action, time_);
 
        if (!is_different && !cleanup) {
-               return TRUE;
+               return retval;
        }
 
        if (dm) {
@@ -420,7 +514,7 @@ contact_list_view_drag_motion (GtkWidget      *widget,
                        dm);
        }
 
-       return TRUE;
+       return retval;
 }
 
 static void
@@ -973,7 +1067,7 @@ contact_list_view_setup (EmpathyContactListView *view)
        /* Setup view */
        g_object_set (view,
                      "headers-visible", FALSE,
-                     "reorderable", TRUE,
+                     "reorderable", FALSE,
                      "show-expanders", FALSE,
                      NULL);
 
index 36f31b0b12e305c195415e646e5271d4c9effb06..a58d4f65c9905ada1a15a14a288bd8c1180b69b6 100644 (file)
@@ -1438,9 +1438,9 @@ chat_window_drag_data_received (GtkWidget        *widget,
                EmpathyChatWindowPriv *priv;
                EmpathyContact *contact;
                const gchar *data;
-               GFile *file;
-               gchar *nl;
+               const gchar *nl;
                gchar *uri;
+               GFile *file;
 
                priv = GET_PRIV (window);
                contact = empathy_chat_get_remote_contact (priv->current_chat);