changeset 15160:c6b79e535eb8

[gaim-migrate @ 17946] Experimental search-as-you-type in GntTree. Press "/" to enter the search-mode, and when you're done, press escape to cancel. The search-mode remains active for 4 seconds before returning to normal. Someone should update the manual, and possibly enhance the behaviour. committer: Tailor Script <tailor@pidgin.im>
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Sun, 10 Dec 2006 11:26:17 +0000
parents 9ca8095b6243
children bface7451bd1
files console/gntblist.c console/libgnt/gnttree.c console/libgnt/gnttree.h
diffstat 3 files changed, 108 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/console/gntblist.c	Sun Dec 10 09:38:02 2006 +0000
+++ b/console/gntblist.c	Sun Dec 10 11:26:17 2006 +0000
@@ -1362,11 +1362,13 @@
 	} else if (strcmp(text, GNT_KEY_CTRL_O) == 0) {
 		gaim_prefs_set_bool(PREF_ROOT "/showoffline",
 				!gaim_prefs_get_bool(PREF_ROOT "/showoffline"));
-	} else if (strcmp(text, "t") == 0) {
-		gg_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
-		gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "move-down");
-	} else if (strcmp(text, "a") == 0) {
-		gg_blist_place_tagged(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
+	} else if (GNT_TREE(ggblist->tree)->search == NULL) {
+		if (strcmp(text, "t") == 0) {
+			gg_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
+			gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "move-down");
+		} else if (strcmp(text, "a") == 0) {
+			gg_blist_place_tagged(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
+		}
 	} else
 		return FALSE;
 
--- a/console/libgnt/gnttree.c	Sun Dec 10 09:38:02 2006 +0000
+++ b/console/libgnt/gnttree.c	Sun Dec 10 11:26:17 2006 +0000
@@ -6,6 +6,8 @@
 #include <string.h>
 #include <ctype.h>
 
+#define SEARCH_TIMEOUT 4000   /* 4 secs */
+
 enum
 {
 	SIG_SELECTION_CHANGED,
@@ -35,6 +37,7 @@
 	GntTreeRow *prev;
 
 	GList *columns;
+	GntTree *tree;
 };
 
 struct _GnTreeCol
@@ -70,12 +73,32 @@
 	return _get_next(row->parent, FALSE);
 }
 
+static gboolean
+row_matches_search(GntTreeRow *row)
+{
+	GntTree *t = row->tree;
+	if (t->search && t->search->len > 0) {
+		char *one = g_utf8_casefold(((GntTreeCol*)row->columns->data)->text, -1);
+		char *two = g_utf8_casefold(t->search->str, -1);
+		char *z = strstr(one, two);
+		g_free(one);
+		g_free(two);
+		if (z == NULL)
+			return FALSE;
+	}
+	return TRUE;
+}
+
 static GntTreeRow *
 get_next(GntTreeRow *row)
 {
 	if (row == NULL)
 		return NULL;
-	return _get_next(row, !row->collapsed);
+	while ((row = _get_next(row, !row->collapsed)) != NULL) {
+		if (row_matches_search(row))
+			break;
+	}
+	return row;
 }
 
 /* Returns the n-th next row. If it doesn't exist, returns NULL */
@@ -135,9 +158,15 @@
 {
 	if (row == NULL)
 		return NULL;
-	if (row->prev)
-		return get_last_child(row->prev);
-	return row->parent;
+	while (row) {
+		if (row->prev)
+			row = get_last_child(row->prev);
+		else
+			row = row->parent;
+		if (!row || row_matches_search(row))
+			break;
+	}
+	return row;
 }
 
 static GntTreeRow *
@@ -332,6 +361,8 @@
 	else if (up >= widget->priv.height - pos)
 		tree->top = get_prev_n(tree->current, rows);
 
