Interactive search capability for TreeView



Hi all,

This patch will add an interactive search capability to the TreeView
widget. Consider this as a first snapshot, there're still some issues with
it.

How does it work? Give the TreeView the focus and press C-f, a little
window with an entry will pop up. Type the first characters of the row
you're searching, as you type all matching items will be selected. Press
escape to get rid of the window.

Issues:
1. only if the selection mode is set to GTK_TREE_SELECTION_MULTI,
multiple items will be selected when typing. If not, only the latest item
found will be selected.
2. I think it's really slow if you use it with big TreeViews. Haven't
tested this though.
3. The window which pops up is a GTK_WINDOW_TOPLEVEL and not a
GTK_WINDOW_POPUP. Should it be a GTK_WINDOW_POPUP?
4. I think the TreeView should scroll to the item which will be selected
first.

I hope this is a step in the right direction. If not, please tell me, I'll
be open for any suggestions.

regards,


	Kris

-- 
Odi et amo. Quare id faciam, fortasse requiris?
	Nescio, sed fieri sentio et excrucior.

-Catullus (Carmen 85)

Index: gtk+/gtk/gtktreeview.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktreeview.c,v
retrieving revision 1.106
diff -u -r1.106 gtktreeview.c
--- gtk+/gtk/gtktreeview.c	2001/06/27 23:44:52	1.106
+++ gtk+/gtk/gtktreeview.c	2001/06/29 23:43:47
@@ -32,7 +32,10 @@
 #include "gtkarrow.h"
 #include "gtkintl.h"
 #include "gtkbindings.h"
+#include "gtkcontainer.h"
+#include "gtkentry.h"
 
+#include <string.h>
 #include <gdk/gdkkeysyms.h>
 
 #if defined (GDK_WINDOWING_X11)
@@ -107,6 +110,7 @@
   TOGGLE_CURSOR_ROW,
   EXPAND_COLLAPSE_CURSOR_ROW,
   SELECT_CURSOR_PARENT,
+  INTERACTIVE_SEARCH,
   LAST_SIGNAL
 };
 
@@ -217,6 +221,7 @@
                                                   guint             time);
 
 /* tree_model signals */
+static void gtk_tree_view_interactive_search              (GtkTreeView     *tree_view);
 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
 							   GtkAdjustment   *hadj,
 							   GtkAdjustment   *vadj);
@@ -258,7 +263,6 @@
 							   gpointer         data);
 
 
-
 /* Internal functions */
 
 static void     gtk_tree_view_add_move_binding     (GtkBindingSet    *binding_set,
@@ -343,6 +347,17 @@
 					   GtkTreePath     *path,
 					   gboolean         clear_and_select);
 
+/* interactive search */
+static gint gtk_tree_view_interactive_search_key_press_event (GtkWidget      *entry,
+							      GdkEventKey    *event,
+							      gpointer        data);
+static void gtk_tree_view_interactive_search_search_childs   (GtkTreeModel     *model,
+		                                              GtkTreeSelection *selection,
+		                                              GtkTreeIter      *iter,
+							      gchar            *text);
+static void gtk_tree_view_interactive_search_search          (GtkWidget        *entry,
+							      GtkTreeView      *tree_view);
+
 
 static GtkContainerClass *parent_class = NULL;
 static guint tree_view_signals[LAST_SIGNAL] = { 0 };
@@ -443,6 +458,7 @@
   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
+  class->interactive_search = gtk_tree_view_interactive_search;
 
   /* Properties */
 
@@ -708,7 +724,16 @@
 		   NULL, NULL,
 		   gtk_marshal_NONE__NONE,
 		   GTK_TYPE_NONE, 0);
-
+  
+  tree_view_signals[INTERACTIVE_SEARCH] =
+    g_signal_newc ("interactive_search",
+		   G_TYPE_FROM_CLASS (object_class),
+		   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
+		   G_STRUCT_OFFSET (GtkTreeViewClass, interactive_search),
+		   NULL, NULL,
+		   gtk_marshal_NONE__NONE,
+		   GTK_TYPE_NONE, 0);
+  
   /* Key bindings */
   gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, 0, "begin_extended_selection", 0);
   gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, GDK_SHIFT_MASK | GDK_RELEASE_MASK, "end_extended_selection", 0);
@@ -810,9 +835,11 @@
 				GTK_TYPE_BOOL, FALSE,
 				GTK_TYPE_BOOL, FALSE,
 				GTK_TYPE_BOOL, TRUE);
-
+  
   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
-
+  
+  /* interactive search */
+  gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "interactive_search", 0);
 }
 
 static void
@@ -8205,4 +8232,139 @@
   tree_view->priv->destroy_count_func = func;
   tree_view->priv->destroy_count_data = data;
   tree_view->priv->destroy_count_destroy = destroy;
+}
+
+
+/* interactive search 
+ */
+
+static void
+gtk_tree_view_interactive_search (GtkTreeView *tree_view)
+{
+  GtkWidget *window;
+  GtkWidget *entry;
+  
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+  
+  /* set up window */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window), "search dialog");
+  gtk_container_set_border_width (GTK_CONTAINER (window), 3);
+  gtk_signal_connect_object (GTK_OBJECT (window), "delete_event",
+			     GTK_SIGNAL_FUNC (gtk_widget_destroy),
+			     GTK_OBJECT (window));
+  gtk_signal_connect 
+    (GTK_OBJECT (window), "key_press_event",
+     GTK_SIGNAL_FUNC (gtk_tree_view_interactive_search_key_press_event),
+     NULL);
+  
+  entry = gtk_entry_new ();
+  gtk_signal_connect
+    (GTK_OBJECT (entry), "changed",
+     GTK_SIGNAL_FUNC (gtk_tree_view_interactive_search_search),
+     tree_view);
+  gtk_container_add (GTK_CONTAINER (window), entry);
+  
+  gtk_widget_show_all (window);
+  gtk_widget_grab_focus (entry);
+}
+
+static gint
+gtk_tree_view_interactive_search_key_press_event (GtkWidget *widget,
+						  GdkEventKey *event,
+						  gpointer data)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+  
+  if (event->keyval == GDK_Escape)
+    {
+      gtk_widget_destroy (widget);
+      return TRUE;
+    }
+  
+  return FALSE;
+}
+
+static void
+gtk_tree_view_interactive_search_search_childs (GtkTreeModel     *model,
+						GtkTreeSelection *selection,
+						GtkTreeIter      *iter,
+						gchar            *text)
+{
+  gint len = strlen (text);
+  gchar *tmp;
+  GValue value = {0,};
+  
+  gtk_tree_model_get_value (model, iter, 0, &value);
+  tmp = g_strdup (g_value_get_string (&value));
+  if (!strncmp (text, tmp, len))
+    gtk_tree_selection_select_iter (selection, iter);
+  g_value_unset (&value);
+  
+  if (gtk_tree_model_iter_has_child (model, iter))
+    {
+      GtkTreeIter child;
+      
+      gtk_tree_model_iter_children (model, &child, iter);
+      gtk_tree_view_interactive_search_search_childs (model,
+						      selection,
+						      &child,
+						      text);	 
+    }
+  
+  while (gtk_tree_model_iter_next (model, iter))
+    {
+      gtk_tree_model_get_value (model, iter, 0, &value);
+      tmp = g_value_get_string (&value);
+      if (!strncmp (text, tmp, len))
+	gtk_tree_selection_select_iter (selection, iter);
+      g_value_unset (&value);
+      
+      if (gtk_tree_model_iter_has_child (model, iter))
+	{
+	  GtkTreeIter child;
+	  
+	  gtk_tree_model_iter_children (model, &child, iter);
+	  gtk_tree_view_interactive_search_search_childs (model,
+							  selection,
+							  &child,
+							  text);	 
+	}
+    }
+}
+
+static void
+gtk_tree_view_interactive_search_search (GtkWidget   *entry,
+					 GtkTreeView *tree_view)
+{
+  gint len;
+  gchar *text;
+  GtkWidget *window;
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  GtkTreeSelection *selection;
+  
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+  
+  window = gtk_widget_get_parent (entry);
+  text = gtk_entry_get_text (GTK_ENTRY (entry));
+  len = strlen (text);
+  model = gtk_tree_view_get_model (tree_view);
+  selection = gtk_tree_view_get_selection (tree_view);
+  
+  /* search */
+  gtk_tree_selection_unselect_all (selection);
+
+  if (len < 1)
+    return;
+  
+  gtk_tree_model_get_iter_root (model, &iter);
+  
+  gtk_tree_view_interactive_search_search_childs (model,
+						  selection,
+						  &iter,
+						  text);
+  
+  return;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]