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;
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,
data = g_slice_new0 (DndGetContactData);
data->new_group = new_group;
data->old_group = old_group;
- data->action = context->action;
+ data->action = gdk_drag_context_get_selected_action (context);
/* FIXME: We should probably wait for the cb before calling
* gtk_drag_finish */
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);
}
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);
GdkEventKey *event,
gpointer user_data)
{
- if (event->keyval == GDK_Menu) {
+ if (event->keyval == GDK_KEY_Menu) {
MenuPopupData *data;
data = g_slice_new (MenuPopupData);
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);
}
}
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);
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
gtk_tree_view_collapse_row (GTK_TREE_VIEW (view), path);
}
- gtk_tree_path_free(path);
+ gtk_tree_path_free (path);
g_free (name);
}
typedef struct {
EmpathyContactListView *view;
- GtkTreePath *path;
+ GtkTreeRowReference *row_ref;
gboolean expand;
} ExpandData;
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;
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)) ||
empathy_contact_group_get_expanded (name);
- /* FIXME: It doesn't work to call gtk_tree_view_expand_row() from within
- * gtk_tree_model_filter_refilter() */
+ /* FIXME: It doesn't work to call gtk_tree_view_expand_row () from within
+ * gtk_tree_model_filter_refilter () */
g_idle_add (contact_list_view_expand_idle_cb, data);
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)
{
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,
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
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;
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);
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);