Compare commits

...

1 Commits

Author SHA1 Message Date
Matthias Clasen
cc58b0e204 A quick attampt at using fuzzy search in the icon browser
This is using the fuzzy search code from libdazzle.
2017-06-03 00:20:46 -04:00
4 changed files with 180 additions and 6 deletions

View File

@@ -21,6 +21,11 @@ gtk3_icon_browser_SOURCES = \
iconbrowserapp.c iconbrowserapp.h \
iconbrowserwin.c iconbrowserwin.h \
iconstore.c iconstore.h \
fuzzy/dzl-fuzzy-index-builder.c fuzzy/dzl-fuzzy-index-builder.h \
fuzzy/dzl-fuzzy-index.c fuzzy/dzl-fuzzy-index.h \
fuzzy/dzl-fuzzy-util.c fuzzy/dzl-fuzzy-util.h \
fuzzy/dzl-fuzzy-index-cursor.c fuzzy/dzl-fuzzy-index-cursor.h \
fuzzy/dzl-fuzzy-index-match.c fuzzy/dzl-fuzzy-index-match.h \
resources.c
BUILT_SOURCES = \
@@ -34,7 +39,8 @@ EXTRA_DIST = \
menus.ui \
iconbrowser.gresource.xml \
window.ui \
icon.list
icon.list \
icon.index
# ------------------- MSVC Build Items ----------------
MSVCPROJS = gtk3-icon-browser

View File

@@ -3,6 +3,8 @@
#include "iconbrowserwin.h"
#include "iconstore.h"
#include <gtk/gtk.h>
#include <fuzzy/dzl-fuzzy-index.h>
#include <fuzzy/dzl-fuzzy-index-match.h>
typedef struct
{
@@ -32,6 +34,7 @@ struct _IconBrowserWindow
gboolean symbolic;
GtkWidget *symbolic_radio;
GtkTreeModelFilter *filter_model;
GtkTreeModelSort *sort_model;
GtkWidget *details;
GtkListStore *store;
@@ -47,6 +50,9 @@ struct _IconBrowserWindow
GtkWidget *image4;
GtkWidget *image5;
GtkWidget *description;
DzlFuzzyIndex *index;
GHashTable *visible;
};
struct _IconBrowserWindowClass
@@ -56,6 +62,31 @@ struct _IconBrowserWindowClass
G_DEFINE_TYPE(IconBrowserWindow, icon_browser_window, GTK_TYPE_APPLICATION_WINDOW);
static void
query_cb (GObject *object,
GAsyncResult *result,
gpointer data)
{
IconBrowserWindow *win = data;
GListModel *model;
GError *error = NULL;
int i;
model = dzl_fuzzy_index_query_finish (win->index, result, &error);
g_print ("%d matches found.\n", g_list_model_get_n_items (model));
g_hash_table_remove_all (win->visible);
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
DzlFuzzyIndexMatch *match = g_list_model_get_item (model, i);
GVariant *document = dzl_fuzzy_index_match_get_document (match);
char *str = g_variant_dup_string (document, NULL);
g_hash_table_insert (win->visible, str, GINT_TO_POINTER (i + 1));
}
g_object_unref (model);
gtk_tree_model_filter_refilter (win->filter_model);
}
static void
search_text_changed (GtkEntry *entry, IconBrowserWindow *win)
{
@@ -66,7 +97,7 @@ search_text_changed (GtkEntry *entry, IconBrowserWindow *win)
if (text[0] == '\0')
return;
gtk_tree_model_filter_refilter (win->filter_model);
dzl_fuzzy_index_query_async (win->index, text, 0, NULL, query_cb, win);
}
static GdkPixbuf *
@@ -301,11 +332,9 @@ icon_visible_func (GtkTreeModel *model,
gchar *name;
gint column;
gboolean search;
const gchar *search_text;
gboolean visible;
search = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (win->search));
search_text = gtk_entry_get_text (GTK_ENTRY (win->searchentry));
if (win->symbolic)
column = ICON_STORE_SYMBOLIC_NAME_COLUMN;
@@ -319,7 +348,7 @@ icon_visible_func (GtkTreeModel *model,
if (!name)
visible = FALSE;
else if (search)
visible = strstr (name, search_text) != NULL;
visible = g_hash_table_lookup (win->visible, name) != NULL;
else
visible = win->current_context != NULL && g_strcmp0 (context, win->current_context->id) == 0;
@@ -355,6 +384,8 @@ search_mode_toggled (GObject *searchbar, GParamSpec *pspec, IconBrowserWindow *w
{
if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (searchbar)))
gtk_list_box_unselect_all (GTK_LIST_BOX (win->context_list));
gtk_tree_model_filter_refilter (win->filter_model);
}
static void
@@ -391,12 +422,56 @@ setup_image_dnd (GtkWidget *image)
g_signal_connect (parent, "drag-data-get", G_CALLBACK (get_image_data), NULL);
}
static gint
sort_func (GtkTreeModel *model,
GtkTreeIter *a,
GtkTreeIter *b,
gpointer data)
{
IconBrowserWindow *win = data;
char *aname = NULL;
char *bname = NULL;
int column;
int apos, bpos;
gboolean search;
int ret;
search = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (win->search));
if (win->symbolic)
column = ICON_STORE_SYMBOLIC_NAME_COLUMN;
else
column = ICON_STORE_NAME_COLUMN;
gtk_tree_model_get (model, a, column, &aname, -1);
gtk_tree_model_get (model, b, column, &bname, -1);
if (!aname || !bname)
ret = 0;
else if (search)
{
apos = GPOINTER_TO_INT (g_hash_table_lookup (win->visible, aname));
bpos = GPOINTER_TO_INT (g_hash_table_lookup (win->visible, bname));
ret = apos - bpos;
}
else
ret = strcmp (aname, bname);
g_free (aname);
g_free (bname);
return ret;
}
static void
icon_browser_window_init (IconBrowserWindow *win)
{
GtkTargetList *list;
GtkTargetEntry *targets;
gint n_targets;
GFile *file;
GError *error = NULL;
gtk_widget_init_template (GTK_WIDGET (win));
@@ -421,6 +496,7 @@ icon_browser_window_init (IconBrowserWindow *win)
win->contexts = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, context_free);
gtk_tree_model_filter_set_visible_func (win->filter_model, icon_visible_func, win, NULL);
gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (win->sort_model), sort_func, win, NULL);
gtk_window_set_transient_for (GTK_WINDOW (win->details), GTK_WINDOW (win));
g_signal_connect (win->searchbar, "notify::search-mode-enabled",
@@ -429,6 +505,18 @@ icon_browser_window_init (IconBrowserWindow *win)
symbolic_toggled (GTK_TOGGLE_BUTTON (win->symbolic_radio), win);
populate (win);
win->index = dzl_fuzzy_index_new ();
file = g_file_new_for_path ("icon.index");
if (!dzl_fuzzy_index_load_file (win->index, file, NULL, &error))
{
g_printerr ("Failed to load index: %s\n", error->message);
g_error_free (error);
}
g_object_unref (file);
win->visible = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
static void
@@ -441,6 +529,7 @@ icon_browser_window_class_init (IconBrowserWindowClass *class)
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, context_list);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, filter_model);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, sort_model);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, symbolic_radio);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, details);

