[PATCH] Typeahead search in list view
- From: Jürg Billeter <j bitron ch>
- To: nautilus-list gnome org
- Subject: [PATCH] Typeahead search in list view
- Date: Sat, 10 Jan 2004 21:07:03 +0100
Hi
I've created a patch to enable the typeahead search in the list view as
it is already implemented in the icon view. Hopefully going in until
Monday.
http://bugzilla.gnome.org/show_bug.cgi?id=85230
Regards,
Jürg
diff -ur nautilus/src/file-manager/fm-list-view.c nautilus-list-typeahead/src/file-manager/fm-list-view.c
--- nautilus/src/file-manager/fm-list-view.c 2004-01-10 20:45:12.000000000 +0100
+++ nautilus-list-typeahead/src/file-manager/fm-list-view.c 2004-01-10 20:50:03.000000000 +0100
@@ -54,6 +54,11 @@
#include <libnautilus/nautilus-scroll-positionable.h>
#include <libnautilus-private/nautilus-cell-renderer-pixbuf-emblem.h>
+typedef struct {
+ char *type_select_pattern;
+ guint64 last_typeselect_time;
+} TypeSelectState;
+
struct FMListViewDetails {
GtkTreeView *tree_view;
FMListModel *model;
@@ -82,6 +87,9 @@
gboolean drag_started;
gboolean row_selected_on_button_down;
+
+ /* typeahead selection state */
+ TypeSelectState *type_select_state;
};
/*
@@ -91,6 +99,14 @@
*/
#define LIST_VIEW_MINIMUM_ROW_HEIGHT 28
+enum {
+ NAUTILUS_TYPESELECT_FLUSH_DELAY = 1000000
+ /* After this time the current typeselect buffer will be
+ * thrown away and the new pressed character will be made
+ * the the start of a new pattern.
+ */
+};
+
static int click_policy_auto_value;
static NautilusFileSortType default_sort_order_auto_value;
static gboolean default_sort_reversed_auto_value;
@@ -571,6 +587,110 @@
}
static gboolean
+select_matching_name (FMListView *view,
+ const char *match_name)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ gboolean match_found;
+ GValue value = { 0 };
+ const gchar *file_name;
+
+ match_found = FALSE;
+
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (view->details->model), &iter)) {
+ return FALSE;
+ }
+
+ do {
+ gtk_tree_model_get_value (GTK_TREE_MODEL (view->details->model), &iter, FM_LIST_MODEL_NAME_COLUMN, &value);
+ file_name = g_value_get_string (&value);
+ match_found = (g_ascii_strncasecmp (match_name, file_name, MIN (strlen (match_name), strlen (file_name))) == 0);
+ g_value_unset (&value);
+
+ if (match_found) {
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->details->model), &iter);
+ gtk_tree_view_set_cursor (view->details->tree_view, path, NULL, FALSE);
+ gtk_tree_view_scroll_to_cell (view->details->tree_view, path, NULL, FALSE, 0, 0);
+ gtk_tree_path_free (path);
+
+ return TRUE;
+ }
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (view->details->model), &iter));
+
+ return FALSE;
+}
+
+void
+fm_list_view_flush_typeselect_state (FMListView *view)
+{
+ if (view->details->type_select_state == NULL) {
+ return;
+ }
+
+ g_free (view->details->type_select_state->type_select_pattern);
+ g_free (view->details->type_select_state);
+ view->details->type_select_state = NULL;
+}
+
+static gboolean
+handle_typeahead (FMListView *view, const char *key_string)
+{
+ char *new_pattern;
+ gint64 now;
+ gint64 time_delta;
+ int key_string_length;
+ int index;
+
+ g_assert (key_string != NULL);
+ g_assert (strlen (key_string) < 5);
+
+ key_string_length = strlen (key_string);
+
+ if (key_string_length == 0) {
+ /* can be an empty string if the modifier was held down, etc. */
+ return FALSE;
+ }
+
+ /* only handle if printable keys typed */
+ for (index = 0; index < key_string_length; index++) {
+ if (!g_ascii_isprint (key_string[index])) {
+ return FALSE;
+ }
+ }
+
+ /* lazily allocate the typeahead state */
+ if (view->details->type_select_state == NULL) {
+ view->details->type_select_state = g_new0 (TypeSelectState, 1);
+ }
+
+ /* find out how long since last character was typed */
+ now = eel_get_system_time ();
+ time_delta = now - view->details->type_select_state->last_typeselect_time;
+ if (time_delta < 0 || time_delta > NAUTILUS_TYPESELECT_FLUSH_DELAY) {
+ /* the typeselect state is too old, start with a fresh one */
+ g_free (view->details->type_select_state->type_select_pattern);
+ view->details->type_select_state->type_select_pattern = NULL;
+ }
+
+ if (view->details->type_select_state->type_select_pattern != NULL) {
+ new_pattern = g_strconcat
+ (view->details->type_select_state->type_select_pattern,
+ key_string, NULL);
+ g_free (view->details->type_select_state->type_select_pattern);
+ } else {
+ new_pattern = g_strdup (key_string);
+ }
+
+ view->details->type_select_state->type_select_pattern = new_pattern;
+ view->details->type_select_state->last_typeselect_time = now;
+
+ select_matching_name (view, new_pattern);
+
+ return TRUE;
+}
+
+static gboolean
popup_menu_callback (GtkWidget *widget, gpointer callback_data)
{
FMListView *view;
@@ -587,8 +707,12 @@
{
FMDirectoryView *view;
GdkEventButton button_event = { 0 };
+ gboolean handled;
+ gboolean flush_typeahead;
view = FM_DIRECTORY_VIEW (callback_data);
+ handled = FALSE;
+ flush_typeahead = TRUE;
switch (event->keyval) {
case GDK_F10:
@@ -598,23 +722,37 @@
break;
case GDK_space:
if (event->state & GDK_CONTROL_MASK) {
- return FALSE;
+ handled = FALSE;
+ break;
}
if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (FM_LIST_VIEW (view)->details->tree_view))) {
- return FALSE;
+ handled = FALSE;
+ break;
}
activate_selected_items (FM_LIST_VIEW (view));
- return TRUE;
+ handled = TRUE;
+ break;
case GDK_Return:
case GDK_KP_Enter:
activate_selected_items (FM_LIST_VIEW (view));
- return TRUE;
+ handled = TRUE;
+ break;
default:
+ /* Don't use Control or Alt keys for type-selecting, because they
+ * might be used for menus.
+ */
+ handled = (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) == 0 &&
+ handle_typeahead (FM_LIST_VIEW (view), event->string);
+ flush_typeahead = !handled;
break;
}
+ if (flush_typeahead) {
+ /* any non-ascii key will force the typeahead state to be forgotten */
+ fm_list_view_flush_typeselect_state (FM_LIST_VIEW (view));
+ }
- return FALSE;
+ return handled;
}
static void
@@ -1437,6 +1575,8 @@
}
gtk_target_list_unref (list_view->details->source_target_list);
+
+ fm_list_view_flush_typeselect_state (list_view);
g_free (list_view->details);
@@ -1604,4 +1744,6 @@
G_CALLBACK (list_view_get_first_visible_file_callback), list_view, 0);
g_signal_connect_object (list_view->details->positionable, "scroll_to_file",
G_CALLBACK (list_view_scroll_to_file_callback), list_view, 0);
+
+ list_view->details->type_select_state = NULL;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]