Interactive search code for TreeView: new patch
- From: Kristian Rietveld <kristian planet nl>
- To: <jrb redhat com>
- Cc: GTK Development list <gtk-devel-list gnome org>
- Subject: Interactive search code for TreeView: new patch
- Date: Sun, 8 Jul 2001 20:30:02 +0200 (CEST)
Hi,
Here's a new patch which adds the interactive search stuff to the
TreeView. Much has changed, a short summary:
- The search dialog is a GTK_WINDOW_POPUP now.
- I found out that the keybinding C-f was already used by the TreeView, so
I removed the C-f keybinding for the search dialog. If you select the
TreeView and start typing, the search dialog will pop up.
- the TreeView will scroll to the selected item now
- If there are more matching iters, you can cycle through them with the
arrow keys
- To get rid of the search dialog you can press Escape/Tab/Enter or just
click somewhere.
- It's now possible to set the search column. See
gtk_tree_view_interactive_search_set_search_column () and
gtk_tree_view_interactive_search_get_search_column (). Both functions
have got doc comments.
`
Other ideas, which are not implemented yet:
- make the position of the search dialog configurable?
- add code which enables people to use their own search functions.
That's all for now. Please mail your suggestions/comments/etc.
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.110
diff -u -r1.110 gtktreeview.c
--- gtk+/gtk/gtktreeview.c 2001/06/30 21:15:27 1.110
+++ gtk+/gtk/gtktreeview.c 2001/07/08 18:00:04
@@ -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)
@@ -344,7 +347,28 @@
GtkTreePath *path,
gboolean clear_and_select);
+/* interactive search */
+static gboolean gtk_tree_view_interactive_search_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data);
+static gboolean gtk_tree_view_interactive_search_key_press_event (GtkWidget *entry,
+ GdkEventKey *event,
+ GtkTreeView *tree_view);
+static void gtk_tree_view_interactive_search_search_move (GtkWidget *window,
+ GtkTreeView *tree_view,
+ gboolean up);
+static gboolean gtk_tree_view_interactive_search_search_iter (GtkTreeModel *model,
+ GtkTreeSelection *selection,
+ GtkTreeIter *iter,
+ gchar *text,
+ gint *count,
+ gint n);
+static void gtk_tree_view_interactive_search_init (GtkWidget *entry,
+ GtkTreeView *tree_view);
+static void gtk_tree_view_interactive_search (GtkTreeView *tree_view,
+ gchar first_char);
+
static GtkContainerClass *parent_class = NULL;
static guint tree_view_signals[LAST_SIGNAL] = { 0 };
@@ -835,6 +859,7 @@
gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
_gtk_tree_view_update_size (tree_view);
+ tree_view->priv->search_column = 0;
}
@@ -958,7 +983,7 @@
tree_view->priv->model = NULL;
}
- if (tree_view->priv->columns != NULL)
+ if (tree_view->priv->columns != NULL)
{
for (list = tree_view->priv->columns; list; list = list->next)
g_object_unref (G_OBJECT (list->data));
@@ -2777,6 +2802,13 @@
}
return TRUE;
}
+
+ if (event->keyval >= GDK_A && event->keyval <= GDK_z)
+ {
+ gtk_tree_view_interactive_search (tree_view, event->keyval);
+ return TRUE;
+ }
+
return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
}
@@ -8214,4 +8246,357 @@
tree_view->priv->destroy_count_func = func;
tree_view->priv->destroy_count_data = data;
tree_view->priv->destroy_count_destroy = destroy;
+}
+
+
+/* interactive search
+ */
+
+/**
+ * gtk_tree_view_interactive_search_get_search_column:
+ * @tree_view: A #GtkTreeView
+ *
+ * Gets the column searched on by the interactive search code.
+ *
+ * Return value: the column the interactive search code searches in.
+ */
+gint
+gtk_tree_view_interactive_search_get_search_column (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
+
+ return (tree_view->priv->search_column);
+}
+
+/**
+ * gtk_tree_view_interactive_search_set_search_column:
+ * @tree_view: A #GtkTreeView
+ * @column: the column to search in
+ *
+ * Sets @column as the column where the interactive search code should search in.
+ */
+void
+gtk_tree_view_interactive_search_set_search_column (GtkTreeView *tree_view,
+ gint column)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ g_return_if_fail (column >= 0);
+
+ tree_view->priv->search_column = column;
+}
+
+static void
+gtk_tree_view_interactive_search (GtkTreeView *tree_view,
+ gchar first_char)
+{
+ gint ox, oy;
+ gint width, height;
+ gint pwidth, pheight;
+ gchar hack[2] = {first_char, 0};
+ GtkWidget *window;
+ GtkWidget *entry;
+ GdkWindow *parent_window;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ /* set up window */
+ window = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_window_set_title (GTK_WINDOW (window), "search dialog");
+ gtk_container_set_border_width (GTK_CONTAINER (window), 3);
+ gtk_window_set_modal (GTK_WINDOW (window), TRUE);
+ 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),
+ tree_view);
+ gtk_signal_connect
+ (GTK_OBJECT (window), "button_press_event",
+ GTK_SIGNAL_FUNC (gtk_tree_view_interactive_search_button_press_event),
+ tree_view);
+
+ /* add entry */
+ entry = gtk_entry_new ();
+ gtk_entry_append_text (GTK_ENTRY (entry), hack);
+ gtk_editable_set_position (GTK_EDITABLE (entry), 2);
+ gtk_signal_connect
+ (GTK_OBJECT (entry), "changed",
+ GTK_SIGNAL_FUNC (gtk_tree_view_interactive_search_init),
+ tree_view);
+ gtk_container_add (GTK_CONTAINER (window), entry);
+
+ /* done, show it */
+ gtk_widget_show_all (window);
+ gtk_widget_grab_focus (entry);
+
+ /* put window in the right position (lower right corner) */
+ parent_window = gtk_widget_get_parent_window (GTK_WIDGET (tree_view));
+ gdk_window_get_origin (parent_window, &ox, &oy);
+ gdk_window_get_geometry (parent_window, NULL, NULL, &pwidth, &pheight, NULL);
+ gdk_window_get_geometry (window->window, NULL, NULL, &width, &height, NULL);
+ gdk_window_move (window->window, ox + pwidth - width, oy + pheight);
+
+ gtk_object_set_data (GTK_OBJECT (window), "text",
+ gtk_entry_get_text (GTK_ENTRY (entry)));
+}
+
+static gboolean
+gtk_tree_view_interactive_search_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ gtk_widget_destroy (widget);
+
+ return TRUE;
+}
+
+static gboolean
+gtk_tree_view_interactive_search_key_press_event (GtkWidget *widget,
+ GdkEventKey *event,
+ GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+ /* close window */
+ if (event->keyval == GDK_Escape || event->keyval == GDK_Return
+ || event->keyval == GDK_Tab)
+ {
+ gtk_widget_destroy (widget);
+ return TRUE;
+ }
+
+ /* select previous matching iter */
+ if (event->keyval == GDK_Up)
+ {
+ gtk_tree_view_interactive_search_search_move (widget,
+ tree_view,
+ TRUE);
+ return TRUE;
+ }
+
+ /* select next matching iter */
+ if (event->keyval == GDK_Down)
+ {
+ gtk_tree_view_interactive_search_search_move (widget,
+ tree_view,
+ FALSE);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+gtk_tree_view_interactive_search_search_move (GtkWidget *window,
+ GtkTreeView *tree_view,
+ gboolean up)
+{
+ gboolean ret;
+ gint *selected_iter;
+ gint len;
+ gint count = 0;
+ gchar *text;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+
+ text = gtk_object_get_data (GTK_OBJECT (window), "text");
+ selected_iter = gtk_object_get_data (GTK_OBJECT (window), "selected-iter");
+
+ g_return_if_fail (text != NULL);
+
+ if (!selected_iter || (up && *selected_iter == 1))
+ return;
+
+ len = strlen (text);
+
+ if (len < 1)
+ return;
+
+ model = gtk_tree_view_get_model (tree_view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ /* search */
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_model_get_iter_root (model, &iter);
+
+ ret = gtk_tree_view_interactive_search_search_iter
+ (model,
+ selection,
+ &iter,
+ text,
+ &count,
+ up?((*selected_iter) - 1):((*selected_iter + 1)));
+
+ if (ret)
+ /* found */
+ *selected_iter += up?(-1):(1);
+ else
+ {
+ /* return to old iter */
+ count = 0;
+ gtk_tree_model_get_iter_root (model, &iter);
+ gtk_tree_view_interactive_search_search_iter (model,
+ selection,
+ &iter,
+ text,
+ &count,
+ *selected_iter);
+
+ /* beep? */
+ }
+}
+
+static gboolean
+gtk_tree_view_interactive_search_search_iter (GtkTreeModel *model,
+ GtkTreeSelection *selection,
+ GtkTreeIter *iter,
+ gchar *text,
+ gint *count,
+ gint n)
+{
+ gint len = strlen (text);
+ gchar *tmp;
+ GValue value = {0,};
+ GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
+ GtkTreeViewColumn *column =
+ gtk_tree_view_get_column (tree_view, tree_view->priv->search_column);
+
+ gtk_tree_model_get_value (model, iter, tree_view->priv->search_column, &value);
+ tmp = g_strdup (g_value_get_string (&value));
+ if (!strncmp (text, tmp, len))
+ {
+ (*count)++;
+
+ if (*count == n)
+ {
+ GtkTreePath *path;
+
+ gtk_tree_selection_select_iter (selection, iter);
+
+ path = gtk_tree_model_get_path (model, iter);
+ gtk_tree_view_scroll_to_cell (tree_view,
+ path, column, 0.5, 0.5);
+ gtk_tree_path_free (path);
+
+ return TRUE;
+ }
+ }
+ g_value_unset (&value);
+
+ if (gtk_tree_model_iter_has_child (model, iter))
+ {
+ gboolean ret;
+ GtkTreeIter child;
+
+ gtk_tree_model_iter_children (model, &child, iter);
+ ret = gtk_tree_view_interactive_search_search_iter (model,
+ selection,
+ &child,
+ text,
+ count,
+ n);
+
+ if (ret)
+ return TRUE; /* iter found and selected */
+ }
+
+ while (gtk_tree_model_iter_next (model, iter))
+ {
+ gtk_tree_model_get_value (model, iter, tree_view->priv->search_column, &value);
+ tmp = g_value_get_string (&value);
+ if (!strncmp (text, tmp, len))
+ {
+ (*count)++;
+ if (*count == n)
+ {
+ GtkTreePath *path;
+
+ gtk_tree_selection_select_iter (selection, iter);
+
+ path = gtk_tree_model_get_path (model, iter);
+ gtk_tree_view_scroll_to_cell (tree_view,
+ path, column, 0.5, 0.5);
+ gtk_tree_path_free (path);
+
+ return TRUE;
+ }
+ }
+ g_value_unset (&value);
+
+ if (gtk_tree_model_iter_has_child (model, iter))
+ {
+ gboolean ret;
+ GtkTreeIter child;
+
+ gtk_tree_model_iter_children (model, &child, iter);
+ ret = gtk_tree_view_interactive_search_search_iter (model,
+ selection,
+ &child,
+ text,
+ count,
+ n);
+
+ if (ret)
+ return TRUE; /* iter found and selected */
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_tree_view_interactive_search_init (GtkWidget *entry,
+ GtkTreeView *tree_view)
+{
+ gint ret;
+ gint *selected_iter;
+ gint len;
+ gint count = 0;
+ 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);
+ selected_iter = gtk_object_get_data (GTK_OBJECT (window), "selected-iter");
+ if (selected_iter)
+ g_free (selected_iter);
+ gtk_object_remove_data (GTK_OBJECT (window), "selected-iter");
+
+ if (len < 1)
+ return;
+
+ gtk_tree_model_get_iter_root (model, &iter);
+
+ ret = gtk_tree_view_interactive_search_search_iter (model,
+ selection,
+ &iter,
+ text,
+ &count,
+ 1);
+
+ if (ret)
+ {
+ selected_iter = g_malloc (sizeof (int));
+ *selected_iter = 1;
+ gtk_object_set_data (GTK_OBJECT (window), "selected-iter",
+ selected_iter);
+ }
+
+ return;
}
Index: gtk+/gtk/gtktreeview.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktreeview.h,v
retrieving revision 1.33
diff -u -r1.33 gtktreeview.h
--- gtk+/gtk/gtktreeview.h 2001/06/29 03:11:01 1.33
+++ gtk+/gtk/gtktreeview.h 2001/07/08 18:00:05
@@ -275,6 +275,11 @@
GdkPixmap *gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view,
GtkTreePath *path);
+/* Interactive search */
+gint gtk_tree_view_interactive_search_get_search_column (GtkTreeView *tree_view);
+void gtk_tree_view_interactive_search_set_search_column (GtkTreeView *tree_view,
+ gint column);
+
/* This function should really never be used. It is just for use by ATK.
*/
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]