Re: [Patch] Interactive search (aka typeahead) enhancement patch



Luis Villa wrote:
> On 2/6/06, Federico Mena Quintero <federico ximian com> wrote:
> 
>>On Mon, 2006-02-06 at 19:06 +0100, Alexander Larsson wrote:
>>
>>>>FYI, we got a lot of complaints for GtkFileChooser when typeahead
>>>>matched strings in the middle of filenames, not just in the beginning.
>>>>You may want to reconsider this :)
>>>
>>>What exactly was the complaints?
>>>Apart from the standard "you changed something, gnome sucks!".
>>
>>People assumed that typing the first few characters of a filename would
>>make the file chooser jump to the first filename in the list that
>>started with those characters.  Instead, they would jump to a filename
>>they didn't expect:  type "re" and it jumps to "andrea.txt", instead of
>>"resume.txt", which is what they expected.
> 
> 
> Isn't the obviously correct behavior that it only jumps to andrea.txt
> if re*.* does not exist?

Good point, that is a more complete behaviour imho, that is, to search
firstly at beginning of word and fallback to middle of the word if the
former didn't find anything. So in the example it'll first match
"resume.txt" and then you type one more char "rea" and will match
"andrea.txt".

I attach alex's patch with the said modification to the icon view
typeahead (changes are only in nautilus-icon-container.c), also I could
implement it within the existent loop so no performance penalty added.

Unfortunately we can't change the list view to get this behaviour as we
use the built-in gtktreeview typeahead, but I think that gtktreeview
itself should get this behaviour by default as it's just the current one
plus a fallback to search in middle-of-word if beginning-of-word didn't
find anything...

Index: libnautilus-private/nautilus-icon-container.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.c,v
retrieving revision 1.407
diff -u -p -r1.407 nautilus-icon-container.c
--- libnautilus-private/nautilus-icon-container.c	29 Jan 2006 21:48:57 -0000	1.407
+++ libnautilus-private/nautilus-icon-container.c	6 Feb 2006 14:37:10 -0000
@@ -3819,8 +3822,11 @@ nautilus_icon_container_search_iter (Nau
 {
 	GList *p;
 	NautilusIcon *icon;
+	NautilusIcon *icon_strstr;
+	gboolean strstr_matched;
 	const char *name;
 	int count;
+	int count2;
 	char *normalized_key, *case_normalized_key;
 	char *normalized_name, *case_normalized_name;
 	
@@ -3838,7 +3844,10 @@ nautilus_icon_container_search_iter (Nau
 	}
 	
 	icon = NULL;
+	icon_strstr = NULL;
+	strstr_matched = FALSE;
 	count = 0;
+	count2 = 0;
 	for (p = container->details->icons; p != NULL && count != n; p = p->next) {
 		icon = p->data;
 		name = nautilus_icon_canvas_item_get_editable_text (icon->item);
@@ -3866,6 +3875,16 @@ nautilus_icon_container_search_iter (Nau
 			count++;
 		}
 
+		if (! strstr_matched) {
+			if (strstr (case_normalized_name, case_normalized_key)) {
+				count2++;
+				if (count2 == n) {
+					icon_strstr = p->data;
+					strstr_matched = TRUE;
+				}
+			}
+		}
+
 		g_free (case_normalized_name);
 	}
 
@@ -3876,6 +3895,14 @@ nautilus_icon_container_search_iter (Nau
 			g_signal_emit (container, signals[SELECTION_CHANGED], 0);
 		}
 		schedule_keyboard_icon_reveal (container, icon);
+		
+		return TRUE;
+	}
+	else if (strstr_matched) {
+		if (select_one_unselect_others (container, icon_strstr)) {
+			g_signal_emit (container, signals[SELECTION_CHANGED], 0);
+		}
+		schedule_keyboard_icon_reveal (container, icon_strstr);
 		
 		return TRUE;
 	}
Index: libnautilus-private/nautilus-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-view.c,v
retrieving revision 1.4
diff -u -p -r1.4 nautilus-view.c
--- libnautilus-private/nautilus-view.c	31 Jan 2006 00:23:54 -0000	1.4
+++ libnautilus-private/nautilus-view.c	6 Feb 2006 14:37:11 -0000
@@ -270,3 +270,13 @@ nautilus_view_pop_up_location_context_me
 		(* NAUTILUS_VIEW_GET_IFACE (view)->pop_up_location_context_menu) (view, event);
 	}
 }
+
+void
+nautilus_view_start_interactive_search (NautilusView   *view)
+{
+	g_return_if_fail (NAUTILUS_IS_VIEW (view));
+
+	if (NAUTILUS_VIEW_GET_IFACE (view)->start_interactive_search != NULL) {
+		(* NAUTILUS_VIEW_GET_IFACE (view)->start_interactive_search) (view);
+	}
+}
Index: libnautilus-private/nautilus-view.h
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-view.h,v
retrieving revision 1.4
diff -u -p -r1.4 nautilus-view.h
--- libnautilus-private/nautilus-view.h	31 Jan 2006 00:23:54 -0000	1.4
+++ libnautilus-private/nautilus-view.h	6 Feb 2006 14:37:11 -0000
@@ -117,6 +117,9 @@ struct _NautilusViewIface 
 	void           (* pop_up_location_context_menu) (NautilusView   *view,
 							 GdkEventButton *event);
 
