[gnome-control-center] shell: Use CcShellMode to do the panels filtering
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center] shell: Use CcShellMode to do the panels filtering
- Date: Tue, 15 Jan 2013 11:17:38 +0000 (UTC)
commit eb3dfe9b77a3139acda58fde048c0c7af66f7b95
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Tue Jan 15 11:37:24 2013 +0100
shell: Use CcShellMode to do the panels filtering
https://bugzilla.gnome.org/show_bug.cgi?id=690577
shell/Makefile.am | 2 +
shell/cc-shell-category-view.c | 3 +-
shell/cc-shell-item-view.c | 9 +--
shell/cc-shell-model.c | 151 ++++++++++++++++++---------------------
shell/cc-shell-model.h | 9 ++-
shell/cc-util.c | 105 ++++++++++++++++++++++++++++
shell/cc-util.h | 28 ++++++++
shell/gnome-control-center.c | 58 ++-------------
8 files changed, 225 insertions(+), 140 deletions(-)
---
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 75454e3..f2eae95 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -33,6 +33,8 @@ gnome_control_center_SOURCES = \
cc-panel.h \
cc-shell.c \
cc-shell.h \
+ cc-util.c \
+ cc-util.h \
hostname-helper.c \
hostname-helper.h \
cc-hostname-entry.c \
diff --git a/shell/cc-shell-category-view.c b/shell/cc-shell-category-view.c
index edf87ef..c924bd0 100644
--- a/shell/cc-shell-category-view.c
+++ b/shell/cc-shell-category-view.c
@@ -129,11 +129,12 @@ cc_shell_category_view_constructed (GObject *object)
renderer = gtk_cell_renderer_pixbuf_new ();
g_object_set (renderer,
"follow-state", TRUE,
+ "stock-size", GTK_ICON_SIZE_DIALOG,
NULL);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (iconview),
renderer, FALSE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (iconview), renderer,
- "pixbuf", COL_PIXBUF);
+ "gicon", COL_GICON);
gtk_icon_view_set_text_column (GTK_ICON_VIEW (iconview), COL_NAME);
gtk_icon_view_set_item_width (GTK_ICON_VIEW (iconview), 100);
diff --git a/shell/cc-shell-item-view.c b/shell/cc-shell-item-view.c
index 4b41d4c..cc8ae98 100644
--- a/shell/cc-shell-item-view.c
+++ b/shell/cc-shell-item-view.c
@@ -123,7 +123,7 @@ iconview_item_activated_cb (GtkIconView *icon_view,
{
GtkTreeModel *model;
GtkTreeIter iter;
- gchar *name, *desktop_file, *id;
+ gchar *name, *id;
model = gtk_icon_view_get_model (icon_view);
@@ -135,14 +135,12 @@ iconview_item_activated_cb (GtkIconView *icon_view,
gtk_tree_model_get (model, &iter,
COL_NAME, &name,
- COL_DESKTOP_FILE, &desktop_file,
COL_ID, &id,
-1);
g_signal_emit (cc_view, signals[DESKTOP_ITEM_ACTIVATED], 0,
- name, id, desktop_file);
+ name, id);
- g_free (desktop_file);
g_free (name);
g_free (id);
}
@@ -187,8 +185,7 @@ cc_shell_item_view_class_init (CcShellItemViewClass *klass)
NULL,
g_cclosure_marshal_generic,
G_TYPE_NONE,
- 3,
- G_TYPE_STRING,
+ 2,
G_TYPE_STRING,
G_TYPE_STRING);
}
diff --git a/shell/cc-shell-model.c b/shell/cc-shell-model.c
index fafd648..2add15e 100644
--- a/shell/cc-shell-model.c
+++ b/shell/cc-shell-model.c
@@ -19,11 +19,13 @@
* Author: Thomas Wood <thos gnome org>
*/
-#include "cc-shell-model.h"
#include <string.h>
#include <gio/gdesktopappinfo.h>
+#include "cc-shell-model.h"
+#include "cc-util.h"
+
#define GNOME_SETTINGS_PANEL_ID_KEY "X-GNOME-Settings-Panel"
#define GNOME_SETTINGS_PANEL_CATEGORY GNOME_SETTINGS_PANEL_ID_KEY
#define GNOME_SETTINGS_PANEL_ID_KEYWORDS "Keywords"
@@ -31,73 +33,6 @@
G_DEFINE_TYPE (CcShellModel, cc_shell_model, GTK_TYPE_LIST_STORE)
-static GdkPixbuf *
-load_pixbuf_for_gicon (GIcon *icon)
-{
- GtkIconTheme *theme;
- GtkIconInfo *icon_info;
- GdkPixbuf *pixbuf = NULL;
- GError *err = NULL;
-
- if (icon == NULL)
- return NULL;
-
- theme = gtk_icon_theme_get_default ();
-
- icon_info = gtk_icon_theme_lookup_by_gicon (theme, icon,
- 48, GTK_ICON_LOOKUP_FORCE_SIZE);
- if (icon_info)
- {
- pixbuf = gtk_icon_info_load_icon (icon_info, &err);
- if (err)
- {
- g_warning ("Could not load icon '%s': %s",
- gtk_icon_info_get_filename (icon_info), err->message);
- g_error_free (err);
- }
-
- gtk_icon_info_free (icon_info);
- }
- else
- {
- char *name;
-
- name = g_icon_to_string (icon);
- g_warning ("Could not find icon '%s'", name);
- g_free (name);
- }
-
- return pixbuf;
-}
-
-static void
-icon_theme_changed (GtkIconTheme *theme,
- CcShellModel *self)
-{
- GtkTreeIter iter;
- GtkTreeModel *model;
- gboolean cont;
-
- model = GTK_TREE_MODEL (self);
- cont = gtk_tree_model_get_iter_first (model, &iter);
- while (cont)
- {
- GdkPixbuf *pixbuf;
- GIcon *icon;
-
- gtk_tree_model_get (model, &iter,
- COL_GICON, &icon,
- -1);
- pixbuf = load_pixbuf_for_gicon (icon);
- g_object_unref (icon);
- gtk_list_store_set (GTK_LIST_STORE (model), &iter,
- COL_PIXBUF, pixbuf,
- -1);
-
- cont = gtk_tree_model_iter_next (model, &iter);
- }
-}
-
static void
cc_shell_model_class_init (CcShellModelClass *klass)
{
@@ -106,17 +41,14 @@ cc_shell_model_class_init (CcShellModelClass *klass)
static void
cc_shell_model_init (CcShellModel *self)
{
- GType types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
- GDK_TYPE_PIXBUF, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_ICON, G_TYPE_STRV};
+ 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};
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_SORT_ASCENDING);
-
- g_signal_connect (G_OBJECT (gtk_icon_theme_get_default ()), "changed",
- G_CALLBACK (icon_theme_changed), self);
}
CcShellModel *
@@ -125,6 +57,24 @@ cc_shell_model_new (void)
return g_object_new (CC_TYPE_SHELL_MODEL, NULL);
}
+static char **
+get_casefolded_keywords (GAppInfo *appinfo)
+{
+ const char * const * keywords;
+ char **casefolded_keywords;
+ int i, n;
+
+ keywords = g_desktop_app_info_get_keywords (G_DESKTOP_APP_INFO (appinfo));
+ n = keywords ? g_strv_length ((char**) keywords) : 0;
+ casefolded_keywords = g_new (char*, n+1);
+
+ for (i = 0; i < n; i++)
+ casefolded_keywords[i] = cc_util_normalize_casefold_and_unaccent (keywords[i]);
+ casefolded_keywords[n] = NULL;
+
+ return casefolded_keywords;
+}
+
void
cc_shell_model_add_item (CcShellModel *model,
CcPanelCategory category,
@@ -133,23 +83,62 @@ cc_shell_model_add_item (CcShellModel *model,
{
GIcon *icon = g_app_info_get_icon (appinfo);
const gchar *name = g_app_info_get_name (appinfo);
- const gchar *desktop = g_desktop_app_info_get_filename (G_DESKTOP_APP_INFO (appinfo));
const gchar *comment = g_app_info_get_description (appinfo);
- GdkPixbuf *pixbuf = NULL;
- const char * const * keywords;
-
- keywords = g_desktop_app_info_get_keywords (G_DESKTOP_APP_INFO (appinfo));
+ char **keywords;
+ char *casefolded_name, *casefolded_description;
- pixbuf = load_pixbuf_for_gicon (icon);
+ casefolded_name = cc_util_normalize_casefold_and_unaccent (name);
+ casefolded_description = cc_util_normalize_casefold_and_unaccent (comment);
+ keywords = get_casefolded_keywords (appinfo);
gtk_list_store_insert_with_values (GTK_LIST_STORE (model), NULL, 0,
COL_NAME, name,
- COL_DESKTOP_FILE, desktop,
+ COL_CASEFOLDED_NAME, casefolded_name,
+ COL_APP, appinfo,
COL_ID, id,
- COL_PIXBUF, pixbuf,
COL_CATEGORY, category,
COL_DESCRIPTION, comment,
+ COL_CASEFOLDED_DESCRIPTION, casefolded_description,
COL_GICON, icon,
COL_KEYWORDS, keywords,
-1);
+
+ g_free (casefolded_name);
+ g_free (casefolded_description);
+ g_strfreev (keywords);
+}
+
+gboolean
+cc_shell_model_iter_matches_search (CcShellModel *model,
+ GtkTreeIter *iter,
+ const char *term)
+{
+ gchar *name, *description;
+ gboolean result;
+ gchar **keywords;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
+ COL_CASEFOLDED_NAME, &name,
+ COL_CASEFOLDED_DESCRIPTION, &description,
+ COL_KEYWORDS, &keywords,
+ -1);
+
+ result = (strstr (name, term) != NULL);
+
+ if (!result && description)
+ result = (strstr (description, term) != NULL);
+
+ if (!result && keywords)
+ {
+ gint i;
+
+ for (i = 0; !result && keywords[i]; i++)
+ result = (strstr (keywords[i], term) == keywords[i]);
+ }
+
+ g_free (name);
+ g_free (description);
+ g_strfreev (keywords);
+
+ return result;
}
diff --git a/shell/cc-shell-model.h b/shell/cc-shell-model.h
index b2e92fd..f92c25f 100644
--- a/shell/cc-shell-model.h
+++ b/shell/cc-shell-model.h
@@ -61,11 +61,12 @@ typedef enum {
enum
{
COL_NAME,
- COL_DESKTOP_FILE,
+ COL_CASEFOLDED_NAME,
+ COL_APP,
COL_ID,
- COL_PIXBUF,
COL_CATEGORY,
COL_DESCRIPTION,
+ COL_CASEFOLDED_DESCRIPTION,
COL_GICON,
COL_KEYWORDS,
@@ -91,6 +92,10 @@ void cc_shell_model_add_item (CcShellModel *model,
GAppInfo *appinfo,
const char *id);
+gboolean cc_shell_model_iter_matches_search (CcShellModel *model,
+ GtkTreeIter *iter,
+ const char *term);
+
G_END_DECLS
#endif /* _CC_SHELL_MODEL_H */
diff --git a/shell/cc-util.c b/shell/cc-util.c
new file mode 100644
index 0000000..e51a9d2
--- /dev/null
+++ b/shell/cc-util.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ * The Control Center is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+
+#include "cc-util.h"
+
+/* Combining diacritical mark?
+ * Basic range: [0x0300,0x036F]
+ * Supplement: [0x1DC0,0x1DFF]
+ * For Symbols: [0x20D0,0x20FF]
+ * Half marks: [0xFE20,0xFE2F]
+ */
+#define IS_CDM_UCS4(c) (((c) >= 0x0300 && (c) <= 0x036F) || \
+ ((c) >= 0x1DC0 && (c) <= 0x1DFF) || \
+ ((c) >= 0x20D0 && (c) <= 0x20FF) || \
+ ((c) >= 0xFE20 && (c) <= 0xFE2F))
+
+/* Copied from tracker/src/libtracker-fts/tracker-parser-glib.c under the GPL
+ * And then from gnome-shell/src/shell-util.c
+ *
+ * Originally written by Aleksander Morgado <aleksander gnu org>
+ */
+char *
+cc_util_normalize_casefold_and_unaccent (const char *str)
+{
+ char *normalized, *tmp;
+ int i = 0, j = 0, ilen;
+
+ if (str == NULL)
+ return NULL;
+
+ normalized = g_utf8_normalize (str, -1, G_NORMALIZE_NFKD);
+ tmp = g_utf8_casefold (normalized, -1);
+ g_free (normalized);
+
+ ilen = strlen (tmp);
+
+ while (i < ilen)
+ {
+ gunichar unichar;
+ gchar *next_utf8;
+ gint utf8_len;
+
+ /* Get next character of the word as UCS4 */
+ unichar = g_utf8_get_char_validated (&tmp[i], -1);
+
+ /* Invalid UTF-8 character or end of original string. */
+ if (unichar == (gunichar) -1 ||
+ unichar == (gunichar) -2)
+ {
+ break;
+ }
+
+ /* Find next UTF-8 character */
+ next_utf8 = g_utf8_next_char (&tmp[i]);
+ utf8_len = next_utf8 - &tmp[i];
+
+ if (IS_CDM_UCS4 ((guint32) unichar))
+ {
+ /* If the given unichar is a combining diacritical mark,
+ * just update the original index, not the output one */
+ i += utf8_len;
+ continue;
+ }
+
+ /* If already found a previous combining
+ * diacritical mark, indexes are different so
+ * need to copy characters. As output and input
+ * buffers may overlap, need to use memmove
+ * instead of memcpy */
+ if (i != j)
+ {
+ memmove (&tmp[j], &tmp[i], utf8_len);
+ }
+
+ /* Update both indexes */
+ i += utf8_len;
+ j += utf8_len;
+ }
+
+ /* Force proper string end */
+ tmp[j] = '\0';
+
+ return tmp;
+}
diff --git a/shell/cc-util.h b/shell/cc-util.h
new file mode 100644
index 0000000..42b09ff
--- /dev/null
+++ b/shell/cc-util.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ * The Control Center is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+
+#ifndef _CC_UTIL_H
+#define _CC_UTIL_H
+
+#include <glib.h>
+
+char *cc_util_normalize_casefold_and_unaccent (const char *str);
+
+#endif
diff --git a/shell/gnome-control-center.c b/shell/gnome-control-center.c
index 0f1a675..145b0b9 100644
--- a/shell/gnome-control-center.c
+++ b/shell/gnome-control-center.c
@@ -40,6 +40,7 @@
#include "cc-shell-category-view.h"
#include "cc-shell-model.h"
#include "cc-panel-loader.h"
+#include "cc-util.h"
G_DEFINE_TYPE (GnomeControlCenter, gnome_control_center, CC_TYPE_SHELL)
@@ -176,7 +177,6 @@ static gboolean
activate_panel (GnomeControlCenter *shell,
const gchar *id,
const gchar **argv,
- const gchar *desktop_file,
const gchar *name,
GIcon *gicon)
{
@@ -184,8 +184,6 @@ activate_panel (GnomeControlCenter *shell,
GtkWidget *box;
const gchar *icon_name;
- if (!desktop_file)
- return FALSE;
if (!id)
return FALSE;
@@ -580,47 +578,12 @@ model_filter_func (GtkTreeModel *model,
GtkTreeIter *iter,
GnomeControlCenterPrivate *priv)
{
- gchar *name;
- gchar *needle, *haystack;
- gboolean result;
- gchar **keywords;
-
- gtk_tree_model_get (model, iter,
- COL_NAME, &name,
- COL_KEYWORDS, &keywords,
- -1);
-
- if (!priv->filter_string || !name)
- {
- g_free (name);
- g_strfreev (keywords);
- return FALSE;
- }
-
- needle = g_utf8_casefold (priv->filter_string, -1);
- haystack = g_utf8_casefold (name, -1);
-
- result = (strstr (haystack, needle) != NULL);
-
- if (!result && keywords)
- {
- gint i;
- gchar *keyword;
-
- for (i = 0; !result && keywords[i]; i++)
- {
- keyword = g_utf8_casefold (keywords[i], -1);
- result = strstr (keyword, needle) == keyword;
- g_free (keyword);
- }
- }
-
- g_free (name);
- g_free (haystack);
- g_free (needle);
- g_strfreev (keywords);
+ if (!priv->filter_string)
+ return FALSE;
- return result;
+ return cc_shell_model_iter_matches_search (CC_SHELL_MODEL (model),
+ iter,
+ priv->filter_string);
}
static gboolean
@@ -647,7 +610,7 @@ search_entry_changed_cb (GtkEntry *entry,
return;
/* Don't re-filter for added trailing or leading spaces */
- str = g_strdup (gtk_entry_get_text (entry));
+ str = cc_util_normalize_casefold_and_unaccent (gtk_entry_get_text (entry));
g_strstrip (str);
if (!g_strcmp0 (str, priv->filter_string))
{
@@ -991,7 +954,6 @@ _shell_set_active_panel_from_id (CcShell *shell,
GtkTreeIter iter;
gboolean iter_valid;
gchar *name = NULL;
- gchar *desktop = NULL;
GIcon *gicon = NULL;
GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv;
GtkWidget *old_panel;
@@ -1016,7 +978,6 @@ _shell_set_active_panel_from_id (CcShell *shell,
gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
COL_NAME, &name,
- COL_DESKTOP_FILE, &desktop,
COL_GICON, &gicon,
COL_ID, &id,
-1);
@@ -1030,13 +991,11 @@ _shell_set_active_panel_from_id (CcShell *shell,
{
g_free (id);
g_free (name);
- g_free (desktop);
if (gicon)
g_object_unref (gicon);
name = NULL;
id = NULL;
- desktop = NULL;
gicon = NULL;
}
@@ -1050,7 +1009,7 @@ _shell_set_active_panel_from_id (CcShell *shell,
{
g_warning ("Could not find settings panel \"%s\"", start_id);
}
- else if (activate_panel (GNOME_CONTROL_CENTER (shell), start_id, argv, desktop,
+ else if (activate_panel (GNOME_CONTROL_CENTER (shell), start_id, argv,
name, gicon) == FALSE)
{
/* Failed to activate the panel for some reason,
@@ -1067,7 +1026,6 @@ _shell_set_active_panel_from_id (CcShell *shell,
}
g_free (name);
- g_free (desktop);
if (gicon)
g_object_unref (gicon);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]