Re: TreeView search dialog -- new patch (take 2)
- From: Kristian Rietveld <kristian planet nl>
- To: Jonathan Blandford <jrb redhat com>
- Cc: GTK Development list <gtk-devel-list gnome org>
- Subject: Re: TreeView search dialog -- new patch (take 2)
- Date: Mon, 16 Jul 2001 22:02:46 +0200 (CEST)
On 16 Jul 2001, Jonathan Blandford wrote:
> Kristian Rietveld <kristian planet nl> writes:
>
> > Hi,
> >
> > This is a new patch which adds the interactive search code to the
> > TreeView. New is the 'configurable search dialog position function' ;)
> > (featuring long and ugly prototypes ...), besides that, nothing has been
> > changed. I think this will be my latest patch for a long time, because I'm
> > leaving Saturday for three weeks (holiday ;).
> >
> > As always, suggestions/comments/etc are welcome.
>
> Looks extremely cool. It basically works, though there are a few minor
> bugs. To be specific:
>
> * You should popdown on focus out.
> * The first letter doesn't seem to work. (ie, typing N doesn't do
> anything on testtreefocus, for example.)
> * It seems to interfere with keybindings. For example, C-n doesn't go
> to the next line, it starts typing n.
> * I think activating the entry should move the cursor to the current
> highlighted location.
All fixed now, see attached patch.
regards,
Kris
>
> But these can all be fixed. It really helps the usability of the tree
> too.
>
> Thanks,
> -Jonathan
>
--
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/16 19:58:26
@@ -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,35 @@
GtkTreePath *path,
gboolean clear_and_select);
+/* interactive search */
+static void gtk_tree_view_interactive_search_dialog_destroy (GtkWidget *search_dialog,
+ GtkTreeView *tree_view);
+static void gtk_tree_view_interactive_search_position_func (GtkTreeView *tree_view,
+ GtkWidget *search_dialog);
+static gboolean gtk_tree_view_interactive_search_delete_event (GtkWidget *widget,
+ GdkEventAny *event,
+ GtkTreeView *tree_view);
+static gboolean gtk_tree_view_interactive_search_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ GtkTreeView *tree_view);
+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 +866,8 @@
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;
+ tree_view->priv->search_dialog_position_func = gtk_tree_view_interactive_search_position_func;
}
@@ -958,7 +991,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 +2810,14 @@
}
return TRUE;
}
+
+ if (event->keyval >= GDK_A && event->keyval <= GDK_z
+ && event->state != GDK_CONTROL_MASK)
+ {
+ gtk_tree_view_interactive_search (tree_view, event->keyval);
+ return TRUE;
+ }
+
return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
}
@@ -2833,6 +2874,7 @@
gtk_tree_view_leave_notify (GtkWidget *widget,
GdkEventCrossing *event)
{
+ GtkWidget *search_dialog;
GtkTreeView *tree_view;
g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
@@ -2846,6 +2888,12 @@
NULL);
ensure_unprelighted (tree_view);
+
+ /* destroy interactive search dialog */
+ search_dialog = gtk_object_get_data (GTK_OBJECT (widget), "search-dialog");
+ if (search_dialog)
+ gtk_tree_view_interactive_search_dialog_destroy (search_dialog,
+ tree_view);
return TRUE;
}
@@ -2882,6 +2930,7 @@
gtk_widget_queue_draw (widget);
GTK_TREE_VIEW (widget)->priv->in_extended_selection = FALSE;
GTK_TREE_VIEW (widget)->priv->in_free_motion = FALSE;
+
return FALSE;
}
@@ -8214,4 +8263,451 @@
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;
+}
+
+/**
+ * gtk_tree_view_interactive_search_get_dialog_position_func:
+ * @tree_view: A #GtkTreeView
+ *
+ * Returns the position function currently in use.
+ *
+ * Return value: the currently used position function for the search dialog.
+ */
+GtkTreeViewSearchDialogPositionFunc
+gtk_tree_view_interactive_search_get_dialog_position_func (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+
+ return tree_view->priv->search_dialog_position_func;
+}
+
+/**
+ * gtk_tree_view_interactive_search_set_dialog_position_func:
+ * @tree_view: A #GtkTreeView
+ * @position_func: the position function to use for the search dialog
+ *
+ * Sets the position function to use for positioning the search dialog. See
+ * gtktreeview.c:gtk_tree_view_interactive_search_position_dialog() for an
+ * example of such a position function.
+ */
+void
+gtk_tree_view_interactive_search_set_dialog_position_func (GtkTreeView *tree_view,
+ GtkTreeViewSearchDialogPositionFunc position_func)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ g_return_if_fail (position_func != NULL);
+
+ tree_view->priv->search_dialog_position_func = position_func;
+}
+
+/**
+ * gtk_tree_view_interactive_search_dialog_reposition:
+ * @tree_view: A #GtkTreeView
+ *
+ * Repositions the search dialog. Call this function after you set the
+ * position function with gtk_tree_view_interactive_search_set_dialog_position_func(),
+ * so the changes take effect.
+ */
+void
+gtk_tree_view_interactive_search_dialog_reposition (GtkTreeView *tree_view)
+{
+ GtkWidget *window;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ window = gtk_object_get_data (GTK_OBJECT (tree_view), "search-dialog");
+
+ tree_view->priv->search_dialog_position_func (tree_view, window);
+}
+
+static void
+gtk_tree_view_interactive_search_dialog_destroy (GtkWidget *search_dialog,
+ GtkTreeView *tree_view)
+{
+ /* remove data from tree_view */
+ gtk_object_remove_data (GTK_OBJECT (tree_view), "search-dialog");
+
+ gtk_widget_destroy (search_dialog);
+}
+
+static void
+gtk_tree_view_interactive_search_position_func (GtkTreeView *tree_view,
+ GtkWidget *search_dialog)
+{
+ gint ox, oy;
+ gint width, height;
+ gint pwidth, pheight;
+ GdkWindow *parent_window;
+
+ /* put window in the 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 (search_dialog->window, NULL, NULL, &width, &height,
+ NULL);
+ gdk_window_move (search_dialog->window, ox + pwidth - width, oy + pheight);
+}
+
+static void
+gtk_tree_view_interactive_search (GtkTreeView *tree_view,
+ gchar first_char)
+{
+ gchar hack[2] = {first_char, 0};
+ GtkWidget *window;
+ GtkWidget *entry;
+
+ 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
+ (GTK_OBJECT (window), "delete_event",
+ GTK_SIGNAL_FUNC (gtk_tree_view_interactive_search_delete_event),
+ tree_view);
+ 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);
+
+ /* position window */
+ tree_view->priv->search_dialog_position_func (tree_view, window);
+
+ gtk_object_set_data (GTK_OBJECT (window), "text",
+ gtk_entry_get_text (GTK_ENTRY (entry)));
+ gtk_object_set_data (GTK_OBJECT (tree_view), "search-dialog", window);
+
+ /* search first matching iter */
+ gtk_tree_view_interactive_search_init (entry, tree_view);
+}
+
+static gboolean
+gtk_tree_view_interactive_search_delete_event (GtkWidget *widget,
+ GdkEventAny *event,
+ GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ gtk_tree_view_interactive_search_dialog_destroy (widget, tree_view);
+
+ return TRUE;
+}
+
+static gboolean
+gtk_tree_view_interactive_search_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ gtk_tree_view_interactive_search_dialog_destroy (widget, tree_view);
+
+ 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_tree_view_interactive_search_dialog_destroy (widget, tree_view);
+ 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/16 19:58:27
@@ -19,6 +19,7 @@
#ifndef __GTK_TREE_VIEW_H__
#define __GTK_TREE_VIEW_H__
+#include <gtk/gtkwidget.h>
#include <gtk/gtkcontainer.h>
#include <gtk/gtktreemodel.h>
#include <gtk/gtktreeviewcolumn.h>
@@ -119,6 +120,8 @@
GtkTreePath *path,
GtkTreeViewDropPosition *pos,
gpointer user_data);
+typedef void (*GtkTreeViewSearchDialogPositionFunc) (GtkTreeView *tree_view,
+ GtkWidget *search_dialog);
/* Creators */
@@ -274,6 +277,15 @@
GtkTreeViewDropPosition *pos);
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);
+GtkTreeViewSearchDialogPositionFunc gtk_tree_view_interactive_search_get_dialog_position_func (GtkTreeView *tree_view);
+void gtk_tree_view_interactive_search_set_dialog_position_func (GtkTreeView *tree_view,
+ GtkTreeViewSearchDialogPositionFunc position_func);
+void gtk_tree_view_interactive_search_dialog_reposition (GtkTreeView *tree_view);
/* This function should really never be used. It is just for use by ATK.
Index: gtk+/gtk/gtktreeprivate.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktreeprivate.h,v
retrieving revision 1.26
diff -u -r1.26 gtktreeprivate.h
--- gtk+/gtk/gtktreeprivate.h 2001/06/29 03:11:01 1.26
+++ gtk+/gtk/gtktreeprivate.h 2001/07/16 19:58:27
@@ -166,6 +166,10 @@
guint in_extended_selection : 1;
guint in_free_motion : 1;
+
+ /* interactive search */
+ gint search_column;
+ GtkTreeViewSearchDialogPositionFunc search_dialog_position_func;
};
#ifdef __GNUC__
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]