+	/* Request popup the interactive search dialog (aka typeahead) */
+	void           (* start_interactive_search) (NautilusView        *view);
+
 	/* Padding for future expansion */
 	void (*_reserved1) (void);
 	void (*_reserved2) (void);
@@ -124,7 +127,6 @@ struct _NautilusViewIface 
 	void (*_reserved4) (void);
 	void (*_reserved5) (void);
 	void (*_reserved6) (void);
-	void (*_reserved7) (void);
 };
 
 GType             nautilus_view_get_type             (void);
@@ -154,6 +156,8 @@ NautilusZoomLevel nautilus_view_get_zoom
 void              nautilus_view_pop_up_location_context_menu (NautilusView    *view,
 							      GdkEventButton  *event);
 void              nautilus_view_grab_focus                 (NautilusView      *view);
+void              nautilus_view_start_interactive_search   (NautilusView      *view);
+  
 
 G_END_DECLS
 
Index: src/nautilus-navigation-window-ui.xml
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-navigation-window-ui.xml,v
retrieving revision 1.14
diff -u -p -r1.14 nautilus-navigation-window-ui.xml
--- src/nautilus-navigation-window-ui.xml	15 Dec 2005 14:25:58 -0000	1.14
+++ src/nautilus-navigation-window-ui.xml	6 Feb 2006 14:37:11 -0000
@@ -17,6 +17,11 @@
 			<menuitem name="Show Hide Statusbar" action="Show Hide Statusbar"/>
 		</placeholder>
 	</menu>
+	<menu action="Edit">
+		<placeholder name="Select Items">
+			<menuitem name="Find" action="Interactive Search"/>
+		</placeholder>
+	</menu>
         <placeholder name="Other Menus">
 	        <menu action="Go">
                         <placeholder name="Navigation Items">
Index: src/nautilus-window-menus.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-window-menus.c,v
retrieving revision 1.293
diff -u -p -r1.293 nautilus-window-menus.c
--- src/nautilus-window-menus.c	15 Dec 2005 14:25:58 -0000	1.293
+++ src/nautilus-window-menus.c	6 Feb 2006 14:37:11 -0000
@@ -346,6 +346,16 @@ action_zoom_normal_callback (GtkAction *
 }
 
 static void
+action_interactive_search_spatial_callback (GtkAction *action,
+					    gpointer   user_data)
+{	
+	NautilusWindow *window;
+	window = NAUTILUS_WINDOW (user_data);
+
+	nautilus_view_start_interactive_search (window->content_view);
+}
+
+static void
 preferences_respond_callback (GtkDialog *dialog,
 			      gint response_id)
 {
@@ -702,6 +712,9 @@ static const GtkActionEntry main_entries
     N_("CD/_DVD Creator"), NULL,           /* label, accelerator */
     N_("Go to the CD/DVD Creator"),                                  /* tooltip */ 
     G_CALLBACK (action_go_to_burn_cd_callback) },
