From ac1e4ef3d26343eb7480ef86af3420146466fec1 Mon Sep 17 00:00:00 2001 From: Jonathan Blandford Date: Fri, 17 Aug 2001 23:35:52 +0000 Subject: [PATCH] Add heavily modified patch from Kristian Rietveld to handle interactive Fri Aug 17 19:30:14 2001 Jonathan Blandford * gtk/gtktreeprivate.h: * gtk/gtktreeview.c: (gtk_tree_view_class_init), (gtk_tree_view_init), (gtk_tree_view_set_property), (gtk_tree_view_get_property), (gtk_tree_view_destroy), (gtk_tree_view_key_press), (gtk_tree_view_leave_notify), (gtk_tree_view_focus_out), (gtk_tree_view_set_model), (gtk_tree_view_set_destroy_count_func), (gtk_tree_view_set_enable_search), (gtk_tree_view_get_enable_search), (gtk_tree_view_get_search_column), (gtk_tree_view_set_search_column), (gtk_tree_view_get_search_equal_func), (gtk_tree_view_set_search_equal_func), (gtk_tree_view_search_dialog_destroy), (gtk_tree_view_search_position_func), (gtk_tree_view_interactive_search), (gtk_tree_view_search_delete_event), (gtk_tree_view_search_button_press_event), (gtk_tree_view_search_key_press_event), (gtk_tree_view_search_move), (gtk_tree_view_search_equal_func), (gtk_tree_view_search_iter), (gtk_tree_view_search_init): * gtk/gtktreeview.h: Add heavily modified patch from Kristian Rietveld to handle interactive searching. --- ChangeLog | 27 ++ ChangeLog.pre-2-0 | 27 ++ ChangeLog.pre-2-10 | 27 ++ ChangeLog.pre-2-2 | 27 ++ ChangeLog.pre-2-4 | 27 ++ ChangeLog.pre-2-6 | 27 ++ ChangeLog.pre-2-8 | 27 ++ gtk/gtktreeprivate.h | 11 + gtk/gtktreeview.c | 796 ++++++++++++++++++++++++++++++++++++++----- gtk/gtktreeview.h | 25 +- 10 files changed, 924 insertions(+), 97 deletions(-) diff --git a/ChangeLog b/ChangeLog index 378716b5f..61526df78 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +Fri Aug 17 19:30:14 2001 Jonathan Blandford + + * gtk/gtktreeprivate.h: + * gtk/gtktreeview.c: (gtk_tree_view_class_init), + (gtk_tree_view_init), (gtk_tree_view_set_property), + (gtk_tree_view_get_property), (gtk_tree_view_destroy), + (gtk_tree_view_key_press), (gtk_tree_view_leave_notify), + (gtk_tree_view_focus_out), (gtk_tree_view_set_model), + (gtk_tree_view_set_destroy_count_func), + (gtk_tree_view_set_enable_search), + (gtk_tree_view_get_enable_search), + (gtk_tree_view_get_search_column), + (gtk_tree_view_set_search_column), + (gtk_tree_view_get_search_equal_func), + (gtk_tree_view_set_search_equal_func), + (gtk_tree_view_search_dialog_destroy), + (gtk_tree_view_search_position_func), + (gtk_tree_view_interactive_search), + (gtk_tree_view_search_delete_event), + (gtk_tree_view_search_button_press_event), + (gtk_tree_view_search_key_press_event), + (gtk_tree_view_search_move), (gtk_tree_view_search_equal_func), + (gtk_tree_view_search_iter), (gtk_tree_view_search_init): + * gtk/gtktreeview.h: + Add heavily modified patch from Kristian Rietveld to handle + interactive searching. + Fri Aug 17 17:30:34 2001 Tim Janik * gtk/gtktreemodel.c (gtk_tree_path_new_from_string): const correct diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 378716b5f..61526df78 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,30 @@ +Fri Aug 17 19:30:14 2001 Jonathan Blandford + + * gtk/gtktreeprivate.h: + * gtk/gtktreeview.c: (gtk_tree_view_class_init), + (gtk_tree_view_init), (gtk_tree_view_set_property), + (gtk_tree_view_get_property), (gtk_tree_view_destroy), + (gtk_tree_view_key_press), (gtk_tree_view_leave_notify), + (gtk_tree_view_focus_out), (gtk_tree_view_set_model), + (gtk_tree_view_set_destroy_count_func), + (gtk_tree_view_set_enable_search), + (gtk_tree_view_get_enable_search), + (gtk_tree_view_get_search_column), + (gtk_tree_view_set_search_column), + (gtk_tree_view_get_search_equal_func), + (gtk_tree_view_set_search_equal_func), + (gtk_tree_view_search_dialog_destroy), + (gtk_tree_view_search_position_func), + (gtk_tree_view_interactive_search), + (gtk_tree_view_search_delete_event), + (gtk_tree_view_search_button_press_event), + (gtk_tree_view_search_key_press_event), + (gtk_tree_view_search_move), (gtk_tree_view_search_equal_func), + (gtk_tree_view_search_iter), (gtk_tree_view_search_init): + * gtk/gtktreeview.h: + Add heavily modified patch from Kristian Rietveld to handle + interactive searching. + Fri Aug 17 17:30:34 2001 Tim Janik * gtk/gtktreemodel.c (gtk_tree_path_new_from_string): const correct diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 378716b5f..61526df78 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,30 @@ +Fri Aug 17 19:30:14 2001 Jonathan Blandford + + * gtk/gtktreeprivate.h: + * gtk/gtktreeview.c: (gtk_tree_view_class_init), + (gtk_tree_view_init), (gtk_tree_view_set_property), + (gtk_tree_view_get_property), (gtk_tree_view_destroy), + (gtk_tree_view_key_press), (gtk_tree_view_leave_notify), + (gtk_tree_view_focus_out), (gtk_tree_view_set_model), + (gtk_tree_view_set_destroy_count_func), + (gtk_tree_view_set_enable_search), + (gtk_tree_view_get_enable_search), + (gtk_tree_view_get_search_column), + (gtk_tree_view_set_search_column), + (gtk_tree_view_get_search_equal_func), + (gtk_tree_view_set_search_equal_func), + (gtk_tree_view_search_dialog_destroy), + (gtk_tree_view_search_position_func), + (gtk_tree_view_interactive_search), + (gtk_tree_view_search_delete_event), + (gtk_tree_view_search_button_press_event), + (gtk_tree_view_search_key_press_event), + (gtk_tree_view_search_move), (gtk_tree_view_search_equal_func), + (gtk_tree_view_search_iter), (gtk_tree_view_search_init): + * gtk/gtktreeview.h: + Add heavily modified patch from Kristian Rietveld to handle + interactive searching. + Fri Aug 17 17:30:34 2001 Tim Janik * gtk/gtktreemodel.c (gtk_tree_path_new_from_string): const correct diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 378716b5f..61526df78 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,30 @@ +Fri Aug 17 19:30:14 2001 Jonathan Blandford + + * gtk/gtktreeprivate.h: + * gtk/gtktreeview.c: (gtk_tree_view_class_init), + (gtk_tree_view_init), (gtk_tree_view_set_property), + (gtk_tree_view_get_property), (gtk_tree_view_destroy), + (gtk_tree_view_key_press), (gtk_tree_view_leave_notify), + (gtk_tree_view_focus_out), (gtk_tree_view_set_model), + (gtk_tree_view_set_destroy_count_func), + (gtk_tree_view_set_enable_search), + (gtk_tree_view_get_enable_search), + (gtk_tree_view_get_search_column), + (gtk_tree_view_set_search_column), + (gtk_tree_view_get_search_equal_func), + (gtk_tree_view_set_search_equal_func), + (gtk_tree_view_search_dialog_destroy), + (gtk_tree_view_search_position_func), + (gtk_tree_view_interactive_search), + (gtk_tree_view_search_delete_event), + (gtk_tree_view_search_button_press_event), + (gtk_tree_view_search_key_press_event), + (gtk_tree_view_search_move), (gtk_tree_view_search_equal_func), + (gtk_tree_view_search_iter), (gtk_tree_view_search_init): + * gtk/gtktreeview.h: + Add heavily modified patch from Kristian Rietveld to handle + interactive searching. + Fri Aug 17 17:30:34 2001 Tim Janik * gtk/gtktreemodel.c (gtk_tree_path_new_from_string): const correct diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 378716b5f..61526df78 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,30 @@ +Fri Aug 17 19:30:14 2001 Jonathan Blandford + + * gtk/gtktreeprivate.h: + * gtk/gtktreeview.c: (gtk_tree_view_class_init), + (gtk_tree_view_init), (gtk_tree_view_set_property), + (gtk_tree_view_get_property), (gtk_tree_view_destroy), + (gtk_tree_view_key_press), (gtk_tree_view_leave_notify), + (gtk_tree_view_focus_out), (gtk_tree_view_set_model), + (gtk_tree_view_set_destroy_count_func), + (gtk_tree_view_set_enable_search), + (gtk_tree_view_get_enable_search), + (gtk_tree_view_get_search_column), + (gtk_tree_view_set_search_column), + (gtk_tree_view_get_search_equal_func), + (gtk_tree_view_set_search_equal_func), + (gtk_tree_view_search_dialog_destroy), + (gtk_tree_view_search_position_func), + (gtk_tree_view_interactive_search), + (gtk_tree_view_search_delete_event), + (gtk_tree_view_search_button_press_event), + (gtk_tree_view_search_key_press_event), + (gtk_tree_view_search_move), (gtk_tree_view_search_equal_func), + (gtk_tree_view_search_iter), (gtk_tree_view_search_init): + * gtk/gtktreeview.h: + Add heavily modified patch from Kristian Rietveld to handle + interactive searching. + Fri Aug 17 17:30:34 2001 Tim Janik * gtk/gtktreemodel.c (gtk_tree_path_new_from_string): const correct diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 378716b5f..61526df78 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,30 @@ +Fri Aug 17 19:30:14 2001 Jonathan Blandford + + * gtk/gtktreeprivate.h: + * gtk/gtktreeview.c: (gtk_tree_view_class_init), + (gtk_tree_view_init), (gtk_tree_view_set_property), + (gtk_tree_view_get_property), (gtk_tree_view_destroy), + (gtk_tree_view_key_press), (gtk_tree_view_leave_notify), + (gtk_tree_view_focus_out), (gtk_tree_view_set_model), + (gtk_tree_view_set_destroy_count_func), + (gtk_tree_view_set_enable_search), + (gtk_tree_view_get_enable_search), + (gtk_tree_view_get_search_column), + (gtk_tree_view_set_search_column), + (gtk_tree_view_get_search_equal_func), + (gtk_tree_view_set_search_equal_func), + (gtk_tree_view_search_dialog_destroy), + (gtk_tree_view_search_position_func), + (gtk_tree_view_interactive_search), + (gtk_tree_view_search_delete_event), + (gtk_tree_view_search_button_press_event), + (gtk_tree_view_search_key_press_event), + (gtk_tree_view_search_move), (gtk_tree_view_search_equal_func), + (gtk_tree_view_search_iter), (gtk_tree_view_search_init): + * gtk/gtktreeview.h: + Add heavily modified patch from Kristian Rietveld to handle + interactive searching. + Fri Aug 17 17:30:34 2001 Tim Janik * gtk/gtktreemodel.c (gtk_tree_path_new_from_string): const correct diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 378716b5f..61526df78 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,30 @@ +Fri Aug 17 19:30:14 2001 Jonathan Blandford + + * gtk/gtktreeprivate.h: + * gtk/gtktreeview.c: (gtk_tree_view_class_init), + (gtk_tree_view_init), (gtk_tree_view_set_property), + (gtk_tree_view_get_property), (gtk_tree_view_destroy), + (gtk_tree_view_key_press), (gtk_tree_view_leave_notify), + (gtk_tree_view_focus_out), (gtk_tree_view_set_model), + (gtk_tree_view_set_destroy_count_func), + (gtk_tree_view_set_enable_search), + (gtk_tree_view_get_enable_search), + (gtk_tree_view_get_search_column), + (gtk_tree_view_set_search_column), + (gtk_tree_view_get_search_equal_func), + (gtk_tree_view_set_search_equal_func), + (gtk_tree_view_search_dialog_destroy), + (gtk_tree_view_search_position_func), + (gtk_tree_view_interactive_search), + (gtk_tree_view_search_delete_event), + (gtk_tree_view_search_button_press_event), + (gtk_tree_view_search_key_press_event), + (gtk_tree_view_search_move), (gtk_tree_view_search_equal_func), + (gtk_tree_view_search_iter), (gtk_tree_view_search_init): + * gtk/gtktreeview.h: + Add heavily modified patch from Kristian Rietveld to handle + interactive searching. + Fri Aug 17 17:30:34 2001 Tim Janik * gtk/gtktreemodel.c (gtk_tree_path_new_from_string): const correct diff --git a/gtk/gtktreeprivate.h b/gtk/gtktreeprivate.h index bf76f1964..60aee31fd 100644 --- a/gtk/gtktreeprivate.h +++ b/gtk/gtktreeprivate.h @@ -66,6 +66,9 @@ enum */ #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*TREE_VIEW_HEADER_HEIGHT(tree_view)) +typedef void (*GtkTreeViewSearchDialogPositionFunc) (GtkTreeView *tree_view, + GtkWidget *search_dialog); + typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder; struct _GtkTreeViewColumnReorder { @@ -171,6 +174,14 @@ struct _GtkTreeViewPrivate guint in_extended_selection : 1; guint in_free_motion : 1; + + /* interactive search */ + guint enable_search : 1; + gint search_column; + GtkTreeViewSearchDialogPositionFunc search_dialog_position_func; + GtkTreeViewSearchEqualFunc search_equal_func; + gpointer search_user_data; + GtkDestroyNotify search_destroy; }; #ifdef __GNUC__ diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index 556ed7d65..1d1b7cd81 100644 --- a/gtk/gtktreeview.c +++ b/gtk/gtktreeview.c @@ -32,7 +32,10 @@ #include "gtkarrow.h" #include "gtkintl.h" #include "gtkbindings.h" +#include "gtkcontainer.h" +#include "gtkentry.h" +#include #include #if defined (GDK_WINDOWING_X11) @@ -120,7 +123,9 @@ enum { PROP_HEADERS_CLICKABLE, PROP_EXPANDER_COLUMN, PROP_REORDERABLE, - PROP_RULES_HINT + PROP_RULES_HINT, + PROP_ENABLE_SEARCH, + PROP_SEARCH_COLUMN, }; static void gtk_tree_view_class_init (GtkTreeViewClass *klass); @@ -141,7 +146,6 @@ static void gtk_tree_view_get_property (GObject *object, static void gtk_tree_view_destroy (GtkObject *object); /* gtkwidget signals */ -static void gtk_tree_view_setup_model (GtkTreeView *tree_view); static void gtk_tree_view_realize (GtkWidget *widget); static void gtk_tree_view_unrealize (GtkWidget *widget); static void gtk_tree_view_map (GtkWidget *widget); @@ -260,93 +264,124 @@ static void gtk_tree_view_reordered (GtkTreeModel *mode /* Internal functions */ -static gboolean gtk_tree_view_is_expander_column (GtkTreeView *tree_view, - GtkTreeViewColumn*column); -static void gtk_tree_view_add_move_binding (GtkBindingSet *binding_set, - guint keyval, - guint modmask, - GtkMovementStep step, - gint count); -static gint gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view, - GtkRBTree *tree); -static void gtk_tree_view_queue_draw_node (GtkTreeView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, - GdkRectangle *clip_rect); -static void gtk_tree_view_queue_draw_path (GtkTreeView *tree_view, - GtkTreePath *path, - GdkRectangle *clip_rect); -static void gtk_tree_view_queue_draw_arrow (GtkTreeView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, - GdkRectangle *clip_rect); -static void gtk_tree_view_draw_arrow (GtkTreeView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, - gint x, - gint y); -static void gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view, - gint *x1, - gint *x2); -static gint gtk_tree_view_new_column_width (GtkTreeView *tree_view, - gint i, - gint *x); -static void gtk_tree_view_ensure_scroll_timeout(GtkTreeView *tree_view, - GFunc func); -static void gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment, - GtkTreeView *tree_view); -static gint gtk_tree_view_insert_iter_height (GtkTreeView *tree_view, - GtkRBTree *tree, - GtkTreeIter *iter, - gint depth); -static void gtk_tree_view_build_tree (GtkTreeView *tree_view, - GtkRBTree *tree, - GtkTreeIter *iter, - gint depth, - gboolean recurse, - gboolean calc_bounds); -static void gtk_tree_view_calc_size (GtkTreeView *priv, - GtkRBTree *tree, - GtkTreeIter *iter, - gint depth); -static gboolean gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view, - GtkTreeIter *iter, - gint depth, - gint *height); -static void gtk_tree_view_discover_dirty (GtkTreeView *tree_view, - GtkRBTree *tree, - GtkTreeIter *iter, - gint depth); -static void gtk_tree_view_check_dirty (GtkTreeView *tree_view); -static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view, - GtkRBTree *tree, - GtkRBNode *node); -static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view, - GdkEventMotion *event); -static void _gtk_tree_view_update_col_width (GtkTreeView *tree_view); - - -static void gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view); -static void gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view, - gint count); -static void gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view, - gint count); -static void gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view, - gint count); -static void gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view, - gint count); -static gboolean gtk_tree_view_real_collapse_row (GtkTreeView *tree_view, - GtkTreePath *path, - GtkRBTree *tree, - GtkRBNode *node); -static gboolean gtk_tree_view_real_expand_row (GtkTreeView *tree_view, - GtkTreePath *path, - GtkRBTree *tree, - GtkRBNode *node, - gboolean open_all); -static void gtk_tree_view_real_set_cursor (GtkTreeView *tree_view, - GtkTreePath *path, - gboolean clear_and_select); +static gboolean gtk_tree_view_is_expander_column (GtkTreeView *tree_view, + GtkTreeViewColumn *column); +static void gtk_tree_view_add_move_binding (GtkBindingSet *binding_set, + guint keyval, + guint modmask, + GtkMovementStep step, + gint count); +static gint gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view, + GtkRBTree *tree); +static void gtk_tree_view_queue_draw_node (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node, + GdkRectangle *clip_rect); +static void gtk_tree_view_queue_draw_path (GtkTreeView *tree_view, + GtkTreePath *path, + GdkRectangle *clip_rect); +static void gtk_tree_view_queue_draw_arrow (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node, + GdkRectangle *clip_rect); +static void gtk_tree_view_draw_arrow (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node, + gint x, + gint y); +static void gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view, + gint *x1, + gint *x2); +static gint gtk_tree_view_new_column_width (GtkTreeView *tree_view, + gint i, + gint *x); +static void gtk_tree_view_ensure_scroll_timeout (GtkTreeView *tree_view, + GFunc func); +static void gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment, + GtkTreeView *tree_view); +static gint gtk_tree_view_insert_iter_height (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkTreeIter *iter, + gint depth); +static void gtk_tree_view_build_tree (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkTreeIter *iter, + gint depth, + gboolean recurse, + gboolean calc_bounds); +static void gtk_tree_view_calc_size (GtkTreeView *priv, + GtkRBTree *tree, + GtkTreeIter *iter, + gint depth); +static gboolean gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view, + GtkTreeIter *iter, + gint depth, + gint *height); +static void gtk_tree_view_discover_dirty (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkTreeIter *iter, + gint depth); +static void gtk_tree_view_check_dirty (GtkTreeView *tree_view); +static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node); +static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view, + GdkEventMotion *event); +static void _gtk_tree_view_update_col_width (GtkTreeView *tree_view); +static void gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view); +static void gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view, + gint count); +static void gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view, + gint count); +static void gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view, + gint count); +static void gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view, + gint count); +static gboolean gtk_tree_view_real_collapse_row (GtkTreeView *tree_view, + GtkTreePath *path, + GtkRBTree *tree, + GtkRBNode *node); +static gboolean gtk_tree_view_real_expand_row (GtkTreeView *tree_view, + GtkTreePath *path, + GtkRBTree *tree, + GtkRBNode *node, + gboolean open_all); +static void gtk_tree_view_real_set_cursor (GtkTreeView *tree_view, + GtkTreePath *path, + gboolean clear_and_select); + + +/* interactive search */ +static void gtk_tree_view_search_dialog_destroy (GtkWidget *search_dialog, + GtkTreeView *tree_view); +static void gtk_tree_view_search_position_func (GtkTreeView *tree_view, + GtkWidget *search_dialog); +static gboolean gtk_tree_view_search_delete_event (GtkWidget *widget, + GdkEventAny *event, + GtkTreeView *tree_view); +static gboolean gtk_tree_view_search_button_press_event (GtkWidget *widget, + GdkEventButton *event, + GtkTreeView *tree_view); +static gboolean gtk_tree_view_search_key_press_event (GtkWidget *entry, + GdkEventKey *event, + GtkTreeView *tree_view); +static void gtk_tree_view_search_move (GtkWidget *window, + GtkTreeView *tree_view, + gboolean up); +static gboolean gtk_tree_view_search_equal_func (GtkTreeModel *model, + gint column, + gchar *key, + GtkTreeIter *iter); +static gboolean gtk_tree_view_search_iter (GtkTreeModel *model, + GtkTreeSelection *selection, + GtkTreeIter *iter, + gchar *text, + gint *count, + gint n); +static void gtk_tree_view_search_init (GtkWidget *entry, + GtkTreeView *tree_view); +static void gtk_tree_view_interactive_search (GtkTreeView *tree_view, + GdkEventKey *key); static GtkContainerClass *parent_class = NULL; @@ -515,6 +550,24 @@ gtk_tree_view_class_init (GtkTreeViewClass *class) FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (o_class, + PROP_ENABLE_SEARCH, + g_param_spec_boolean ("enable_search", + _("Enable Search"), + _("View allows user to search through columns interactively"), + TRUE, + G_PARAM_READWRITE)); + + g_object_class_install_property (o_class, + PROP_SEARCH_COLUMN, + g_param_spec_int ("search_column", + _("Search Column"), + _("Model column to search through when searching through code"), + -1, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + /* Style properties */ /* the width of the column resize windows */ #define _TREE_VIEW_EXPANDER_SIZE 10 @@ -833,6 +886,10 @@ gtk_tree_view_init (GtkTreeView *tree_view) 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->enable_search = TRUE; + tree_view->priv->search_column = -1; + tree_view->priv->search_dialog_position_func = gtk_tree_view_search_position_func; + tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func; } @@ -875,6 +932,11 @@ gtk_tree_view_set_property (GObject *object, break; case PROP_RULES_HINT: gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value)); + case PROP_ENABLE_SEARCH: + gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value)); + break; + case PROP_SEARCH_COLUMN: + gtk_tree_view_set_search_column (tree_view, g_value_get_int (value)); break; default: break; @@ -914,6 +976,12 @@ gtk_tree_view_get_property (GObject *object, case PROP_RULES_HINT: g_value_set_boolean (value, tree_view->priv->has_rules); break; + case PROP_ENABLE_SEARCH: + g_value_set_boolean (value, tree_view->priv->enable_search); + break; + case PROP_SEARCH_COLUMN: + g_value_set_int (value, tree_view->priv->search_column); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -940,6 +1008,7 @@ static void gtk_tree_view_destroy (GtkObject *object) { GtkTreeView *tree_view = GTK_TREE_VIEW (object); + GtkWidget *search_dialog; GList *list; gtk_tree_view_set_model (tree_view, NULL); @@ -957,7 +1026,7 @@ gtk_tree_view_destroy (GtkObject *object) 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)); @@ -1005,6 +1074,12 @@ gtk_tree_view_destroy (GtkObject *object) gtk_tree_row_reference_free (tree_view->priv->anchor); tree_view->priv->anchor = NULL; + /* destroy interactive search dialog */ + search_dialog = gtk_object_get_data (GTK_OBJECT (tree_view), "search-dialog"); + if (search_dialog) + gtk_tree_view_search_dialog_destroy (search_dialog, + tree_view); + if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } @@ -2774,6 +2849,7 @@ gtk_tree_view_key_press (GtkWidget *widget, GdkEventKey *event) { GtkTreeView *tree_view = (GtkTreeView *) widget; + gint retval; if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG)) { @@ -2784,7 +2860,13 @@ gtk_tree_view_key_press (GtkWidget *widget, } return TRUE; } - return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event); + + retval = (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event); + + if (! retval) + gtk_tree_view_interactive_search (tree_view, event); + + return retval; } /* FIXME Is this function necessary? Can I get an enter_notify event @@ -2853,8 +2935,8 @@ gtk_tree_view_leave_notify (GtkWidget *widget, NULL); ensure_unprelighted (tree_view); - - return TRUE; + +return TRUE; } @@ -2881,6 +2963,8 @@ static gint gtk_tree_view_focus_out (GtkWidget *widget, GdkEventFocus *event) { + GtkWidget *search_dialog; + g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); @@ -2889,6 +2973,12 @@ gtk_tree_view_focus_out (GtkWidget *widget, gtk_widget_queue_draw (widget); GTK_TREE_VIEW (widget)->priv->in_extended_selection = FALSE; GTK_TREE_VIEW (widget)->priv->in_free_motion = FALSE; + + /* destroy interactive search dialog */ + search_dialog = gtk_object_get_data (GTK_OBJECT (widget), "search-dialog"); + if (search_dialog) + gtk_tree_view_search_dialog_destroy (search_dialog, + GTK_TREE_VIEW (widget)); return FALSE; } @@ -6133,15 +6223,30 @@ gtk_tree_view_set_model (GtkTreeView *tree_view, tree_view->priv->drag_dest_row = NULL; } g_object_unref (tree_view->priv->model); + tree_view->priv->search_column = -1; } tree_view->priv->model = model; + if (tree_view->priv->model) { + gint i; GtkTreePath *path; GtkTreeIter iter; + + if (tree_view->priv->search_column == -1) + { + for (i = 0; i < gtk_tree_model_get_n_columns (model); i++) + { + if (gtk_tree_model_get_column_type (model, i) == G_TYPE_STRING) + { + tree_view->priv->search_column = i; + break; + } + } + } g_object_ref (tree_view->priv->model); g_signal_connect (tree_view->priv->model, "range_changed", @@ -8356,3 +8461,508 @@ gtk_tree_view_set_destroy_count_func (GtkTreeView *tree_view, tree_view->priv->destroy_count_data = data; tree_view->priv->destroy_count_destroy = destroy; } + + +/* + * Interactive search + */ + +/** + * gtk_tree_view_set_enable_search: + * @tree_view: A #GtkTreeView + * @enable_search: %TRUE, if the user can search interactively + * + * If @enable_search is set, then the user can type in text to search through + * the tree interactively. + */ +void +gtk_tree_view_set_enable_search (GtkTreeView *tree_view, + gboolean enable_search) +{ + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); + + tree_view->priv->enable_search = !!enable_search; +} + +/** + * gtk_tree_view_get_enable_search: + * @tree_view: A #GtkTreeView + * + * Returns whether or not the tree allows interactive searching. + * + * Return value: whether or not to let the user search interactively + */ +gboolean +gtk_tree_view_get_enable_search (GtkTreeView *tree_view) +{ + g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE); + + return tree_view->priv->enable_search; +} + + +/** + * gtk_tree_view_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_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_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. Additionally, turns on interactive searching. + */ +void +gtk_tree_view_set_search_column (GtkTreeView *tree_view, + gint column) +{ + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); + g_return_if_fail (column >= 0); + + if (tree_view->priv->search_column == column) + return; + + tree_view->priv->search_column = column; + +} + +/** + * gtk_tree_view_search_get_search_equal_func: + * @tree_view: A #GtkTreeView + * + * Returns the compare function currently in use. + * + * Return value: the currently used compare function for the search code. + */ + +GtkTreeViewSearchEqualFunc +gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view) +{ + g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL); + + return tree_view->priv->search_equal_func; +} + +/** + * gtk_tree_view_set_search_equal_func: + * @tree_view: A #GtkTreeView + * @compare_func: the compare function to use during the search + * + * Sets the compare function to use to search the TreeView. + */ +void +gtk_tree_view_set_search_equal_func (GtkTreeView *tree_view, + GtkTreeViewSearchEqualFunc search_equal_func, + gpointer search_user_data, + GtkDestroyNotify search_destroy) +{ + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); + g_return_if_fail (search_equal_func !=NULL); + + if (tree_view->priv->search_destroy) + (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data); + + tree_view->priv->search_equal_func = search_equal_func; + tree_view->priv->search_user_data = search_user_data; + tree_view->priv->search_destroy = search_destroy; + if (tree_view->priv->search_equal_func == NULL) + tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func; +} + +static void +gtk_tree_view_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_search_position_func (GtkTreeView *tree_view, + GtkWidget *search_dialog) +{ + gint tree_x, tree_y; + gint tree_width, tree_height; + GdkWindow *tree_window = GTK_WIDGET (tree_view)->window; + GtkRequisition requisition; + + /* put window in the lower right corner */ + gdk_window_get_origin (tree_window, &tree_x, &tree_y); + gdk_window_get_size (tree_window, + &tree_width, + &tree_height); + gtk_widget_size_request (search_dialog, &requisition); + gtk_window_move (GTK_WINDOW (search_dialog), + tree_x + tree_width - requisition.width, + tree_y + tree_height); +} + +static void +gtk_tree_view_interactive_search (GtkTreeView *tree_view, + GdkEventKey *event) +{ + GtkWidget *window; + GtkWidget *entry; + + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); + switch (event->keyval) + { + case GDK_Shift_L: + case GDK_Shift_R: + case GDK_Control_L: + case GDK_Control_R: + case GDK_Caps_Lock: + case GDK_Shift_Lock: + case GDK_Meta_L: + case GDK_Meta_R: + case GDK_Alt_L: + case GDK_Alt_R: + case GDK_Super_L: + case GDK_Super_R: + case GDK_Hyper_L: + case GDK_Hyper_R: + case GDK_Mode_switch: + return; + default: + break; + } + + if (tree_view->priv->enable_search == FALSE || + tree_view->priv->search_column < 0) + return; + + /* 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_search_delete_event), + tree_view); + gtk_signal_connect + (GTK_OBJECT (window), "key_press_event", + GTK_SIGNAL_FUNC (gtk_tree_view_search_key_press_event), + tree_view); + gtk_signal_connect + (GTK_OBJECT (window), "button_press_event", + GTK_SIGNAL_FUNC (gtk_tree_view_search_button_press_event), + tree_view); + + /* add entry */ + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_signal_connect + (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (gtk_tree_view_search_init), + tree_view); + gtk_container_add (GTK_CONTAINER (window), entry); + + /* done, show it */ + tree_view->priv->search_dialog_position_func (tree_view, window); + gtk_widget_show_all (window); + gtk_widget_grab_focus (entry); + + gtk_widget_event (entry, (GdkEvent *) event); + + /* position 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_search_init (entry, tree_view); +} + +static gboolean +gtk_tree_view_search_delete_event (GtkWidget *widget, + GdkEventAny *event, + GtkTreeView *tree_view) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + gtk_tree_view_search_dialog_destroy (widget, tree_view); + + return TRUE; +} + +static gboolean +gtk_tree_view_search_button_press_event (GtkWidget *widget, + GdkEventButton *event, + GtkTreeView *tree_view) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + gtk_tree_view_search_dialog_destroy (widget, tree_view); + + return TRUE; +} + +static gboolean +gtk_tree_view_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_search_dialog_destroy (widget, tree_view); + return TRUE; + } + + /* select previous matching iter */ + if (event->keyval == GDK_Up) + { + gtk_tree_view_search_move (widget, + tree_view, + TRUE); + return TRUE; + } + + /* select next matching iter */ + if (event->keyval == GDK_Down) + { + gtk_tree_view_search_move (widget, + tree_view, + FALSE); + return TRUE; + } + return FALSE; +} + +static void +gtk_tree_view_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_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_search_iter (model, selection, + &iter, text, + &count, *selected_iter); + + } +} + +static gboolean +gtk_tree_view_search_equal_func (GtkTreeModel *model, + gint column, + gchar *key, + GtkTreeIter *iter) +{ + gboolean retval = TRUE; + gchar *normalized_string; + gchar *normalized_key; + gchar *case_normalized_string; + gchar *case_normalized_key; + GValue value = {0,}; + gint key_len; + + gtk_tree_model_get_value (model, iter, column, &value); + normalized_string = g_utf8_normalize (g_value_get_string (&value), G_NORMALIZE_ALL); + normalized_key = g_utf8_normalize (key, G_NORMALIZE_ALL); + case_normalized_string = g_utf8_casefold (normalized_string); + case_normalized_key = g_utf8_casefold (normalized_key); + + key_len = strlen (case_normalized_key); + + if (!strncmp (case_normalized_key, case_normalized_string, key_len)) + retval = FALSE; + + g_value_unset (&value); + g_free (normalized_key); + g_free (normalized_string); + g_free (case_normalized_key); + g_free (case_normalized_string); + + return retval; +} + +static gboolean +gtk_tree_view_search_iter (GtkTreeModel *model, + GtkTreeSelection *selection, + GtkTreeIter *iter, + gchar *text, + gint *count, + gint n) +{ + GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection); + GtkTreeViewColumn *column = + gtk_tree_view_get_column (tree_view, tree_view->priv->search_column); + + if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter)) + { + (*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_view_real_set_cursor (tree_view, path, FALSE); + gtk_tree_path_free (path); + + return TRUE; + } + } + + 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_search_iter (model, selection, + &child, text, + count, n); + + if (ret) + return TRUE; /* iter found and selected */ + } + + while (gtk_tree_model_iter_next (model, iter)) + { + if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter)) + { + (*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_view_real_set_cursor (tree_view, path, FALSE); + gtk_tree_path_free (path); + + return TRUE; + } + } + + 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_search_iter (model, selection, + &child, text, + count, n); + + if (ret) + return TRUE; /* iter found and selected */ + } + } + + return FALSE; +} + +static void +gtk_tree_view_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_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); + } +} diff --git a/gtk/gtktreeview.h b/gtk/gtktreeview.h index cee0a1e28..f0412a84f 100644 --- a/gtk/gtktreeview.h +++ b/gtk/gtktreeview.h @@ -19,6 +19,7 @@ #ifndef __GTK_TREE_VIEW_H__ #define __GTK_TREE_VIEW_H__ +#include #include #include #include @@ -119,6 +120,10 @@ typedef gboolean (* GtkTreeViewDroppableFunc) (GtkTreeView *tree_vi GtkTreePath *path, GtkTreeViewDropPosition *pos, gpointer user_data); +typedef gboolean (*GtkTreeViewSearchEqualFunc) (GtkTreeModel *model, + gint column, + gchar *key, + GtkTreeIter *iter); /* Creators */ @@ -275,13 +280,25 @@ gboolean gtk_tree_view_get_dest_row_at_pos (GtkTreeView GdkPixmap *gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view, GtkTreePath *path); +/* Interactive search */ +void gtk_tree_view_set_enable_search (GtkTreeView *tree_view, + gboolean use_search); +gboolean gtk_tree_view_get_enable_search (GtkTreeView *tree_view); +gint gtk_tree_view_get_search_column (GtkTreeView *tree_view); +void gtk_tree_view_set_search_column (GtkTreeView *tree_view, + gint column); +GtkTreeViewSearchEqualFunc gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view); +void gtk_tree_view_set_search_equal_func (GtkTreeView *tree_view, + GtkTreeViewSearchEqualFunc search_compare_func, + gpointer search_data, + GtkDestroyNotify search_destroy); /* This function should really never be used. It is just for use by ATK. */ -typedef void (* GtkTreeDestroyCountFunc) (GtkTreeView *tree_view, - GtkTreePath *path, - gint children, - gpointer user_data); +typedef void (* GtkTreeDestroyCountFunc) (GtkTreeView *tree_view, + GtkTreePath *path, + gint children, + gpointer user_data); void gtk_tree_view_set_destroy_count_func (GtkTreeView *tree_view, GtkTreeDestroyCountFunc func, gpointer data, -- 2.43.2