]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-contact-list-view.c
Merge branch 'sasl'
[empathy.git] / libempathy-gtk / empathy-contact-list-view.c
index 8d0cd784fbcbabb7277f418981b2019408d50c51..1b11309f3f150efd8047dab08b48afd3479ec152 100644 (file)
@@ -149,8 +149,10 @@ contact_list_view_is_visible_contact (EmpathyContactListView *self,
        gchar *dup_str = NULL;
        gboolean visible;
 
+       g_assert (live != NULL);
+
        /* check alias name */
-       str = empathy_contact_get_name (contact);
+       str = empathy_contact_get_alias (contact);
        if (empathy_live_search_match (live, str))
                return TRUE;
 
@@ -183,7 +185,8 @@ contact_list_view_filter_visible_func (GtkTreeModel *model,
        GtkTreeIter                 child_iter;
        gboolean                    visible;
 
-       if (!gtk_widget_get_visible (priv->search_widget))
+       if (priv->search_widget == NULL ||
+           !gtk_widget_get_visible (priv->search_widget))
                return TRUE;
 
        gtk_tree_model_get (model, iter,
@@ -760,11 +763,9 @@ contact_list_view_drag_data_get (GtkWidget        *widget,
        g_object_unref (contact);
        str = g_strconcat (account_id, ":", contact_id, NULL);
 
-       switch (info) {
-       case DND_DRAG_TYPE_CONTACT_ID:
+       if (info == DND_DRAG_TYPE_CONTACT_ID) {
                gtk_selection_data_set (selection, drag_atoms_source[info], 8,
                                        (guchar *) str, strlen (str) + 1);
-               break;
        }
 
        g_free (str);
@@ -815,8 +816,6 @@ contact_list_view_popup_menu_idle_cb (gpointer user_data)
        }
 
        if (menu) {
-               g_signal_connect (menu, "deactivate",
-                                 G_CALLBACK (gtk_menu_detach), NULL);
                gtk_menu_attach_to_widget (GTK_MENU (menu),
                                           GTK_WIDGET (data->view), NULL);
                gtk_widget_show (menu);
@@ -855,7 +854,7 @@ contact_list_view_key_press_event_cb (EmpathyContactListView *view,
                                      GdkEventKey            *event,
                                      gpointer                user_data)
 {
-       if (event->keyval == GDK_Menu) {
+       if (event->keyval == GDK_KEY_Menu) {
                MenuPopupData *data;
 
                data = g_slice_new (MenuPopupData);
@@ -891,7 +890,7 @@ contact_list_view_row_activated (GtkTreeView       *view,
        if (contact) {
                DEBUG ("Starting a chat");
                empathy_dispatcher_chat_with_contact (contact,
-                       gtk_get_current_event_time (), NULL, NULL);
+                       gtk_get_current_event_time ());
                g_object_unref (contact);
        }
 }
@@ -935,8 +934,6 @@ contact_list_view_call_activated_cb (
        gtk_menu_shell_append (shell, item);
        gtk_widget_show (item);
 
-       g_signal_connect (menu, "deactivate",
-                         G_CALLBACK (gtk_menu_detach), NULL);
        gtk_menu_attach_to_widget (GTK_MENU (menu),
                                   GTK_WIDGET (view), NULL);
        gtk_widget_show (menu);
@@ -1210,8 +1207,89 @@ contact_list_view_search_text_notify_cb (EmpathyLiveSearch      *search,
                                         EmpathyContactListView *view)
 {
        EmpathyContactListViewPriv *priv = GET_PRIV (view);
+       GtkTreePath *path;
+       GtkTreeViewColumn *focus_column;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       gboolean set_cursor = FALSE;
 
        gtk_tree_model_filter_refilter (priv->filter);
+
+       /* Set cursor on the first contact. If it is already set on a group,
+        * set it on its first child contact. Note that first child of a group
+        * is its separator, that's why we actually set to the 2nd
+        */
+
+       model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+       gtk_tree_view_get_cursor (GTK_TREE_VIEW (view), &path, &focus_column);
+
+       if (path == NULL) {
+               path = gtk_tree_path_new_from_string ("0:1");
+               set_cursor = TRUE;
+       } else if (gtk_tree_path_get_depth (path) < 2) {
+               gboolean is_group;
+
+               gtk_tree_model_get_iter (model, &iter, path);
+               gtk_tree_model_get (model, &iter,
+                       EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+                       -1);
+
+               if (is_group) {
+                       gtk_tree_path_down (path);
+                       gtk_tree_path_next (path);
+                       set_cursor = TRUE;
+               }
+       }
+
+       if (set_cursor) {
+               /* FIXME: Workaround for GTK bug #621651, we have to make sure
+                * the path is valid. */
+               if (gtk_tree_model_get_iter (model, &iter, path)) {
+                       gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path,
+                               focus_column, FALSE);
+               }
+       }
+
+       gtk_tree_path_free (path);
+}
+
+static void
+contact_list_view_search_activate_cb (GtkWidget *search,
+                                     EmpathyContactListView *view)
+{
+       GtkTreePath *path;
+       GtkTreeViewColumn *focus_column;
+
+       gtk_tree_view_get_cursor (GTK_TREE_VIEW (view), &path, &focus_column);
+       if (path != NULL) {
+               gtk_tree_view_row_activated (GTK_TREE_VIEW (view), path,
+                       focus_column);
+               gtk_tree_path_free (path);
+
+               gtk_widget_hide (search);
+       }
+}
+
+static gboolean
+contact_list_view_search_key_navigation_cb (GtkWidget *search,
+                                           GdkEvent *event,
+                                           EmpathyContactListView *view)
+{
+       GdkEventKey *eventkey = ((GdkEventKey *) event);
+       gboolean ret = FALSE;
+
+       if (eventkey->keyval == GDK_KEY_Up || eventkey->keyval == GDK_KEY_Down) {
+               GdkEvent *new_event;
+
+               new_event = gdk_event_copy (event);
+               gtk_widget_grab_focus (GTK_WIDGET (view));
+               ret = gtk_widget_event (GTK_WIDGET (view), new_event);
+               gtk_widget_grab_focus (search);
+
+               gdk_event_free (new_event);
+       }
+
+       return ret;
 }
 
 static void
@@ -1291,7 +1369,7 @@ contact_list_view_search_show_cb (EmpathyLiveSearch      *search,
 
 typedef struct {
        EmpathyContactListView *view;
-       GtkTreePath *path;
+       GtkTreeRowReference *row_ref;
        gboolean expand;
 } ExpandData;
 
@@ -1299,25 +1377,31 @@ static gboolean
 contact_list_view_expand_idle_cb (gpointer user_data)
 {
        ExpandData *data = user_data;
+       GtkTreePath *path;
+
+       path = gtk_tree_row_reference_get_path (data->row_ref);
+       if (path == NULL)
+               goto done;
 
        g_signal_handlers_block_by_func (data->view,
                contact_list_view_row_expand_or_collapse_cb,
                GINT_TO_POINTER (data->expand));
 
        if (data->expand) {
-               gtk_tree_view_expand_row (GTK_TREE_VIEW (data->view),
-                       data->path, TRUE);
+               gtk_tree_view_expand_row (GTK_TREE_VIEW (data->view), path,
+                   TRUE);
        } else {
-               gtk_tree_view_collapse_row (GTK_TREE_VIEW (data->view),
-                       data->path);
+               gtk_tree_view_collapse_row (GTK_TREE_VIEW (data->view), path);
        }
+       gtk_tree_path_free (path);
 
        g_signal_handlers_unblock_by_func (data->view,
                contact_list_view_row_expand_or_collapse_cb,
                GINT_TO_POINTER (data->expand));
 
+done:
        g_object_unref (data->view);
-       gtk_tree_path_free (data->path);
+       gtk_tree_row_reference_free (data->row_ref);
        g_slice_free (ExpandData, data);
 
        return FALSE;
@@ -1346,7 +1430,7 @@ contact_list_view_row_has_child_toggled_cb (GtkTreeModel           *model,
 
        data = g_slice_new0 (ExpandData);
        data->view = g_object_ref (view);
-       data->path = gtk_tree_path_copy (path);
+       data->row_ref = gtk_tree_row_reference_new (model, path);
        data->expand =
                (priv->list_features & EMPATHY_CONTACT_LIST_FEATURE_GROUPS_SAVE) == 0 ||
                (priv->search_widget != NULL && gtk_widget_get_visible (priv->search_widget)) ||
@@ -1359,6 +1443,52 @@ contact_list_view_row_has_child_toggled_cb (GtkTreeModel           *model,
        g_free (name);
 }
 
+static void
+contact_list_view_verify_group_visibility (EmpathyContactListView *view,
+                                          GtkTreePath            *path)
+{
+       EmpathyContactListViewPriv *priv = GET_PRIV (view);
+       GtkTreeModel *model;
+       GtkTreePath *parent_path;
+       GtkTreeIter parent_iter;
+
+       if (gtk_tree_path_get_depth (path) < 2)
+               return;
+
+       /* A group row is visible if and only if at least one if its child is
+        * visible. So when a row is inserted/deleted/changed in the base model,
+        * that could modify the visibility of its parent in the filter model.
+        */
+
+       model = GTK_TREE_MODEL (priv->store);
+       parent_path = gtk_tree_path_copy (path);
+       gtk_tree_path_up (parent_path);
+       if (gtk_tree_model_get_iter (model, &parent_iter, parent_path)) {
+               /* This tells the filter to verify the visibility of that row,
+                * and show/hide it if necessary */
+               gtk_tree_model_row_changed (GTK_TREE_MODEL (priv->store),
+                       parent_path, &parent_iter);
+       }
+       gtk_tree_path_free (parent_path);
+}
+
+static void
+contact_list_view_store_row_changed_cb (GtkTreeModel           *model,
+                                       GtkTreePath            *path,
+                                       GtkTreeIter            *iter,
+                                       EmpathyContactListView *view)
+{
+       contact_list_view_verify_group_visibility (view, path);
+}
+
+static void
+contact_list_view_store_row_deleted_cb (GtkTreeModel           *model,
+                                       GtkTreePath            *path,
+                                       EmpathyContactListView *view)
+{
+       contact_list_view_verify_group_visibility (view, path);
+}
+
 static void
 contact_list_view_constructed (GObject *object)
 {
@@ -1368,10 +1498,6 @@ contact_list_view_constructed (GObject *object)
        GtkTreeViewColumn          *col;
        guint                       i;
 
-       gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view),
-                                            empathy_contact_list_store_search_equal_func,
-                                            NULL, NULL);
-
        priv->filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (
                        GTK_TREE_MODEL (priv->store), NULL));
        gtk_tree_model_filter_set_visible_func (priv->filter,
@@ -1385,6 +1511,16 @@ contact_list_view_constructed (GObject *object)
        gtk_tree_view_set_model (GTK_TREE_VIEW (view),
                                 GTK_TREE_MODEL (priv->filter));
 
+       tp_g_signal_connect_object (priv->store, "row-changed",
+               G_CALLBACK (contact_list_view_store_row_changed_cb),
+               view, 0);
+       tp_g_signal_connect_object (priv->store, "row-inserted",
+               G_CALLBACK (contact_list_view_store_row_changed_cb),
+               view, 0);
+       tp_g_signal_connect_object (priv->store, "row-deleted",
+               G_CALLBACK (contact_list_view_store_row_deleted_cb),
+               view, 0);
+
        /* Setup view */
        /* Setting reorderable is a hack that gets us row previews as drag icons
           for free.  We override all the drag handlers.  It's tricky to get the
@@ -1943,7 +2079,7 @@ contact_list_view_remove_activate_cb (GtkMenuItem            *menuitem,
 
                parent = empathy_get_toplevel_window (GTK_WIDGET (view));
                text = g_strdup_printf (_("Do you really want to remove the contact '%s'?"),
-                                       empathy_contact_get_name (contact));
+                                       empathy_contact_get_alias (contact));
                if (contact_list_view_remove_dialog_show (parent, _("Removing contact"), text)) {
                        EmpathyContactList *list;
 
@@ -2020,6 +2156,12 @@ empathy_contact_list_view_set_live_search (EmpathyContactListView *view,
                g_signal_handlers_disconnect_by_func (priv->search_widget,
                        contact_list_view_search_text_notify_cb,
                        view);
+               g_signal_handlers_disconnect_by_func (priv->search_widget,
+                       contact_list_view_search_activate_cb,
+                       view);
+               g_signal_handlers_disconnect_by_func (priv->search_widget,
+                       contact_list_view_search_key_navigation_cb,
+                       view);
                g_signal_handlers_disconnect_by_func (priv->search_widget,
                        contact_list_view_search_hide_cb,
                        view);
@@ -2041,6 +2183,12 @@ empathy_contact_list_view_set_live_search (EmpathyContactListView *view,
                g_signal_connect (priv->search_widget, "notify::text",
                        G_CALLBACK (contact_list_view_search_text_notify_cb),
                        view);
+               g_signal_connect (priv->search_widget, "activate",
+                       G_CALLBACK (contact_list_view_search_activate_cb),
+                       view);
+               g_signal_connect (priv->search_widget, "key-navigation",
+                       G_CALLBACK (contact_list_view_search_key_navigation_cb),
+                       view);
                g_signal_connect (priv->search_widget, "hide",
                        G_CALLBACK (contact_list_view_search_hide_cb),
                        view);