]> git.0d.be Git - empathy.git/blobdiff - src/empathy-chat-window.c
Merge commit 'staz/dnd'
[empathy.git] / src / empathy-chat-window.c
index 0ed5011df49846b18f82b249af5c3eb403edabb6..29d574a3e6e6f8d6fecf0c1ee17c6730a4e1af06 100644 (file)
 
 #include <libempathy/empathy-contact.h>
 #include <libempathy/empathy-message.h>
-#include <libempathy/empathy-dispatcher.h>
 #include <libempathy/empathy-chatroom-manager.h>
 #include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-tp-contact-factory.h>
+#include <libempathy/empathy-contact-list.h>
 
 #include <libempathy-gtk/empathy-images.h>
 #include <libempathy-gtk/empathy-conf.h>
 #include <libempathy-gtk/empathy-ui-utils.h>
 #include <libempathy-gtk/empathy-notify-manager.h>
 
-#include <extensions/extensions.h>
-
 #include "empathy-chat-window.h"
 #include "empathy-about-dialog.h"
+#include "empathy-invite-participant-dialog.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_CHAT
 #include <libempathy/empathy-debug.h>
@@ -93,6 +93,7 @@ typedef struct {
        GtkAction   *menu_edit_cut;
        GtkAction   *menu_edit_copy;
        GtkAction   *menu_edit_paste;
+       GtkAction   *menu_edit_find;
 
        GtkAction   *menu_tabs_next;
        GtkAction   *menu_tabs_prev;
@@ -118,6 +119,7 @@ static const GtkTargetEntry drag_types_dest[] = {
        { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
        { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, DND_DRAG_TYPE_TAB },
        { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST },
+       { "text/path-list", 0, DND_DRAG_TYPE_URI_LIST },
 };
 
 static const GtkTargetEntry drag_types_dest_contact[] = {
@@ -125,6 +127,9 @@ static const GtkTargetEntry drag_types_dest_contact[] = {
 };
 
 static const GtkTargetEntry drag_types_dest_file[] = {
+       /* must be first to be prioritized, in order to receive the
+        * note's file path from Tomboy instead of an URI */
+       { "text/path-list", 0, DND_DRAG_TYPE_URI_LIST },
        { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST },
 };
 
@@ -346,6 +351,32 @@ chat_window_menu_context_update (EmpathyChatWindowPriv *priv,
        gtk_action_set_sensitive (priv->menu_conv_insert_smiley, is_connected);
 }
 
+static void
+chat_window_conversation_menu_update (EmpathyChatWindowPriv *priv,
+                                      EmpathyChatWindow     *self)
+{
+       EmpathyTpChat *tp_chat;
+       TpConnection *connection;
+       GtkAction *action;
+       gboolean sensitive = FALSE;
+
+       g_return_if_fail (priv->current_chat != NULL);
+
+       action = gtk_ui_manager_get_action (priv->ui_manager,
+               "/chats_menubar/menu_conv/menu_conv_invite_participant");
+       tp_chat = empathy_chat_get_tp_chat (priv->current_chat);
+
+       if (tp_chat != NULL) {
+               connection = empathy_tp_chat_get_connection (tp_chat);
+
+               sensitive = empathy_tp_chat_can_add_contact (tp_chat) &&
+                       (tp_connection_get_status (connection, NULL) ==
+                        TP_CONNECTION_STATUS_CONNECTED);
+       }
+
+       gtk_action_set_sensitive (action, sensitive);
+}
+
 static void
 chat_window_contact_menu_update (EmpathyChatWindowPriv *priv,
                                 EmpathyChatWindow     *window)
@@ -537,6 +568,8 @@ chat_window_update (EmpathyChatWindow *window)
        chat_window_menu_context_update (priv,
                                         num_pages);
 
+       chat_window_conversation_menu_update (priv, window);
+
        chat_window_contact_menu_update (priv,
                                         window);
 
@@ -820,21 +853,21 @@ chat_window_contacts_toggled_cb (GtkToggleAction   *toggle_action,
 }
 
 static void
-upgrade_to_muc_cb (TpConnection *connection,
-                  gboolean      yours,
-                  const char   *object_path,
-                  GHashTable   *properties,
-                  const GError *error,
-                  gpointer      user_data,
-                  GObject      *window)
-{
-       if (error)
-       {
-               g_critical ("%s", error->message);
+got_contact_cb (EmpathyTpContactFactory *factory,
+                EmpathyContact          *contact,
+                const GError            *error,
+                gpointer                 user_data,
+                GObject                 *object)
+{
+       EmpathyTpChat *tp_chat = EMPATHY_TP_CHAT (user_data);
+
+       if (error != NULL) {
+               DEBUG ("Failed: %s", error->message);
                return;
+       } else {
+               empathy_contact_list_add (EMPATHY_CONTACT_LIST (tp_chat),
+                               contact, _("Inviting you to this room"));
        }
-
-       g_print ("GOT CHANNEL! %s\n", object_path);
 }
 
 static void
@@ -842,51 +875,46 @@ chat_window_invite_participant_activate_cb (GtkAction         *action,
                                            EmpathyChatWindow *window)
 {
        EmpathyChatWindowPriv *priv;
+       GtkWidget             *dialog;
        EmpathyTpChat         *tp_chat;
-       TpConnection          *connection;
        TpChannel             *channel;
-       GHashTable            *props;
-       GPtrArray             *channels;
-       char                  *invitees[3] = { NULL, };
-
-       g_print ("INVITE PARTICIPANT\n");
+       int                    response;
+       TpAccount             *account;
 
        priv = GET_PRIV (window);
 
        g_return_if_fail (priv->current_chat != NULL);
 
-       /* FIXME: this is for upgrading a 1-to-1 channel to a MUC, inviting
-        * a user to a MUC is much easier, and needs to be written */
-
        tp_chat = empathy_chat_get_tp_chat (priv->current_chat);
-       connection = empathy_tp_chat_get_connection (tp_chat);
        channel = empathy_tp_chat_get_channel (tp_chat);
+       account = empathy_chat_get_account (priv->current_chat);
+
+       dialog = empathy_invite_participant_dialog_new (
+                       GTK_WINDOW (priv->dialog), account);
+       gtk_widget_show (dialog);
+
+       response = gtk_dialog_run (GTK_DIALOG (dialog));
 
-       /* Ensure a MUC channel */
-       channels = g_ptr_array_sized_new (1);
-       g_ptr_array_add (channels, (char *) tp_proxy_get_object_path (channel));
+       if (response == GTK_RESPONSE_ACCEPT) {
+               TpConnection *connection;
+               EmpathyTpContactFactory *factory;
+               const char *id;
 
-       invitees[0] = (char *) tp_channel_get_identifier (channel);
-       // invitees[1] = /* FIXME: ask for this */
+               id = empathy_contact_selector_dialog_get_selected (
+                               EMPATHY_CONTACT_SELECTOR_DIALOG (dialog), NULL);
+               if (EMP_STR_EMPTY (id)) goto out;
 
-       props = tp_asv_new (
-           TP_IFACE_CHANNEL ".ChannelType", G_TYPE_STRING,
-               TP_IFACE_CHANNEL_TYPE_TEXT,
-           TP_IFACE_CHANNEL ".TargetHandleType", G_TYPE_UINT,
-               TP_HANDLE_TYPE_NONE,
-           EMP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialChannels",
-               TP_ARRAY_TYPE_OBJECT_PATH_LIST, channels,
-           EMP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialInviteeIDs",
-               G_TYPE_STRV, invitees,
-           /* FIXME: InvitationMessage ? */
-           NULL);
+               connection = tp_channel_borrow_connection (channel);
+               factory = empathy_tp_contact_factory_dup_singleton (connection);
 
-       /* FIXME: this probably needs to go through EmpathyDispatcher */
-       tp_cli_connection_interface_requests_call_ensure_channel (
-           connection, -1, props, upgrade_to_muc_cb, NULL, NULL,
-           G_OBJECT (window));
+               empathy_tp_contact_factory_get_from_id (factory, id,
+                       got_contact_cb, tp_chat,  NULL, NULL);
 
-       g_hash_table_destroy (props);
+               g_object_unref (factory);
+       }
+
+out:
+       gtk_widget_destroy (dialog);
 }
 
 static void
@@ -979,6 +1007,19 @@ chat_window_paste_activate_cb (GtkAction         *action,
        empathy_chat_paste (priv->current_chat);
 }
 
+static void
+chat_window_find_activate_cb (GtkAction         *action,
+                             EmpathyChatWindow *window)
+{
+       EmpathyChatWindowPriv *priv;
+
+       g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (window));
+
+       priv = GET_PRIV (window);
+
+       empathy_chat_find (priv->current_chat);
+}
+
 static void
 chat_window_tabs_next_activate_cb (GtkAction         *action,
                                   EmpathyChatWindow *window)
@@ -1280,6 +1321,8 @@ chat_window_new_message_cb (EmpathyChat       *chat,
 
        if (has_focus && priv->current_chat == chat) {
                /* window and tab are focused so consider the message to be read */
+
+               /* FIXME: see Bug#610994 and coments about it in EmpathyChatPriv */
                empathy_chat_messages_read (chat);
                return;
        }
@@ -1495,7 +1538,7 @@ chat_window_focus_in_event_cb (GtkWidget        *widget,
 }
 
 static gboolean
-chat_window_drag_motion (GtkWidget        *widget,
+chat_window_drag_drop (GtkWidget        *widget,
                         GdkDragContext   *context,
                         int               x,
                         int               y,
@@ -1504,14 +1547,36 @@ chat_window_drag_motion (GtkWidget        *widget,
 {
        GdkAtom target;
        EmpathyChatWindowPriv *priv;
-       GdkAtom dest_target;
 
        priv = GET_PRIV (window);
 
-       target = gtk_drag_dest_find_target (widget, context, NULL);
+       target = gtk_drag_dest_find_target (widget, context, priv->file_targets);
+       if (target == GDK_NONE)
+               target = gtk_drag_dest_find_target (widget, context, priv->contact_targets);
+
+       if (target != GDK_NONE) {
+               gtk_drag_get_data (widget, context, target, time_);
+               return TRUE;
+       }
+
+       return FALSE;
+}
 
-       dest_target = gdk_atom_intern_static_string ("text/uri-list");
-       if (target == dest_target) {
+static gboolean
+chat_window_drag_motion (GtkWidget        *widget,
+                        GdkDragContext   *context,
+                        int               x,
+                        int               y,
+                        guint             time_,
+                        EmpathyChatWindow *window)
+{
+       GdkAtom target;
+       EmpathyChatWindowPriv *priv;
+
+       priv = GET_PRIV (window);
+
+       target = gtk_drag_dest_find_target (widget, context, priv->file_targets);
+       if (target != GDK_NONE) {
                /* This is a file drag.  Ensure the contact is online and set the
                   drag type to COPY.  Note that it's possible that the tab will
                   be switched by GTK+ after a timeout from drag_motion without
@@ -1540,8 +1605,8 @@ chat_window_drag_motion (GtkWidget        *widget,
                return TRUE;
        }
 
-       dest_target = gdk_atom_intern_static_string ("text/contact-id");
-       if (target == dest_target) {
+       target = gtk_drag_dest_find_target (widget, context, priv->contact_targets);
+       if (target != GDK_NONE) {
                /* This is a drag of a contact from a contact list.  Set to COPY.
                   FIXME: If this drag is to a MUC window, it invites the user.
                   Otherwise, it opens a chat.  Should we use a different drag
@@ -1551,9 +1616,7 @@ chat_window_drag_motion (GtkWidget        *widget,
                return TRUE;
        }
 
-       /* Otherwise, it must be a notebook tab drag.  Set to MOVE. */
-       gdk_drag_status (context, GDK_ACTION_MOVE, time_);
-       return TRUE;
+       return FALSE;
 }
 
 static void
@@ -1672,23 +1735,10 @@ chat_window_drag_data_received (GtkWidget        *widget,
                        EmpathyChatWindowPriv *priv;
 
                        priv = GET_PRIV (window);
-
-                       if (old_window == window) {
-                               DEBUG ("DND tab (within same window)");
-                               priv->dnd_same_window = TRUE;
-                               gtk_drag_finish (context, TRUE, FALSE, time_);
-                               return;
-                       }
-
-                       priv->dnd_same_window = FALSE;
+                       priv->dnd_same_window = (old_window == window);
+                       DEBUG ("DND tab (within same window: %s)",
+                               priv->dnd_same_window ? "Yes" : "No");
                }
-
-               /* We should return TRUE to remove the data when doing
-                * GDK_ACTION_MOVE, but we don't here otherwise it has
-                * weird consequences, and we handle that internally
-                * anyway with add_chat () and remove_chat ().
-                */
-               gtk_drag_finish (context, TRUE, FALSE, time_);
        } else {
                DEBUG ("DND from unknown source");
                gtk_drag_finish (context, FALSE, FALSE, time_);
@@ -1783,6 +1833,7 @@ empathy_chat_window_init (EmpathyChatWindow *window)
                                       "menu_edit_cut", &priv->menu_edit_cut,
                                       "menu_edit_copy", &priv->menu_edit_copy,
                                       "menu_edit_paste", &priv->menu_edit_paste,
+                                      "menu_edit_find", &priv->menu_edit_find,
                                       "menu_tabs_next", &priv->menu_tabs_next,
                                       "menu_tabs_prev", &priv->menu_tabs_prev,
                                       "menu_tabs_left", &priv->menu_tabs_left,
@@ -1802,6 +1853,7 @@ empathy_chat_window_init (EmpathyChatWindow *window)
                              "menu_edit_cut", "activate", chat_window_cut_activate_cb,
                              "menu_edit_copy", "activate", chat_window_copy_activate_cb,
                              "menu_edit_paste", "activate", chat_window_paste_activate_cb,
+                             "menu_edit_find", "activate", chat_window_find_activate_cb,
                              "menu_tabs_next", "activate", chat_window_tabs_next_activate_cb,
                              "menu_tabs_prev", "activate", chat_window_tabs_previous_activate_cb,
                              "menu_tabs_left", "activate", chat_window_tabs_left_activate_cb,
@@ -1883,7 +1935,7 @@ empathy_chat_window_init (EmpathyChatWindow *window)
 
        /* Set up drag and drop */
        gtk_drag_dest_set (GTK_WIDGET (priv->notebook),
-                          GTK_DEST_DEFAULT_ALL,
+                          GTK_DEST_DEFAULT_HIGHLIGHT,
                           drag_types_dest,
                           G_N_ELEMENTS (drag_types_dest),
                           GDK_ACTION_MOVE | GDK_ACTION_COPY);
@@ -1897,6 +1949,10 @@ empathy_chat_window_init (EmpathyChatWindow *window)
                          "drag-data-received",
                          G_CALLBACK (chat_window_drag_data_received),
                          window);
+       g_signal_connect (priv->notebook,
+                         "drag-drop",
+                         G_CALLBACK (chat_window_drag_drop),
+                         window);
 
        chat_windows = g_list_prepend (chat_windows, window);
 
@@ -1983,6 +2039,7 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window,
        GtkWidget             *label;
        GtkWidget             *popup_label;
        GtkWidget             *child;
+       GValue                value = { 0, };
 
        g_return_if_fail (window != NULL);
        g_return_if_fail (EMPATHY_IS_CHAT (chat));
@@ -2030,8 +2087,13 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window,
        gtk_notebook_append_page_menu (GTK_NOTEBOOK (priv->notebook), child, label, popup_label);
        gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (priv->notebook), child, TRUE);
        gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (priv->notebook), child, TRUE);
-       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (priv->notebook), child,
-                                           TRUE, TRUE, GTK_PACK_START);
+       g_value_init (&value, G_TYPE_BOOLEAN);
+       g_value_set_boolean (&value, TRUE);
+       gtk_container_child_set_property (GTK_CONTAINER (priv->notebook),
+                                         child, "tab-expand" , &value);
+       gtk_container_child_set_property (GTK_CONTAINER (priv->notebook),
+                                         child,  "tab-fill" , &value);
+       g_value_unset (&value);
 
        DEBUG ("Chat added (%d references)", G_OBJECT (chat)->ref_count);
 }
@@ -2184,7 +2246,7 @@ empathy_chat_window_present_chat (EmpathyChat *chat)
 
        priv = GET_PRIV (window);
        empathy_chat_window_switch_to_chat (window, chat);
-       empathy_window_present (GTK_WINDOW (priv->dialog), TRUE);
+       empathy_window_present (GTK_WINDOW (priv->dialog));
 
        gtk_widget_grab_focus (chat->input_text_view);
 }