View File

@@ -1,8 +1,84 @@
#include <string.h>
#include <gtk/gtk.h>
#include <iconbrowserapp.h>
#include <fuzzy/dzl-fuzzy-index-builder.h>
static void
build_fuzzy_index (void)
{
DzlFuzzyIndexBuilder *builder;
GFile *file;
GKeyFile *kf;
char *data;
gsize length;
char **groups;
int i;
GFile *outfile;
GError *error = NULL;
builder = dzl_fuzzy_index_builder_new ();
dzl_fuzzy_index_builder_set_case_sensitive (builder, FALSE);
file = g_file_new_for_uri ("resource:/org/gtk/iconbrowser/gtk/icon.list");
g_file_load_contents (file, NULL, &data, &length, NULL, NULL);
kf = g_key_file_new ();
g_key_file_load_from_data (kf, data, length, G_KEY_FILE_NONE, NULL);
groups = g_key_file_get_groups (kf, &length);
for (i = 0; i < length; i++)
{
const char *context;
char **keys;
gsize len;
int j;
context = groups[i];
keys = g_key_file_get_keys (kf, context, &len, NULL);
for (j = 0; j < len; j++)
{
const char *key = keys[j];
char *symbolic;
if (strcmp (key, "Name") == 0 || strcmp (key, "Description") == 0)
continue;
dzl_fuzzy_index_builder_insert (builder, key, g_variant_new_string (key));
symbolic = g_strconcat (key, "-symbolic", NULL);
dzl_fuzzy_index_builder_insert (builder, symbolic, g_variant_new_string (symbolic));
g_free (symbolic);
}
g_strfreev (keys);
}
g_strfreev (groups);
outfile = g_file_new_for_path ("icon.index");
if (!dzl_fuzzy_index_builder_write (builder, outfile, G_PRIORITY_DEFAULT, NULL, &error))
{
g_printerr ("%s\n", error->message);
g_error_free (error);
}
else
{
g_print ("icon.index written\n");
}
g_object_unref (builder);
}
int
main (int argc, char *argv[])
{
if (argc == 2 && strcmp (argv[1], "--generate-index") == 0)
{
build_fuzzy_index ();
return 0;
}
return g_application_run (G_APPLICATION (icon_browser_app_new ()), argc, argv);
}

View File

@@ -3,8 +3,11 @@
<!-- interface-requires gtk+ 3.8 -->
<object class="IconStore" id="store">
</object>
<object class="GtkTreeModelSort" id="sort_model">
<property name="model">store</property>
</object>
<object class="GtkTreeModelFilter" id="filter_model">
<property name="child_model">store</property>
<property name="child_model">sort_model</property>
</object>
<template class="IconBrowserWindow" parent="GtkApplicationWindow">
<property name="title" translatable="yes">Icon Browser</property>