diff options
author | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2016-05-26 13:08:40 -0300 |
---|---|---|
committer | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2016-06-03 12:32:37 -0300 |
commit | 57ba49a13753f3e03e4b7e798a8b155ae24153b5 (patch) | |
tree | 4d2b3eeda9116305ad8581c4ac67271d6059d1ca /shell | |
parent | b6ab2a492237e051da8e8885a674063137c6c1f4 (diff) | |
download | gnome-control-center-57ba49a13753f3e03e4b7e798a8b155ae24153b5.tar.gz |
window: reimplement search
We previously had a dedicate view for handling search,
based on model filtering and a custom panel to display
that differently.
After moving to GtkListBox, search can be trivially
done by using a filtering function, and widgets can
be fine-tuned to display extra information.
This patch, then, reimplements the search using a filtering
function over the panels' list.
https://bugzilla.gnome.org/show_bug.cgi?id=766922
Diffstat (limited to 'shell')
-rw-r--r-- | shell/alt/cc-window.c | 317 | ||||
-rw-r--r-- | shell/window.ui | 2 |
2 files changed, 48 insertions, 271 deletions
diff --git a/shell/alt/cc-window.c b/shell/alt/cc-window.c index f1eff97b2..40f85b5be 100644 --- a/shell/alt/cc-window.c +++ b/shell/alt/cc-window.c @@ -85,11 +85,6 @@ struct _CcWindow GtkListStore *store; - GtkTreeModel *search_filter; - GtkWidget *search_view; - gchar *filter_string; - gchar **filter_terms; - CcPanel *active_panel; }; @@ -292,8 +287,6 @@ shell_show_overview_page (CcWindow *self) self->previous_panels = g_queue_new (); /* clear the search text */ - g_free (self->filter_string); - self->filter_string = g_strdup (""); gtk_entry_set_text (GTK_ENTRY (self->search_entry), ""); if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (self->search_bar))) gtk_widget_grab_focus (self->search_entry); @@ -353,253 +346,70 @@ row_selected_cb (GtkListBox *listbox, } } +/* + * GtkListBox functions + */ static gboolean -model_filter_func (GtkTreeModel *model, - GtkTreeIter *iter, - CcWindow *self) +filter_func (GtkListBoxRow *row, + gpointer user_data) { - char **t; - gboolean matches = FALSE; - - if (!self->filter_string || !self->filter_terms) - return FALSE; - - for (t = self->filter_terms; *t; t++) - { - matches = cc_shell_model_iter_matches_search (CC_SHELL_MODEL (model), - iter, - *t); - if (!matches) - break; - } - - return matches; -} + CcWindow *self; + RowData *data; + gchar *search_text, *panel_text, *panel_description; + const gchar *entry_text; + gboolean retval; -static void -search_entry_changed_cb (GtkEntry *entry, - CcWindow *self) -{ - char *str; + self = CC_WINDOW (user_data); + data = g_object_get_data (G_OBJECT (row), "data"); + entry_text = gtk_entry_get_text (GTK_ENTRY (self->search_entry)); - /* if the entry text was set manually (not by the user) */ - if (!g_strcmp0 (self->filter_string, gtk_entry_get_text (entry))) - { - cc_shell_model_set_sort_terms (CC_SHELL_MODEL (self->store), NULL); - return; - } + panel_text = cc_util_normalize_casefold_and_unaccent (data->name); + search_text = cc_util_normalize_casefold_and_unaccent (entry_text); + panel_description = cc_util_normalize_casefold_and_unaccent (data->description); - /* Don't re-filter for added trailing or leading spaces */ - str = cc_util_normalize_casefold_and_unaccent (gtk_entry_get_text (entry)); - g_strstrip (str); - if (!g_strcmp0 (str, self->filter_string)) - { - g_free (str); - return; - } + g_strstrip (panel_text); + g_strstrip (search_text); + g_strstrip (panel_description); - g_free (self->filter_string); - self->filter_string = str; + /* + * The description label is only visible when the search is + * happening. + */ + gtk_widget_set_visible (data->description_label, g_utf8_strlen (search_text, -1) > 0); - g_strfreev (self->filter_terms); - self->filter_terms = g_strsplit (self->filter_string, " ", -1); + retval = g_strstr_len (panel_text, -1, search_text) != NULL || + g_strstr_len (panel_description, -1, search_text) != NULL; - cc_shell_model_set_sort_terms (CC_SHELL_MODEL (self->store), self->filter_terms); + g_free (panel_text); + g_free (search_text); + g_free (panel_description); - if (!g_strcmp0 (self->filter_string, "")) - { - shell_show_overview_page (self); - } - else - { - gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (self->search_filter)); - gtk_stack_set_visible_child_name (GTK_STACK (self->stack), SEARCH_PAGE); - } + return retval; } -static gboolean -search_entry_key_press_event_cb (GtkEntry *entry, - GdkEventKey *event, - CcWindow *self) +static void +search_entry_changed_cb (GtkEntry *entry, + CcWindow *self) { - if (event->keyval == GDK_KEY_Return && - g_strcmp0 (self->filter_string, "") != 0) - { - GtkTreePath *path; - GtkTreeSelection *selection; - - path = gtk_tree_path_new_first (); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->search_view)); - gtk_tree_selection_select_path (selection, path); - - if (!gtk_tree_selection_path_is_selected (selection, path)) - { - gtk_tree_path_free (path); - return FALSE; - } - - gtk_tree_view_row_activated (GTK_TREE_VIEW (self->search_view), path, - gtk_tree_view_get_column (GTK_TREE_VIEW (self->search_view), 0)); - gtk_tree_path_free (path); - return TRUE; - } - - if (event->keyval == GDK_KEY_Escape) - { - gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (self->search_bar), FALSE); - gtk_entry_set_text (entry, ""); - return TRUE; - } - - return FALSE; + gtk_list_box_invalidate_filter (GTK_LIST_BOX (self->listbox)); } static void -on_search_row_activated (GtkTreeView *treeview, - GtkTreePath *path, - GtkTreeViewColumn *column, - CcWindow *shell) +search_entry_activate_cb (GtkEntry *entry, + CcWindow *self) { - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - char *id = NULL; - - selection = gtk_tree_view_get_selection (treeview); - - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) - return; + GtkListBoxRow *row; - gtk_tree_model_get (model, &iter, - COL_ID, &id, - -1); + row = gtk_list_box_get_row_at_y (GTK_LIST_BOX (self->listbox), 0); - if (id) - cc_window_set_active_panel_from_id (CC_SHELL (shell), id, NULL, NULL); - - gtk_tree_selection_unselect_all (selection); - - g_free (id); -} - -static gboolean -on_search_button_press_event (GtkTreeView *treeview, - GdkEventButton *event, - CcWindow *shell) -{ - if (event->type == GDK_BUTTON_PRESS && event->button == 1) + if (row) { - GtkTreePath *path = NULL; - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - - /* We don't check for the position being blank, - * it could be the dead space between columns */ - gtk_tree_view_is_blank_at_pos (treeview, - event->x, event->y, - &path, - NULL, - NULL, - NULL); - if (path == NULL) - return FALSE; - - model = gtk_tree_view_get_model (treeview); - if (gtk_tree_model_get_iter (model, &iter, path) == FALSE) - { - gtk_tree_path_free (path); - return FALSE; - } - - selection = gtk_tree_view_get_selection (treeview); - gtk_tree_selection_select_iter (selection, &iter); - - on_search_row_activated (treeview, NULL, NULL, shell); - - gtk_tree_path_free (path); - - return TRUE; + gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (self->search_bar), FALSE); + gtk_list_box_select_row (GTK_LIST_BOX (self->listbox), row); + gtk_widget_grab_focus (GTK_WIDGET (row)); } - - return FALSE; } -static void -setup_search (CcWindow *self) -{ - GtkWidget *search_view; - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - g_return_if_fail (self->store != NULL); - - /* create the search filter */ - self->search_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (self->store), - NULL); - - gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (self->search_filter), - (GtkTreeModelFilterVisibleFunc) - model_filter_func, - self, NULL); - - /* set up the search view */ - self->search_view = search_view = gtk_tree_view_new (); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (search_view), FALSE); - gtk_tree_view_set_enable_search (GTK_TREE_VIEW (search_view), FALSE); - gtk_tree_view_set_model (GTK_TREE_VIEW (search_view), - GTK_TREE_MODEL (self->search_filter)); - /* This needs to happen after setting the model, otherwise - * the search column will be the first string column */ - gtk_tree_view_set_search_column (GTK_TREE_VIEW (search_view), -1); - - renderer = gtk_cell_renderer_pixbuf_new (); - g_object_set (renderer, - "xpad", 15, - "ypad", 10, - "stock-size", GTK_ICON_SIZE_DIALOG, - "follow-state", TRUE, - NULL); - column = gtk_tree_view_column_new_with_attributes ("Icon", renderer, - "gicon", COL_GICON, - NULL); - gtk_tree_view_column_set_expand (column, FALSE); - gtk_tree_view_append_column (GTK_TREE_VIEW (self->search_view), column); - - renderer = gtk_cell_renderer_text_new (); - g_object_set (renderer, - "xpad", 0, - NULL); - column = gtk_tree_view_column_new_with_attributes ("Name", renderer, - "text", COL_NAME, - NULL); - gtk_tree_view_column_set_expand (column, FALSE); - gtk_tree_view_append_column (GTK_TREE_VIEW (self->search_view), column); - - renderer = gd_styled_text_renderer_new (); - gd_styled_text_renderer_add_class (GD_STYLED_TEXT_RENDERER (renderer), "dim-label"); - g_object_set (renderer, - "xpad", 15, - "ellipsize", PANGO_ELLIPSIZE_END, - NULL); - column = gtk_tree_view_column_new_with_attributes ("Description", renderer, - "text", COL_DESCRIPTION, - NULL); - gtk_tree_view_column_set_expand (column, TRUE); - gtk_tree_view_append_column (GTK_TREE_VIEW (self->search_view), column); - - gtk_container_add (GTK_CONTAINER (self->search_scrolled), search_view); - - g_signal_connect (self->search_view, "row-activated", - G_CALLBACK (on_search_row_activated), self); - g_signal_connect (self->search_view, "button-press-event", - G_CALLBACK (on_search_button_press_event), self); - - self->filter_string = g_strdup (""); - - gtk_widget_show (self->search_view); -} static void setup_model (CcWindow *shell) @@ -930,7 +740,6 @@ cc_window_dispose (GObject *object) } g_clear_object (&self->store); - g_clear_object (&self->search_filter); g_clear_object (&self->active_panel); G_OBJECT_CLASS (cc_window_parent_class)->dispose (object); @@ -947,9 +756,6 @@ cc_window_finalize (GObject *object) self->previous_panels = NULL; } - g_free (self->filter_string); - g_strfreev (self->filter_terms); - G_OBJECT_CLASS (cc_window_parent_class)->finalize (object); } @@ -992,8 +798,8 @@ cc_window_class_init (CcWindowClass *klass) gtk_widget_class_bind_template_callback (widget_class, previous_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, gdk_window_set_cb); gtk_widget_class_bind_template_callback (widget_class, row_selected_cb); + gtk_widget_class_bind_template_callback (widget_class, search_entry_activate_cb); gtk_widget_class_bind_template_callback (widget_class, search_entry_changed_cb); - gtk_widget_class_bind_template_callback (widget_class, search_entry_key_press_event_cb); gtk_widget_class_bind_template_callback (widget_class, sidelist_size_allocate_cb); gtk_widget_class_bind_template_callback (widget_class, stack_page_notify_cb); gtk_widget_class_bind_template_callback (widget_class, window_map_event_cb); @@ -1019,9 +825,6 @@ window_key_press_event (GtkWidget *win, gboolean retval; GdkModifierType state; gboolean is_rtl; - gboolean overview; - gboolean search; - const gchar *id; retval = GDK_EVENT_PROPAGATE; state = event->state; @@ -1030,12 +833,7 @@ window_key_press_event (GtkWidget *win, state = state & gtk_accelerator_get_default_mod_mask (); is_rtl = gtk_widget_get_direction (win) == GTK_TEXT_DIR_RTL; - id = gtk_stack_get_visible_child_name (GTK_STACK (self->stack)); - overview = g_str_equal (id, OVERVIEW_PAGE); - search = g_str_equal (id, SEARCH_PAGE); - - if ((overview || search) && - gtk_search_bar_handle_event (GTK_SEARCH_BAR (self->search_bar), (GdkEvent*) event) == GDK_EVENT_STOP) + if (gtk_search_bar_handle_event (GTK_SEARCH_BAR (self->search_bar), (GdkEvent*) event) == GDK_EVENT_STOP) return GDK_EVENT_STOP; if (state == GDK_CONTROL_MASK) @@ -1046,8 +844,6 @@ window_key_press_event (GtkWidget *win, case GDK_KEY_S: case GDK_KEY_f: case GDK_KEY_F: - if (!overview && !search) - break; retval = !gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (self->search_bar)); gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (self->search_bar), retval); if (retval) @@ -1061,18 +857,10 @@ window_key_press_event (GtkWidget *win, break; case GDK_KEY_W: case GDK_KEY_w: - if (!overview) - shell_show_overview_page (self); retval = GDK_EVENT_STOP; break; } } - else if (state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Up) - { - if (!overview) - shell_show_overview_page (self); - retval = GDK_EVENT_STOP; - } else if ((!is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Left) || (is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Right) || event->keyval == GDK_KEY_Back) @@ -1080,19 +868,8 @@ window_key_press_event (GtkWidget *win, previous_button_clicked_cb (NULL, self); retval = GDK_EVENT_STOP; } - return retval; -} -static void -create_search_page (CcWindow *self) -{ - self->search_scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->search_scrolled), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_stack_add_named (GTK_STACK (self->stack), self->search_scrolled, SEARCH_PAGE); - - /* setup search functionality */ - setup_search (self); + return retval; } static void @@ -1113,7 +890,8 @@ create_window (CcWindow *self) * not tracked. */ self->listbox = gtk_list_box_new (); - gtk_list_box_set_selection_mode (GTK_LIST_BOX (self->listbox), GTK_SELECTION_SINGLE); + gtk_list_box_set_selection_mode (GTK_LIST_BOX (self->listbox), GTK_SELECTION_BROWSE); + gtk_list_box_set_filter_func (GTK_LIST_BOX (self->listbox), filter_func, self, NULL); g_signal_connect (self->listbox, "row-selected", G_CALLBACK (row_selected_cb), self); @@ -1121,7 +899,6 @@ create_window (CcWindow *self) gtk_widget_show (self->listbox); setup_model (self); - create_search_page (self); /* connect various signals */ g_signal_connect_after (self, "key_press_event", diff --git a/shell/window.ui b/shell/window.ui index 9712f7e4e..ee97f4dac 100644 --- a/shell/window.ui +++ b/shell/window.ui @@ -33,8 +33,8 @@ <property name="primary_icon_name">edit-find-symbolic</property> <property name="primary_icon_activatable">False</property> <property name="primary_icon_sensitive">False</property> + <signal name="activate" handler="search_entry_activate_cb" object="CcWindow" swapped="no" /> <signal name="search-changed" handler="search_entry_changed_cb" object="CcWindow" swapped="no" /> - <signal name="key-press-event" handler="search_entry_key_press_event_cb" object="CcWindow" swapped="no" /> </object> </child> </object> |