[recipes] Redo search APIs
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [recipes] Redo search APIs
- Date: Sun, 1 Jan 2017 16:06:11 +0000 (UTC)
commit c9eca5222ca32ff17545424832a588ad7fe61061
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Dec 31 15:57:36 2016 -0500
Redo search APIs
We were passing around a string an splitting it in gr_recipe_matches,
which is problematic since it breaks with terms like:
"i+:sunflower seeds"
Instead of inventing some complicated quoting convention, just avoid
joining it into a single string in the first place, as far as possible,
and just pass an array of search terms around.
src/gr-query-editor.c | 67 +++++++++++++++++++++++++------------------
src/gr-query-editor.h | 8 +++--
src/gr-recipe-store.c | 76 ++++++++++++++++++++++++++++++++++++++-----------
src/gr-recipe-store.h | 10 ++++--
src/gr-recipe.c | 9 ++----
src/gr-recipe.h | 4 +-
src/gr-search-page.c | 13 +++-----
src/gr-search-page.h | 4 +-
src/gr-window.c | 38 +++++++++++++++---------
9 files changed, 144 insertions(+), 85 deletions(-)
---
diff --git a/src/gr-query-editor.c b/src/gr-query-editor.c
index 448de5e..c278384 100644
--- a/src/gr-query-editor.c
+++ b/src/gr-query-editor.c
@@ -50,7 +50,7 @@ struct _GrQueryEditor
GtkWidget *ing_list;
char *ing_term;
- char *query;
+ char **terms;
};
enum
@@ -529,11 +529,20 @@ static void
entry_changed_cb (GtkWidget *entry,
GrQueryEditor *editor)
{
- g_autoptr(GString) s = NULL;
+ const char *text;
g_autoptr(GString) s2 = NULL;
+ g_auto(GStrv) terms = NULL;
+ GPtrArray *a = NULL;
GList *children, *l;
+ int i;
+
+ a = g_ptr_array_new ();
- s = g_string_new (gtk_entry_get_text (GTK_ENTRY (editor->entry)));
+ text = gtk_entry_get_text (GTK_ENTRY (editor->entry));
+ terms = g_strsplit (text, " ", -1);
+
+ for (i = 0; terms[i]; i++)
+ g_ptr_array_add (a, g_strdup (terms[i]));
s2 = g_string_new ("");
@@ -547,10 +556,8 @@ entry_changed_cb (GtkWidget *entry,
continue;
term = gr_meal_row_get_search_term (GR_MEAL_ROW (row));
- if (term) {
- g_string_append_c (s, ' ');
- g_string_append (s, term);
- }
+ if (term)
+ g_ptr_array_add (a, g_strdup (term));
label = gr_meal_row_get_label (GR_MEAL_ROW (row));
if (label) {
@@ -578,10 +585,8 @@ entry_changed_cb (GtkWidget *entry,
continue;
term = gr_diet_row_get_search_term (GR_DIET_ROW (row));
- if (term) {
- g_string_append_c (s, ' ');
- g_string_append (s, term);
- }
+ if (term)
+ g_ptr_array_add (a, g_strdup (term));
label = gr_diet_row_get_label (GR_DIET_ROW (row));
if (label) {
@@ -609,10 +614,8 @@ entry_changed_cb (GtkWidget *entry,
continue;
term = gr_ingredient_row_get_search_term (GR_INGREDIENT_ROW (row));
- if (term) {
- g_string_append_c (s, ' ');
- g_string_append (s, term);
- }
+ if (term)
+ g_ptr_array_add (a, g_strdup (term));
label = gr_ingredient_row_get_label (GR_INGREDIENT_ROW (row));
if (label) {
@@ -628,10 +631,12 @@ entry_changed_cb (GtkWidget *entry,
gtk_label_set_label (GTK_LABEL (editor->ing_search_button_label), s2->str);
- g_free (editor->query);
- editor->query = g_strdup (s->str);
+ g_ptr_array_add (a, NULL);
+
+ g_strfreev (editor->terms);
+ editor->terms = (char **)g_ptr_array_free (a, FALSE);
- g_signal_emit (editor, signals[CHANGED], 0, editor->query);
+ g_signal_emit (editor, signals[CHANGED], 0);
}
static void
@@ -646,7 +651,7 @@ gr_query_editor_finalize (GObject *object)
{
GrQueryEditor *self = (GrQueryEditor *)object;
- g_free (self->query);
+ g_strfreev (self->terms);
g_free (self->ing_term);
G_OBJECT_CLASS (gr_query_editor_parent_class)->finalize (object);
@@ -712,7 +717,7 @@ gr_query_editor_class_init (GrQueryEditorClass *klass)
0,
NULL, NULL,
g_cclosure_marshal_generic,
- G_TYPE_NONE, 1, G_TYPE_STRING);
+ G_TYPE_NONE, 0);
signals[CANCEL] =
g_signal_new ("cancel",
@@ -778,10 +783,10 @@ gr_query_editor_init (GrQueryEditor *self)
populate_ingredients_list (self);
}
-char *
-gr_query_editor_get_query (GrQueryEditor *editor)
+const char **
+gr_query_editor_get_terms (GrQueryEditor *editor)
{
- return editor->query;
+ return (const char **)editor->terms;
}
static void
@@ -893,15 +898,22 @@ gr_query_editor_set_query (GrQueryEditor *editor,
const char *query)
{
g_auto(GStrv) terms = NULL;
- int i;
-
- g_signal_handlers_block_by_func (editor->entry, entry_changed_cb, editor);
terms = g_strsplit (query, " ", -1);
+ gr_query_editor_set_terms (editor, (const char **)terms);
+}
+
+void
+gr_query_editor_set_terms (GrQueryEditor *editor,
+ const char **terms)
+{
+ int i;
clear_tags (editor);
- for (i = 0; i < g_strv_length (terms); i++) {
+ g_signal_handlers_block_by_func (editor->entry, entry_changed_cb, editor);
+
+ for (i = 0; terms[i]; i++) {
if (g_str_has_prefix (terms[i], "i+:")) {
set_ingredient_tag (editor, terms[i] + 3, TRUE, FALSE);
}
@@ -920,7 +932,6 @@ gr_query_editor_set_query (GrQueryEditor *editor,
}
gtk_editable_set_position (GTK_EDITABLE (editor->entry), -1);
-
g_signal_handlers_unblock_by_func (editor->entry, entry_changed_cb, editor);
g_signal_emit_by_name (editor->entry, "search-changed", 0);
diff --git a/src/gr-query-editor.h b/src/gr-query-editor.h
index 0934c36..9782229 100644
--- a/src/gr-query-editor.h
+++ b/src/gr-query-editor.h
@@ -30,9 +30,11 @@ G_DECLARE_FINAL_TYPE (GrQueryEditor, gr_query_editor, GR, QUERY_EDITOR, GtkSearc
GrQueryEditor *gr_query_editor_new (void);
-char * gr_query_editor_get_query (GrQueryEditor *editor);
-void gr_query_editor_set_query (GrQueryEditor *editor,
- const char *query);
+void gr_query_editor_set_query (GrQueryEditor *editor,
+ const char *query);
+const char ** gr_query_editor_get_terms (GrQueryEditor *editor);
+void gr_query_editor_set_terms (GrQueryEditor *editor,
+ const char **query);
gboolean gr_query_editor_handle_event (GrQueryEditor *editor,
GdkEvent *event);
diff --git a/src/gr-recipe-store.c b/src/gr-recipe-store.c
index e0d6d7b..c092671 100644
--- a/src/gr-recipe-store.c
+++ b/src/gr-recipe-store.c
@@ -1413,7 +1413,7 @@ struct _GrRecipeSearch
GrRecipeStore *store;
- char *query;
+ char **query;
gulong idle;
GHashTableIter iter;
@@ -1483,10 +1483,10 @@ static gboolean
recipe_matches (GrRecipeSearch *search,
GrRecipe *recipe)
{
- if (strcmp (search->query, "is:favorite") == 0)
+ if (strcmp (search->query[0], "is:favorite") == 0)
return gr_recipe_store_is_favorite (search->store, recipe);
else
- return gr_recipe_matches (recipe, search->query);
+ return gr_recipe_matches (recipe, (const char **)search->query);
}
static gboolean
@@ -1584,36 +1584,78 @@ refilter_existing_results (GrRecipeSearch *search)
}
static gboolean
-query_is_narrowing (GrRecipeSearch *search,
- const char *query)
+query_is_narrowing (GrRecipeSearch *search,
+ const char **query)
{
- /* FIXME: can be more precise */
- return search->query && g_str_has_prefix (query, search->query);
+ int i, j;
+
+ /* Being narrower means having more conditions */
+ if (search->query == NULL)
+ return FALSE;
+
+ for (i = 0; search->query[i]; i++) {
+ const char *term = search->query[i];
+
+ if (g_str_has_prefix (term, "i+:") ||
+ g_str_has_prefix (term, "i-:") ||
+ g_str_has_prefix (term, "by:") ||
+ g_str_has_prefix (term, "se:") ||
+ g_str_has_prefix (term, "me:") ||
+ g_str_has_prefix (term, "di:")) {
+ if (!g_strv_contains (query, term))
+ return FALSE;
+ }
+ else {
+ gboolean res = FALSE;
+ for (j = 0; query[j]; j++) {
+ if (g_str_has_prefix (query[j], term)) {
+ res = TRUE;
+ break;
+ }
+ }
+ if (!res)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
}
void
gr_recipe_search_stop (GrRecipeSearch *search)
{
stop_search (search);
- g_clear_pointer (&search->query, g_free);
+ g_clear_pointer (&search->query, g_strfreev);
}
void
gr_recipe_search_set_query (GrRecipeSearch *search,
const char *query)
{
+ g_auto(GStrv) strv = NULL;
+
+ if (query)
+ strv = g_strsplit (query, " ", -1);
+
+ gr_recipe_search_set_terms (search, (const char **)strv);
+}
+
+void
+gr_recipe_search_set_terms (GrRecipeSearch *search,
+ const char **terms)
+{
gboolean narrowing;
- if (query == NULL) {
+ if (terms == NULL) {
stop_search (search);
- g_clear_pointer (&search->query, g_free);
+ g_clear_pointer (&search->query, g_strfreev);
return;
}
- narrowing = query_is_narrowing (search, query);
+ narrowing = query_is_narrowing (search, terms);
- g_free (search->query);
- search->query = g_strdup (query);
+ g_strfreev (search->query);
+ search->query = g_strdupv ((char **)terms);
if (narrowing) {
refilter_existing_results (search);
@@ -1624,10 +1666,10 @@ gr_recipe_search_set_query (GrRecipeSearch *search,
}
}
-const char *
-gr_recipe_search_get_query (GrRecipeSearch *search)
+const char **
+gr_recipe_search_get_terms (GrRecipeSearch *search)
{
- return search->query;
+ return (const char **)search->query;
}
static void
@@ -1636,7 +1678,7 @@ gr_recipe_search_finalize (GObject *object)
GrRecipeSearch *search = (GrRecipeSearch *)object;
stop_search (search);
- g_free (search->query);
+ g_strfreev (search->query);
g_object_unref (search->store);
G_OBJECT_CLASS (gr_recipe_search_parent_class)->finalize (object);
diff --git a/src/gr-recipe-store.h b/src/gr-recipe-store.h
index ccdc6c8..eb9dc24 100644
--- a/src/gr-recipe-store.h
+++ b/src/gr-recipe-store.h
@@ -87,9 +87,11 @@ G_DECLARE_FINAL_TYPE (GrRecipeSearch, gr_recipe_search, GR, RECIPE_SEARCH, GObje
GrRecipeSearch *gr_recipe_search_new (void);
-void gr_recipe_search_set_query (GrRecipeSearch *search,
- const char *query);
-const char * gr_recipe_search_get_query (GrRecipeSearch *search);
-void gr_recipe_search_stop (GrRecipeSearch *search);
+void gr_recipe_search_set_query (GrRecipeSearch *search,
+ const char *query);
+void gr_recipe_search_set_terms (GrRecipeSearch *search,
+ const char **query);
+const char ** gr_recipe_search_get_terms (GrRecipeSearch *search);
+void gr_recipe_search_stop (GrRecipeSearch *search);
G_END_DECLS
diff --git a/src/gr-recipe.c b/src/gr-recipe.c
index c8b3cad..88dd918 100644
--- a/src/gr-recipe.c
+++ b/src/gr-recipe.c
@@ -636,16 +636,13 @@ gr_recipe_is_readonly (GrRecipe *recipe)
return recipe->readonly;
}
-/* term is assumed to be g_utf8_casefold'ed where appropriate */
+/* terms are assumed to be g_utf8_casefold'ed where appropriate */
gboolean
-gr_recipe_matches (GrRecipe *recipe,
- const char *term)
+gr_recipe_matches (GrRecipe *recipe,
+ const char **terms)
{
- g_auto(GStrv) terms = NULL;
int i;
- terms = g_strsplit (term, " ", -1);
-
for (i = 0; terms[i]; i++) {
if (g_str_has_prefix (terms[i], "i+:")) {
if (!recipe->cf_ingredients || strstr (recipe->cf_ingredients, terms[i] + 3) ==
NULL) {
diff --git a/src/gr-recipe.h b/src/gr-recipe.h
index debfd06..56509b2 100644
--- a/src/gr-recipe.h
+++ b/src/gr-recipe.h
@@ -52,7 +52,7 @@ GDateTime *gr_recipe_get_ctime (GrRecipe *recipe);
GDateTime *gr_recipe_get_mtime (GrRecipe *recipe);
gboolean gr_recipe_is_readonly (GrRecipe *recipe);
-gboolean gr_recipe_matches (GrRecipe *recipe,
- const char *term);
+gboolean gr_recipe_matches (GrRecipe *recipe,
+ const char **terms);
G_END_DECLS
diff --git a/src/gr-search-page.c b/src/gr-search-page.c
index 75109c8..80a72b4 100644
--- a/src/gr-search-page.c
+++ b/src/gr-search-page.c
@@ -177,26 +177,23 @@ check_match (GtkWidget *child,
#endif
void
-gr_search_page_update_search (GrSearchPage *page,
- const char *term)
+gr_search_page_update_search (GrSearchPage *page,
+ const char **terms)
{
- g_autofree char *cf_term = NULL;
-
gtk_stack_set_visible_child_name (GTK_STACK (page->search_stack), "list");
- if (term == NULL || strlen (term) < 1) {
+ if (terms == NULL || terms[0] == NULL) {
container_remove_all (GTK_CONTAINER (page->flow_box));
return;
}
- cf_term = g_utf8_casefold (term, -1);
- gr_recipe_search_set_query (page->search, cf_term);
+ gr_recipe_search_set_terms (page->search, terms);
}
static void
search_page_reload (GrSearchPage *page)
{
- gr_search_page_update_search (page, gr_recipe_search_get_query (page->search));
+ gr_search_page_update_search (page, gr_recipe_search_get_terms (page->search));
}
static void
diff --git a/src/gr-search-page.h b/src/gr-search-page.h
index 0fc4dc8..49d866c 100644
--- a/src/gr-search-page.h
+++ b/src/gr-search-page.h
@@ -29,7 +29,7 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GrSearchPage, gr_search_page, GR, SEARCH_PAGE, GtkBox)
GtkWidget *gr_search_page_new (void);
-void gr_search_page_update_search (GrSearchPage *self,
- const char *term);
+void gr_search_page_update_search (GrSearchPage *self,
+ const char **terms);
G_END_DECLS
diff --git a/src/gr-window.c b/src/gr-window.c
index f9fa2c7..dab182a 100644
--- a/src/gr-window.c
+++ b/src/gr-window.c
@@ -67,12 +67,12 @@ G_DEFINE_TYPE (GrWindow, gr_window, GTK_TYPE_APPLICATION_WINDOW)
typedef struct
{
- gchar *page;
- gchar *header_start_child;
- gchar *header_title_child;
- gchar *header_end_child;
- gchar *header_title;
- gchar *search;
+ char *page;
+ char *header_start_child;
+ char *header_title_child;
+ char *header_end_child;
+ char *header_title;
+ char **search;
} BackEntry;
static void
@@ -83,7 +83,7 @@ back_entry_free (BackEntry *entry)
g_free (entry->header_title_child);
g_free (entry->header_end_child);
g_free (entry->header_title);
- g_free (entry->search);
+ g_strfreev (entry->search);
g_free (entry);
}
@@ -105,7 +105,7 @@ save_back_entry (GrWindow *window)
entry->header_title = g_strdup (gtk_header_bar_get_title (GTK_HEADER_BAR (window->header)));
if (strcmp (entry->page, "search") == 0)
- entry->search = g_strdup (gr_query_editor_get_query (GR_QUERY_EDITOR (window->search_bar)));
+ entry->search = g_strdupv ((char **)gr_query_editor_get_terms (GR_QUERY_EDITOR
(window->search_bar)));
else
entry->search = NULL;
@@ -131,7 +131,7 @@ go_back (GrWindow *window)
if (strcmp (entry->page, "search") == 0) {
gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (window->search_bar), TRUE);
- gr_query_editor_set_query (GR_QUERY_EDITOR (window->search_bar), entry->search);
+ gr_query_editor_set_terms (GR_QUERY_EDITOR (window->search_bar), (const char
**)entry->search);
}
else {
gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (window->search_bar), FALSE);
@@ -188,9 +188,13 @@ void
gr_window_show_search (GrWindow *window,
const char *search)
{
+ g_auto(GStrv) terms = NULL;
+
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (window->search_button), TRUE);
switch_to_search (window);
- gr_query_editor_set_query (GR_QUERY_EDITOR (window->search_bar), search);
+ terms = g_new0 (char *, 2);
+ terms[0] = g_strdup (search);
+ gr_query_editor_set_terms (GR_QUERY_EDITOR (window->search_bar), (const char **)terms);
}
static void search_changed (GrWindow *window);
@@ -224,14 +228,14 @@ static void
search_changed (GrWindow *window)
{
const char *visible;
- const char *terms;
+ const char **terms;
visible = gtk_stack_get_visible_child_name (GTK_STACK (window->main_stack));
if (strcmp (visible, "search") != 0)
switch_to_search (window);
- terms = gr_query_editor_get_query (GR_QUERY_EDITOR (window->search_bar));
+ terms = gr_query_editor_get_terms (GR_QUERY_EDITOR (window->search_bar));
gr_search_page_update_search (GR_SEARCH_PAGE (window->search_page), terms);
}
@@ -612,10 +616,14 @@ void
gr_window_show_search_by_ingredients (GrWindow *window,
const char *ingredient)
{
- g_autofree char *term = NULL;
+ g_auto(GStrv) terms = NULL;
switch_to_search (window);
gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (window->search_bar), TRUE);
- term = g_strconcat ("i+:", ingredient, NULL);
- gr_query_editor_set_query (GR_QUERY_EDITOR (window->search_bar), term);
+
+ terms = g_new (char *, 2);
+ terms[0] = g_strconcat ("i+:", ingredient, NULL);
+ terms[1] = NULL;
+
+ gr_query_editor_set_terms (GR_QUERY_EDITOR (window->search_bar), (const char **)terms);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]