core/filter: filter_search() returns a new GHashTable
I think this is cleaner than having an upper layer allocate the results set manually. This also lets me return NULL in the case that there were no results. Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
parent
fda3f761a0
commit
93fb40360d
|
@ -7,14 +7,19 @@
|
||||||
static GHashTable *filter_index = NULL;
|
static GHashTable *filter_index = NULL;
|
||||||
|
|
||||||
|
|
||||||
void __filter_copy(GHashTable *lhs, GHashTable *rhs)
|
GHashTable *__filter_copy(GHashTable *set)
|
||||||
{
|
{
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
|
GHashTable *res;
|
||||||
gpointer data;
|
gpointer data;
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, lhs);
|
res = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||||
|
g_hash_table_iter_init(&iter, set);
|
||||||
|
|
||||||
while (g_hash_table_iter_next(&iter, &data, NULL))
|
while (g_hash_table_iter_next(&iter, &data, NULL))
|
||||||
g_hash_table_add(rhs, data);
|
g_hash_table_add(res, data);
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __filter_inline_intersect(GHashTable *lhs, GHashTable *rhs)
|
void __filter_inline_intersect(GHashTable *lhs, GHashTable *rhs)
|
||||||
|
@ -91,14 +96,13 @@ void filter_remove(const gchar *text, void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter_search(const gchar *text, GHashTable *res)
|
GHashTable *filter_search(const gchar *text)
|
||||||
{
|
{
|
||||||
gchar *lower = string_lowercase(text);
|
gchar *lower = string_lowercase(text);
|
||||||
GHashTable *found;
|
GHashTable *found, *res = NULL;
|
||||||
glong begin, end;
|
glong begin, end;
|
||||||
gchar *c, *substr;
|
gchar *c, *substr;
|
||||||
|
|
||||||
g_hash_table_remove_all(res);
|
|
||||||
c = lower;
|
c = lower;
|
||||||
|
|
||||||
for (begin = 0, end = 1; end <= g_utf8_strlen(lower, -1); end++) {
|
for (begin = 0, end = 1; end <= g_utf8_strlen(lower, -1); end++) {
|
||||||
|
@ -111,12 +115,13 @@ void filter_search(const gchar *text, GHashTable *res)
|
||||||
g_free(substr);
|
g_free(substr);
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
g_hash_table_remove_all(res);
|
g_hash_table_destroy(res);
|
||||||
|
res = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (begin == 0)
|
if (!res)
|
||||||
__filter_copy(found, res);
|
res = __filter_copy(found);
|
||||||
else
|
else
|
||||||
__filter_inline_intersect(found, res);
|
__filter_inline_intersect(found, res);
|
||||||
|
|
||||||
|
@ -125,4 +130,5 @@ void filter_search(const gchar *text, GHashTable *res)
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(lower);
|
g_free(lower);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
11
gui/queue.c
11
gui/queue.c
|
@ -68,6 +68,8 @@ static gboolean __queue_visible_func(GtkTreeModel *model, GtkTreeIter *iter,
|
||||||
|
|
||||||
if (!gq_queue || (strlen(gtk_entry_get_text(GTK_ENTRY(data))) == 0))
|
if (!gq_queue || (strlen(gtk_entry_get_text(GTK_ENTRY(data))) == 0))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
if (!gq_queue->gq_visible)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
track = gui_queue_model_iter_get_track(gq_queue->gq_model, iter);
|
track = gui_queue_model_iter_get_track(gq_queue->gq_model, iter);
|
||||||
return g_hash_table_contains(gq_queue->gq_visible, track);
|
return g_hash_table_contains(gq_queue->gq_visible, track);
|
||||||
|
@ -80,9 +82,13 @@ void __queue_filter(GtkSearchEntry *entry, gpointer data)
|
||||||
if (!gq_queue)
|
if (!gq_queue)
|
||||||
return;
|
return;
|
||||||
if (strlen(text) > 0)
|
if (strlen(text) > 0)
|
||||||
filter_search(text, gq_queue->gq_visible);
|
gq_queue->gq_visible = filter_search(text);
|
||||||
|
|
||||||
gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(gq_queue->gq_filter));
|
gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(gq_queue->gq_filter));
|
||||||
gui_view_scroll();
|
gui_view_scroll();
|
||||||
|
|
||||||
|
if (gq_queue->gq_visible)
|
||||||
|
g_hash_table_destroy(gq_queue->gq_visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct gui_queue *gui_queue_alloc(struct queue *queue, const gchar *text,
|
struct gui_queue *gui_queue_alloc(struct queue *queue, const gchar *text,
|
||||||
|
@ -97,7 +103,7 @@ struct gui_queue *gui_queue_alloc(struct queue *queue, const gchar *text,
|
||||||
GTK_TREE_MODEL(gq->gq_model), NULL);
|
GTK_TREE_MODEL(gq->gq_model), NULL);
|
||||||
gq->gq_queue = queue;
|
gq->gq_queue = queue;
|
||||||
|
|
||||||
gq->gq_visible = g_hash_table_new(g_direct_hash, g_direct_equal);
|
gq->gq_visible = NULL;
|
||||||
gtk_tree_model_filter_set_visible_func(
|
gtk_tree_model_filter_set_visible_func(
|
||||||
GTK_TREE_MODEL_FILTER(gq->gq_filter),
|
GTK_TREE_MODEL_FILTER(gq->gq_filter),
|
||||||
__queue_visible_func,
|
__queue_visible_func,
|
||||||
|
@ -110,7 +116,6 @@ void gui_queue_free(struct queue *queue)
|
||||||
{
|
{
|
||||||
struct gui_queue *gq = gui_queue(queue);
|
struct gui_queue *gq = gui_queue(queue);
|
||||||
|
|
||||||
g_hash_table_destroy(gq->gq_visible);
|
|
||||||
queue->q_private = NULL;
|
queue->q_private = NULL;
|
||||||
|
|
||||||
if (gq_queue == gq)
|
if (gq_queue == gq)
|
||||||
|
|
|
@ -21,6 +21,6 @@ void filter_add(const gchar *, void *);
|
||||||
void filter_remove(const gchar *, void *);
|
void filter_remove(const gchar *, void *);
|
||||||
|
|
||||||
/* Search for the input string in the index. */
|
/* Search for the input string in the index. */
|
||||||
void filter_search(const gchar *, GHashTable *);
|
GHashTable *filter_search(const gchar *);
|
||||||
|
|
||||||
#endif /* OCARINA_CORE_FILTER_H */
|
#endif /* OCARINA_CORE_FILTER_H */
|
||||||
|
|
|
@ -25,7 +25,7 @@ const gchar *test_strings[] = {
|
||||||
|
|
||||||
static void test_filter()
|
static void test_filter()
|
||||||
{
|
{
|
||||||
GHashTable *res = g_hash_table_new(g_direct_hash, g_direct_equal);
|
GHashTable *res;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
filter_init();
|
filter_init();
|
||||||
|
@ -34,46 +34,50 @@ static void test_filter()
|
||||||
} test_loop_passed();
|
} test_loop_passed();
|
||||||
|
|
||||||
/* Search for a word! */
|
/* Search for a word! */
|
||||||
filter_search("hyrule", res);
|
res = filter_search("hyrule");
|
||||||
test_equal(g_hash_table_size(res), 3);
|
test_equal(g_hash_table_size(res), 3);
|
||||||
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(1)), true); /* hyrule symphony */
|
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(1)), true); /* hyrule symphony */
|
||||||
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(3)), true); /* hyrule field */
|
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(3)), true); /* hyrule field */
|
||||||
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(4)), true); /* hyrule castle */
|
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(4)), true); /* hyrule castle */
|
||||||
|
g_hash_table_destroy(res);
|
||||||
|
|
||||||
/* A second search should clear the set. */
|
/* A second search should clear the set. */
|
||||||
filter_search("zelda", res);
|
res = filter_search("zelda");
|
||||||
test_equal(g_hash_table_size(res), 2);
|
test_equal(g_hash_table_size(res), 2);
|
||||||
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(11)), true); /* princess zelda */
|
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(11)), true); /* princess zelda */
|
||||||
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(13)), true); /* the legend of zelda medley */
|
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(13)), true); /* the legend of zelda medley */
|
||||||
|
g_hash_table_destroy(res);
|
||||||
|
|
||||||
/* Partial word search. */
|
/* Partial word search. */
|
||||||
filter_search("ko", res);
|
res = filter_search("ko");
|
||||||
test_equal(g_hash_table_size(res), 2);
|
test_equal(g_hash_table_size(res), 2);
|
||||||
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(0)), true); /* koji kondo */
|
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(0)), true); /* koji kondo */
|
||||||
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(2)), true); /* kokiri forest */
|
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(2)), true); /* kokiri forest */
|
||||||
|
g_hash_table_destroy(res);
|
||||||
|
|
||||||
/* Multiple word search. */
|
/* Multiple word search. */
|
||||||
filter_search("hyrule field", res);
|
res = filter_search("hyrule field");
|
||||||
test_equal(g_hash_table_size(res), 1);
|
test_equal(g_hash_table_size(res), 1);
|
||||||
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(3)), true); /* hyrule field */
|
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(3)), true); /* hyrule field */
|
||||||
|
g_hash_table_destroy(res);
|
||||||
|
|
||||||
/* Search for unknown word. */
|
/* Search for unknown word. */
|
||||||
filter_search("field termina", res);
|
res = filter_search("field termina");
|
||||||
test_equal(g_hash_table_size(res), 0);
|
test_equal((void *)res, NULL);
|
||||||
|
|
||||||
/* Search for empty string. */
|
/* Search for empty string. */
|
||||||
filter_search("", res);
|
res = filter_search("");
|
||||||
test_equal(g_hash_table_size(res), 0);
|
test_equal((void *)res, NULL);
|
||||||
|
|
||||||
/* Remove a string and search again. */
|
/* Remove a string and search again. */
|
||||||
filter_remove("hyrule symphony", GUINT_TO_POINTER(1));
|
filter_remove("hyrule symphony", GUINT_TO_POINTER(1));
|
||||||
filter_search("hyrule", res);
|
res = filter_search("hyrule");
|
||||||
test_equal(g_hash_table_size(res), 2);
|
test_equal(g_hash_table_size(res), 2);
|
||||||
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(3)), true); /* hyrule field */
|
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(3)), true); /* hyrule field */
|
||||||
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(4)), true); /* hyrule castle */
|
test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(4)), true); /* hyrule castle */
|
||||||
|
g_hash_table_destroy(res);
|
||||||
|
|
||||||
filter_deinit();
|
filter_deinit();
|
||||||
g_hash_table_destroy(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_UNIT_TESTS(
|
DECLARE_UNIT_TESTS(
|
||||||
|
|
|
@ -126,29 +126,31 @@ static void test_track()
|
||||||
static void test_track_filter()
|
static void test_track_filter()
|
||||||
{
|
{
|
||||||
const struct db_ops *track_ops = test_track_ops();
|
const struct db_ops *track_ops = test_track_ops();
|
||||||
GHashTable *search = g_hash_table_new(g_direct_hash, g_direct_equal);
|
|
||||||
struct track *track;
|
struct track *track;
|
||||||
|
GHashTable *search;
|
||||||
|
|
||||||
track = test_alloc("0/Hyrule Symphony/01 - Title Theme.ogg");
|
track = test_alloc("0/Hyrule Symphony/01 - Title Theme.ogg");
|
||||||
track->tr_dbe.dbe_index = 0;
|
track->tr_dbe.dbe_index = 0;
|
||||||
track_ops->dbe_setup(&track->tr_dbe);
|
track_ops->dbe_setup(&track->tr_dbe);
|
||||||
|
|
||||||
filter_search("Title Theme", search);
|
search = filter_search("Title Theme");
|
||||||
test_equal(g_hash_table_size(search), 1);
|
test_equal(g_hash_table_size(search), 1);
|
||||||
test_equal(g_hash_table_contains(search, track), true);
|
test_equal(g_hash_table_contains(search, track), true);
|
||||||
|
|
||||||
filter_search("Koji Kondo", search);
|
|
||||||
test_equal(g_hash_table_size(search), 1);
|
|
||||||
test_equal(g_hash_table_contains(search, track), true);
|
|
||||||
|
|
||||||
filter_search("Hyrule Symphony", search);
|
|
||||||
test_equal(g_hash_table_size(search), 1);
|
|
||||||
test_equal(g_hash_table_contains(search, track), true);
|
|
||||||
|
|
||||||
filter_search("No Track", search);
|
|
||||||
test_equal(g_hash_table_size(search), 0);
|
|
||||||
|
|
||||||
g_hash_table_destroy(search);
|
g_hash_table_destroy(search);
|
||||||
|
|
||||||
|
search = filter_search("Koji Kondo");
|
||||||
|
test_equal(g_hash_table_size(search), 1);
|
||||||
|
test_equal(g_hash_table_contains(search, track), true);
|
||||||
|
g_hash_table_destroy(search);
|
||||||
|
|
||||||
|
search = filter_search("Hyrule Symphony");
|
||||||
|
test_equal(g_hash_table_size(search), 1);
|
||||||
|
test_equal(g_hash_table_contains(search, track), true);
|
||||||
|
g_hash_table_destroy(search);
|
||||||
|
|
||||||
|
search = filter_search("No Track");
|
||||||
|
test_equal((void *)search, NULL);
|
||||||
|
|
||||||
g_free(track->tr_path);
|
g_free(track->tr_path);
|
||||||
track_ops->dbe_free(&track->tr_dbe);
|
track_ops->dbe_free(&track->tr_dbe);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,10 @@ static void test_queue()
|
||||||
|
|
||||||
gtk_init(&argc, NULL);
|
gtk_init(&argc, NULL);
|
||||||
gui_builder_init("share/ocarina/ocarina6.glade");
|
gui_builder_init("share/ocarina/ocarina6.glade");
|
||||||
|
queue_init(&q, 0, &test_ops);
|
||||||
gui_view_init();
|
gui_view_init();
|
||||||
|
while (idle_run_task()) {};
|
||||||
|
|
||||||
search = GTK_ENTRY(gui_builder_widget("o_search"));
|
search = GTK_ENTRY(gui_builder_widget("o_search"));
|
||||||
enable = GTK_SWITCH(gui_builder_widget("o_enable"));
|
enable = GTK_SWITCH(gui_builder_widget("o_enable"));
|
||||||
random = GTK_TOGGLE_BUTTON(gui_builder_widget("o_random"));
|
random = GTK_TOGGLE_BUTTON(gui_builder_widget("o_random"));
|
||||||
|
@ -60,7 +63,6 @@ static void test_queue()
|
||||||
treeview = GTK_TREE_VIEW(gui_builder_widget("o_treeview"));
|
treeview = GTK_TREE_VIEW(gui_builder_widget("o_treeview"));
|
||||||
|
|
||||||
/* Test initialization */
|
/* Test initialization */
|
||||||
queue_init(&q, 0, &test_ops);
|
|
||||||
gq = gui_queue(&q);
|
gq = gui_queue(&q);
|
||||||
test_equal((void *)gq->gq_queue, (void *)&q);
|
test_equal((void *)gq->gq_queue, (void *)&q);
|
||||||
test_not_equal((void *)gq->gq_model, NULL);
|
test_not_equal((void *)gq->gq_model, NULL);
|
||||||
|
|
Loading…
Reference in New Issue