+	if (tree->top && !row_matches_search(tree->top))
+		tree->top = get_next(tree->top);
 	row = tree->top;
 	scrcol = widget->priv.width - 1 - 2 * pos;  /* exclude the borders and the scrollbar */
 	for (i = start + pos; row && i < widget->priv.height - pos;
@@ -343,6 +374,8 @@
 		GntTextFormatFlags flags = row->flags;
 		int attr = 0;
 
+		if (!row_matches_search(row))
+			continue;
 		str = update_row_text(tree, row);
 
 		if ((wr = gnt_util_onscreen_width(str, NULL)) > scrcol)
@@ -574,18 +607,46 @@
 	return TRUE;
 }
 
+static void
+end_search(GntTree *tree)
+{
+	if (tree->search) {
+		g_source_remove(tree->search_timeout);
+		g_string_free(tree->search, TRUE);
+		tree->search = NULL;
+		tree->search_timeout = 0;
+	}
+}
+
+static gboolean
+search_timeout(gpointer data)
+{
+	GntTree *tree = data;
+
+	end_search(tree);
+	redraw_tree(tree);
+
+	return FALSE;
+}
+
 static gboolean
 gnt_tree_key_pressed(GntWidget *widget, const char *text)
 {
 	GntTree *tree = GNT_TREE(widget);
 	GntTreeRow *old = tree->current;
 
-	if (text[0] == '\r')
-	{
+	if (text[0] == '\r') {
+		end_search(tree);
 		gnt_widget_activate(widget);
-	}
-	else if (text[0] == ' ' && text[1] == 0)
-	{
+	} else if (tree->search) {
+		if (isalnum(*text)) {
+			tree->search = g_string_append_c(tree->search, *text);
+			redraw_tree(tree);
+			g_source_remove(tree->search_timeout);
+			tree->search_timeout = g_timeout_add(SEARCH_TIMEOUT, search_timeout, tree);
+		}
+		return TRUE;
+	} else if (text[0] == ' ' && text[1] == 0) {
 		/* Space pressed */
 		GntTreeRow *row = tree->current;
 		if (row && row->child)
@@ -616,6 +677,7 @@
 	GntTree *tree = GNT_TREE(widget);
 	int i;
 
+	end_search(tree);
 	g_hash_table_destroy(tree->hash);
 	g_list_free(tree->list);
 
@@ -684,6 +746,28 @@
 		tree->columns[tree->ncol - 1].width += widget->priv.width - n - 2 - 1 * tree->ncol;
 }
 
+static gboolean
+start_search(GntBindable *bindable, GList *list)
+{
+	GntTree *tree = GNT_TREE(bindable);
+	if (tree->search)
+		return FALSE;
+	tree->search = g_string_new(NULL);
+	tree->search_timeout = g_timeout_add(SEARCH_TIMEOUT, search_timeout, tree);
+	return TRUE;
+}
+
+static gboolean
+end_search_action(GntBindable *bindable, GList *list)
+{
+	GntTree *tree = GNT_TREE(bindable);
+	if (tree->search == NULL)
+		return FALSE;
+	end_search(tree);
+	redraw_tree(tree);
+	return TRUE;
+}
+
 static void
 gnt_tree_class_init(GntTreeClass *klass)
 {
@@ -732,6 +816,10 @@
 				GNT_KEY_PGUP, NULL);
 	gnt_bindable_class_register_action(bindable, "page-down", action_page_down,
 				GNT_KEY_PGDOWN, NULL);
+	gnt_bindable_class_register_action(bindable, "start-search", start_search,
+				"/", NULL);
+	gnt_bindable_class_register_action(bindable, "end-search", end_search_action,
+				"\033", NULL);
 
 	gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), bindable);
 	GNTDEBUG;
@@ -956,6 +1044,7 @@
 	GntTreeRow *pr = NULL;
 
 	g_hash_table_replace(tree->hash, key, row);
+	row->tree = tree;
 
 	if (bigbro == NULL && tree->compare)
 	{
--- a/console/libgnt/gnttree.h	Sun Dec 10 09:38:02 2006 +0000
+++ b/console/libgnt/gnttree.h	Sun Dec 10 11:26:17 2006 +0000
@@ -52,6 +52,9 @@
 	gboolean show_title;
 	gboolean show_separator; /* Whether to show column separators */
 
+	GString *search;
+	int search_timeout;
+
 	GCompareFunc compare;
 };