summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2016-05-26 13:08:40 -0300
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2016-06-03 12:32:37 -0300
commit57ba49a13753f3e03e4b7e798a8b155ae24153b5 (patch)
tree4d2b3eeda9116305ad8581c4ac67271d6059d1ca /shell
parentb6ab2a492237e051da8e8885a674063137c6c1f4 (diff)
downloadgnome-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.c317
-rw-r--r--shell/window.ui2
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>