[recipes] Redo search APIs



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]