+  { "Interactive Search", GTK_STOCK_FIND, N_("_Find in this folder"),
+    "<control>J", N_("Find files in this folder"),
+    G_CALLBACK (action_interactive_search_spatial_callback) },
 };
 
 /**
Index: src/file-manager/fm-icon-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-icon-view.c,v
retrieving revision 1.318
diff -u -p -r1.318 fm-icon-view.c
--- src/file-manager/fm-icon-view.c	12 Dec 2005 16:59:11 -0000	1.318
+++ src/file-manager/fm-icon-view.c	6 Feb 2006 14:37:11 -0000
@@ -183,6 +183,7 @@ static void                 fm_icon_view
 static void                 fm_icon_view_set_directory_tighter_layout (FMIconView           *icon_view,
 								       NautilusFile         *file,
 								       gboolean              tighter_layout);
+static void                 fm_icon_view_start_interactive_search     (NautilusView         *view);
 static const SortCriterion *get_sort_criterion_by_sort_type           (NautilusFileSortType  sort_type);
 static void                 set_sort_criterion_by_sort_type           (FMIconView           *icon_view,
 								       NautilusFileSortType  sort_type);
@@ -2584,6 +2585,21 @@ icon_view_scroll_to_file (NautilusView *
 	}
 }
 
+static void
+fm_icon_view_start_interactive_search (NautilusView *view)
+{
+	NautilusIconContainer  *icon_container;
+	gboolean ret;
+
+	icon_container = NAUTILUS_ICON_CONTAINER (GTK_BIN (FM_ICON_VIEW (view))->child);
+	if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (icon_container))) {
+		gtk_widget_grab_focus (GTK_WIDGET (icon_container));
+	}
+
+	ret = EEL_CALL_METHOD_WITH_RETURN_VALUE
+		(NAUTILUS_ICON_CONTAINER_CLASS, icon_container,
+		 start_interactive_search, (icon_container));
+}
 
 static void
 fm_icon_view_class_init (FMIconViewClass *klass)
@@ -2666,6 +2682,7 @@ fm_icon_view_iface_init (NautilusViewIfa
 	iface->get_first_visible_file = icon_view_get_first_visible_file;
 	iface->scroll_to_file = icon_view_scroll_to_file;
 	iface->get_title = NULL;
+	iface->start_interactive_search = fm_icon_view_start_interactive_search;
 }
 
 static void
Index: src/file-manager/fm-list-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-list-view.c,v
retrieving revision 1.265
diff -u -p -r1.265 fm-list-view.c
--- src/file-manager/fm-list-view.c	31 Jan 2006 00:23:55 -0000	1.265
+++ src/file-manager/fm-list-view.c	6 Feb 2006 14:37:11 -0000
@@ -135,6 +135,12 @@ static NautilusZoomLevel        default_
 static GList *                  default_visible_columns_auto_value;
 static GList *                  default_column_order_auto_value;
 
+static gboolean interactive_search_equal_func (GtkTreeModel  *model,
+						gint 		column,
+						const gchar	*key,
+						GtkTreeIter	*iter,
+						gpointer	search_data);
+static void   fm_list_view_start_interactive_search	   (NautilusView      *view);
 static GList *fm_list_view_get_selection                   (FMDirectoryView   *view);
 static GList *fm_list_view_get_selection_for_file_transfer (FMDirectoryView   *view);
 static void   fm_list_view_set_zoom_level                  (FMListView        *view,
@@ -236,6 +242,82 @@ button_event_modifies_selection (GdkEven
 	return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
 }
 
+static gboolean
+interactive_search_equal_func (GtkTreeModel *model,
+				 gint          column,
+				 const gchar  *key,
+				 GtkTreeIter  *iter,
+				 gpointer      search_data)
+{
+	gboolean retval;
+	const gchar *str;
+	gchar *normalized_string;
+	gchar *normalized_key;
+	gchar *case_normalized_string;
+	gchar *case_normalized_key;
+	GValue value = {0,};
+	GValue transformed = {0,};
+
+	gtk_tree_model_get_value (model, iter, column, &value);
+
+	g_value_init (&transformed, G_TYPE_STRING);
+	
+	if (!g_value_transform (&value, &transformed)) {
+		g_value_unset (&value);
+		return TRUE;
+	}
+
+	g_value_unset (&value);
+	
+	str = g_value_get_string (&transformed);
+	if (str == NULL) {
+		g_value_unset (&transformed);
+		return TRUE;
+	}
+
+	normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
+	normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
+	
+	case_normalized_string = NULL;
+	case_normalized_key = NULL;
+	retval = TRUE;
+	if (normalized_string && normalized_key) {
+		case_normalized_string = g_utf8_casefold (normalized_string, -1);
+		case_normalized_key = g_utf8_casefold (normalized_key, -1);
+		
+		if (strstr (case_normalized_string, case_normalized_key) != NULL) {
+			retval = FALSE;
+		}
+	}
+	
+	g_value_unset (&transformed);
+	g_free (normalized_key);
+	g_free (normalized_string);
+	g_free (case_normalized_key);
+	g_free (case_normalized_string);
+	
+	return retval;
+}
+
+static void
+fm_list_view_start_interactive_search (NautilusView *view)
+{
+	GtkTreeView *tv;
+	gboolean ret;
+	FMListView *listview;
+
+	listview = FM_LIST_VIEW (view);
+	tv = listview->details->tree_view;
+	
+	if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tv))) {
+		gtk_widget_grab_focus (GTK_WIDGET (tv));
+	}
+
+	ret = EEL_CALL_METHOD_WITH_RETURN_VALUE
+		(GTK_TREE_VIEW_CLASS, tv,
+		 start_interactive_search, (tv));
+}
+
 static void
 fm_list_view_did_not_drag (FMListView *view,
 			   GdkEventButton *event)
@@ -2543,6 +2625,7 @@ fm_list_view_iface_init (NautilusViewIfa
 	iface->scroll_to_file = list_view_scroll_to_file;
 	iface->get_title = NULL;
 	iface->grab_focus = fm_list_view_grab_focus;
+	iface->start_interactive_search = fm_list_view_start_interactive_search;
 }
 
 
@@ -2552,6 +2635,10 @@ fm_list_view_init (FMListView *list_view
 	list_view->details = g_new0 (FMListViewDetails, 1);
 
 	create_and_set_up_tree_view (list_view);
+
+	gtk_tree_view_set_search_equal_func (list_view->details->tree_view,
+					     interactive_search_equal_func,
+					     NULL, NULL);
 
 	eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_SORT_ORDER,
 						  default_sort_order_changed_callback,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]