[gnome-control-center] shell: Make search results sorting smarter
- From: Rui Matos <rtcm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center] shell: Make search results sorting smarter
- Date: Fri, 16 May 2014 10:00:52 +0000 (UTC)
commit 13abc75273922e01b2987d483c1bb4a20de44d86
Author: Rui Matos <tiagomatos gmail com>
Date: Sat Apr 26 23:11:47 2014 +0200
shell: Make search results sorting smarter
Instead of just sorting by the name the sort order will now be:
1. Panels whose name match a search term
2. Panels whose keywords match the most search terms
3. Panels whose description match the most search terms
4. The remaining panels by name
https://bugzilla.gnome.org/show_bug.cgi?id=729027
search-provider/cc-search-provider.c | 4 +
shell/cc-shell-model.c | 238 +++++++++++++++++++++++++++++++++-
shell/cc-shell-model.h | 6 +
shell/cc-window.c | 2 +
4 files changed, 248 insertions(+), 2 deletions(-)
---
diff --git a/search-provider/cc-search-provider.c b/search-provider/cc-search-provider.c
index 19ac9ee..ab081d0 100644
--- a/search-provider/cc-search-provider.c
+++ b/search-provider/cc-search-provider.c
@@ -113,6 +113,8 @@ handle_get_initial_result_set (CcShellSearchProvider2 *skeleton,
casefolded_terms = get_casefolded_terms (terms);
results = g_ptr_array_new ();
+ cc_shell_model_set_sort_terms (CC_SHELL_MODEL (model), casefolded_terms);
+
ok = gtk_tree_model_get_iter_first (model, &iter);
while (ok)
{
@@ -154,6 +156,8 @@ handle_get_subsearch_result_set (CcShellSearchProvider2 *skeleton,
casefolded_terms = get_casefolded_terms (terms);
results = g_ptr_array_new ();
+ cc_shell_model_set_sort_terms (CC_SHELL_MODEL (model), casefolded_terms);
+
for (i = 0; previous_results[i]; i++)
{
if (gtk_tree_model_get_iter_from_string (model, &iter,
diff --git a/shell/cc-shell-model.c b/shell/cc-shell-model.c
index 2add15e..55f3e3c 100644
--- a/shell/cc-shell-model.c
+++ b/shell/cc-shell-model.c
@@ -30,12 +30,225 @@
#define GNOME_SETTINGS_PANEL_CATEGORY GNOME_SETTINGS_PANEL_ID_KEY
#define GNOME_SETTINGS_PANEL_ID_KEYWORDS "Keywords"
+struct _CcShellModelPrivate
+{
+ gchar **sort_terms;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (CcShellModel, cc_shell_model, GTK_TYPE_LIST_STORE)
+
+static gint
+sort_by_name (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b)
+{
+ gchar *a_name = NULL;
+ gchar *b_name = NULL;
+ gint rval = 0;
+
+ gtk_tree_model_get (model, a, COL_CASEFOLDED_NAME, &a_name, -1);
+ gtk_tree_model_get (model, b, COL_CASEFOLDED_NAME, &b_name, -1);
+
+ rval = g_strcmp0 (a_name, b_name);
+
+ g_free (a_name);
+ g_free (b_name);
+
+ return rval;
+}
+
+static gint
+sort_by_name_with_terms (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gchar **terms)
+{
+ gboolean a_match, b_match;
+ gchar *a_name = NULL;
+ gchar *b_name = NULL;
+ gint rval = 0;
+ gint i;
+
+ gtk_tree_model_get (model, a, COL_CASEFOLDED_NAME, &a_name, -1);
+ gtk_tree_model_get (model, b, COL_CASEFOLDED_NAME, &b_name, -1);
+
+ for (i = 0; terms[i]; ++i)
+ {
+ a_match = strstr (a_name, terms[i]) != NULL;
+ b_match = strstr (b_name, terms[i]) != NULL;
+
+ if (a_match && !b_match)
+ {
+ rval = -1;
+ break;
+ }
+ else if (!a_match && b_match)
+ {
+ rval = 1;
+ break;
+ }
+ }
+
+ g_free (a_name);
+ g_free (b_name);
+
+ return rval;
+}
+
+static gint
+count_matches (gchar **keywords,
+ gchar **terms)
+{
+ gint i, j, c;
+
+ if (!keywords || !terms)
+ return 0;
+
+ c = 0;
+
+ for (i = 0; terms[i]; ++i)
+ for (j = 0; keywords[j]; ++j)
+ if (strstr (keywords[j], terms[i]))
+ c += 1;
+
+ return c;
+}
+
+static gint
+sort_by_keywords_with_terms (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gchar **terms)
+{
+ gint a_matches, b_matches;
+ gchar **a_keywords = NULL;
+ gchar **b_keywords = NULL;
+ gint rval = 0;
+
+ gtk_tree_model_get (model, a, COL_KEYWORDS, &a_keywords, -1);
+ gtk_tree_model_get (model, b, COL_KEYWORDS, &b_keywords, -1);
+
+ a_matches = count_matches (a_keywords, terms);
+ b_matches = count_matches (b_keywords, terms);
+
+ if (a_matches > b_matches)
+ rval = -1;
+ else if (a_matches < b_matches)
+ rval = 1;
+
+ g_strfreev (a_keywords);
+ g_strfreev (b_keywords);
+
+ return rval;
+}
+
+static gint
+sort_by_description_with_terms (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gchar **terms)
+{
+ gint a_matches, b_matches;
+ gchar *a_description = NULL;
+ gchar *b_description = NULL;
+ gchar **a_description_split = NULL;
+ gchar **b_description_split = NULL;
+ gint rval = 0;
+
+ gtk_tree_model_get (model, a, COL_DESCRIPTION, &a_description, -1);
+ gtk_tree_model_get (model, b, COL_DESCRIPTION, &b_description, -1);
-G_DEFINE_TYPE (CcShellModel, cc_shell_model, GTK_TYPE_LIST_STORE)
+ if (a_description && !b_description)
+ {
+ rval = -1;
+ goto out;
+ }
+ else if (!a_description && b_description)
+ {
+ rval = 1;
+ goto out;
+ }
+ else if (!a_description && !b_description)
+ {
+ rval = 0;
+ goto out;
+ }
+
+ a_description_split = g_strsplit (a_description, " ", -1);
+ b_description_split = g_strsplit (b_description, " ", -1);
+
+ a_matches = count_matches (a_description_split, terms);
+ b_matches = count_matches (b_description_split, terms);
+
+ if (a_matches > b_matches)
+ rval = -1;
+ else if (a_matches < b_matches)
+ rval = 1;
+
+ out:
+ g_free (a_description);
+ g_free (b_description);
+ g_strfreev (a_description_split);
+ g_strfreev (b_description_split);
+
+ return rval;
+}
+
+static gint
+sort_with_terms (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gchar **terms)
+{
+ gint rval;
+
+ rval = sort_by_name_with_terms (model, a, b, terms);
+ if (rval)
+ return rval;
+
+ rval = sort_by_keywords_with_terms (model, a, b, terms);
+ if (rval)
+ return rval;
+
+ rval = sort_by_description_with_terms (model, a, b, terms);
+ if (rval)
+ return rval;
+
+ return sort_by_name (model, a, b);
+}
+
+static gint
+cc_shell_model_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer data)
+{
+ CcShellModel *self = data;
+ CcShellModelPrivate *priv = self->priv;
+
+ if (!priv->sort_terms || !priv->sort_terms[0])
+ return sort_by_name (model, a, b);
+ else
+ return sort_with_terms (model, a, b, priv->sort_terms);
+}
+
+static void
+cc_shell_model_finalize (GObject *object)
+{
+ CcShellModelPrivate *priv = CC_SHELL_MODEL (object)->priv;;
+
+ g_strfreev (priv->sort_terms);
+
+ G_OBJECT_CLASS (cc_shell_model_parent_class)->finalize (object);
+}
static void
cc_shell_model_class_init (CcShellModelClass *klass)
{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = cc_shell_model_finalize;
}
static void
@@ -44,10 +257,16 @@ cc_shell_model_init (CcShellModel *self)
GType types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_APP_INFO, G_TYPE_STRING,
G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_ICON, G_TYPE_STRV};
+ self->priv = cc_shell_model_get_instance_private (self);
+
gtk_list_store_set_column_types (GTK_LIST_STORE (self),
N_COLS, types);
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self), COL_NAME,
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (self),
+ cc_shell_model_sort_func,
+ self, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
GTK_SORT_ASCENDING);
}
@@ -142,3 +361,18 @@ cc_shell_model_iter_matches_search (CcShellModel *model,
return result;
}
+
+void
+cc_shell_model_set_sort_terms (CcShellModel *self,
+ gchar **terms)
+{
+ CcShellModelPrivate *priv = self->priv;
+
+ g_strfreev (priv->sort_terms);
+ priv->sort_terms = g_strdupv (terms);
+
+ /* trigger a re-sort */
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (self),
+ cc_shell_model_sort_func,
+ self, NULL);
+}
diff --git a/shell/cc-shell-model.h b/shell/cc-shell-model.h
index f92c25f..bf24173 100644
--- a/shell/cc-shell-model.h
+++ b/shell/cc-shell-model.h
@@ -50,6 +50,7 @@ G_BEGIN_DECLS
typedef struct _CcShellModel CcShellModel;
typedef struct _CcShellModelClass CcShellModelClass;
+typedef struct _CcShellModelPrivate CcShellModelPrivate;
typedef enum {
CC_CATEGORY_PERSONAL,
@@ -76,6 +77,8 @@ enum
struct _CcShellModel
{
GtkListStore parent;
+
+ CcShellModelPrivate *priv;
};
struct _CcShellModelClass
@@ -96,6 +99,9 @@ gboolean cc_shell_model_iter_matches_search (CcShellModel *model,
GtkTreeIter *iter,
const char *term);
+void cc_shell_model_set_sort_terms (CcShellModel *model,
+ gchar **terms);
+
G_END_DECLS
#endif /* _CC_SHELL_MODEL_H */
diff --git a/shell/cc-window.c b/shell/cc-window.c
index d091e79..8da4645 100644
--- a/shell/cc-window.c
+++ b/shell/cc-window.c
@@ -621,6 +621,8 @@ search_entry_changed_cb (GtkEntry *entry,
g_strfreev (priv->filter_terms);
priv->filter_terms = g_strsplit (priv->filter_string, " ", -1);
+ cc_shell_model_set_sort_terms (CC_SHELL_MODEL (priv->store), priv->filter_terms);
+
if (!g_strcmp0 (priv->filter_string, ""))
{
shell_show_overview_page (center);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]