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
This commit is contained in:
parent
98a2ab2603
commit
13abc75273
4 changed files with 248 additions and 2 deletions
|
@ -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,
|
||||
|
|
|
@ -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 (CcShellModel, cc_shell_model, GTK_TYPE_LIST_STORE)
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue