diff options
author | Dave Camp <dave@ximian.com> | 2004-01-10 20:58:06 +0000 |
---|---|---|
committer | Dave Camp <campd@src.gnome.org> | 2004-01-10 20:58:06 +0000 |
commit | 961d315c4b82ebd06dc1580b0e89bb4be92520bb (patch) | |
tree | 25b658d684321f7d796e0897b2bd8a11eecad5d1 /src/file-manager | |
parent | 711ee0bda0107a6ebc77738d45a29a3bb5734169 (diff) | |
download | nautilus-961d315c4b82ebd06dc1580b0e89bb4be92520bb.tar.gz |
Moved the typeahead duration to a public header. Implement icon-view-style
2004-01-10 Dave Camp <dave@ximian.com>
* libnautilus-private/nautilus-icon-container.h:
* libnautilus-private/nautilus-icon-container.c:
(handle_typeahead): Moved the typeahead duration to a
public header.
* src/file-manager/fm-list-view.c: (select_matching_name),
(fm_list_view_flush_typeselect_state), (handle_typeahead),
(key_press_callback), (fm_list_view_finalize),
(fm_list_view_instance_init): Implement icon-view-style
typeahead for the list view. Patch from
Jürg Billeter <j@bitron.ch>
Diffstat (limited to 'src/file-manager')
-rw-r--r-- | src/file-manager/fm-list-view.c | 148 |
1 files changed, 143 insertions, 5 deletions
diff --git a/src/file-manager/fm-list-view.c b/src/file-manager/fm-list-view.c index 1a1128057..5f909aa8c 100644 --- a/src/file-manager/fm-list-view.c +++ b/src/file-manager/fm-list-view.c @@ -28,6 +28,7 @@ #include <config.h> #include "fm-list-view.h" +#include <string.h> #include "fm-error-reporting.h" #include "fm-list-model.h" #include <eel/eel-cell-renderer-pixbuf-list.h> @@ -54,6 +55,14 @@ #include <libnautilus/nautilus-scroll-positionable.h> #include <libnautilus-private/nautilus-cell-renderer-pixbuf-emblem.h> +/* Included for the typeselect flush delay */ +#include <libnautilus-private/nautilus-icon-container.h> + +typedef struct { + char *type_select_pattern; + guint64 last_typeselect_time; +} TypeSelectState; + struct FMListViewDetails { GtkTreeView *tree_view; FMListModel *model; @@ -82,6 +91,9 @@ struct FMListViewDetails { gboolean drag_started; gboolean row_selected_on_button_down; + + /* typeahead selection state */ + TypeSelectState *type_select_state; }; /* @@ -571,6 +583,110 @@ button_release_callback (GtkWidget *widget, } 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; +} + +static 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_ICON_CONTAINER_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 +703,12 @@ key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_dat { 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 +718,37 @@ key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_dat 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 +1571,8 @@ fm_list_view_finalize (GObject *object) } 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 +1740,6 @@ fm_list_view_instance_init (FMListView *list_view) 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; } |