summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLogan Rathbone <poprocks@gmail.com>2023-02-02 13:57:02 -0500
committerLogan Rathbone <poprocks@gmail.com>2023-02-02 13:57:49 -0500
commit62046d9225d4d3d062a663f1739773cef94918e0 (patch)
tree58e7adb126d6b5e7cfd30fea3af2b79d20112f6b /src
parent956c5c87a76dab65084b01c99764be82fe658681 (diff)
downloadzenity-62046d9225d4d3d062a663f1739773cef94918e0.tar.gz
tree: Add searchability
Diffstat (limited to 'src')
-rw-r--r--src/tree.c14
-rw-r--r--src/zenity-tree-column-view.c181
-rw-r--r--src/zenity-tree-column-view.h2
-rw-r--r--src/zenity.ui11
4 files changed, 190 insertions, 18 deletions
diff --git a/src/tree.c b/src/tree.c
index 754f40a..f4ade82 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -220,11 +220,19 @@ cv_activated_cb (ZenityTreeColumnView *cv, gpointer data)
zenity_util_gapp_quit (parent, zen_data);
}
+static void
+search_changed_cb (GtkSearchEntry *entry, gpointer data)
+{
+ zenity_tree_column_view_set_search (col_view,
+ gtk_editable_get_text (GTK_EDITABLE(entry)));
+}
+
void
zenity_tree (ZenityData *data, ZenityTreeData *tree_data)
{
g_autoptr(GtkBuilder) builder = NULL;
GtkWidget *dialog;
+ GtkWidget *search_entry;
GObject *text;
GListStore *store;
ZenityTreeListType list_type;
@@ -280,7 +288,6 @@ zenity_tree (ZenityData *data, ZenityTreeData *tree_data)
}
dialog = GTK_WIDGET(gtk_builder_get_object (builder, "zenity_tree_dialog"));
-
g_signal_connect (dialog, "response", G_CALLBACK(zenity_tree_dialog_response), data);
if (data->dialog_title)
@@ -327,6 +334,9 @@ zenity_tree (ZenityData *data, ZenityTreeData *tree_data)
*/
g_signal_connect (col_view, "activated", G_CALLBACK(cv_activated_cb), data);
+ search_entry = GTK_WIDGET(gtk_builder_get_object (builder, "zenity_tree_search_entry"));
+ g_signal_connect (search_entry, "search-changed", G_CALLBACK(search_changed_cb), NULL);
+
if (tree_data->radiobox) {
list_type = ZENITY_TREE_LIST_RADIO;
}
@@ -361,8 +371,6 @@ zenity_tree (ZenityData *data, ZenityTreeData *tree_data)
zenity_tree_fill_entries_from_stdin ();
}
- // FIXME - make stuff searchable
-
zenity_util_show_dialog (dialog);
if (data->timeout_delay > 0) {
diff --git a/src/zenity-tree-column-view.c b/src/zenity-tree-column-view.c
index 2e12122..1d810d1 100644
--- a/src/zenity-tree-column-view.c
+++ b/src/zenity-tree-column-view.c
@@ -3,6 +3,17 @@
#define UI_FILE RESOURCE_BASE_PATH "/zenity-tree-column-view.ui"
+/* ZenityTreeItem */
+
+enum zenity_tree_item_prop_enum
+{
+ TEXT = 1,
+ CHILD,
+ N_PROPERTIES_ZENITY_TREE_ITEM
+};
+
+static GParamSpec *zenity_tree_item_properties[N_PROPERTIES_ZENITY_TREE_ITEM];
+
struct _ZenityTreeItem
{
GObject parent_instance;
@@ -13,13 +24,92 @@ struct _ZenityTreeItem
G_DEFINE_TYPE (ZenityTreeItem, zenity_tree_item, G_TYPE_OBJECT)
static void
+zenity_tree_item_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ZenityTreeItem *self = ZENITY_TREE_ITEM(object);
+
+ switch (property_id)
+ {
+ case TEXT:
+ zenity_tree_item_set_text (self, g_value_get_string (value));
+ break;
+
+ case CHILD:
+ zenity_tree_item_set_child (self, GTK_WIDGET(g_value_get_object (value)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+zenity_tree_item_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ZenityTreeItem *self = ZENITY_TREE_ITEM(object);
+
+ switch (property_id)
+ {
+ case TEXT:
+ g_value_set_string (value, zenity_tree_item_get_text (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+static void
zenity_tree_item_init (ZenityTreeItem *item)
{
}
static void
+zenity_tree_item_dispose (GObject *object)
+{
+ ZenityTreeItem *self = ZENITY_TREE_ITEM(object);
+
+ if (g_object_is_floating (self->child))
+ g_warning ("%s: trying to dispose ZenityTreeItem before the widget has been parented. "
+ "Likely a programmer error. A leak will likely result.", __func__);
+ else
+ g_clear_object (&self->child);
+
+ G_OBJECT_CLASS(zenity_tree_item_parent_class)->dispose (object);
+}
+
+static void
+zenity_tree_item_finalize (GObject *object)
+{
+ ZenityTreeItem *self = ZENITY_TREE_ITEM(object);
+
+ g_free (self->text);
+
+ G_OBJECT_CLASS(zenity_tree_item_parent_class)->finalize (object);
+}
+
+static void
zenity_tree_item_class_init (ZenityTreeItemClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GParamFlags flags = G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT;
+
+ object_class->dispose = zenity_tree_item_dispose;
+ object_class->finalize = zenity_tree_item_finalize;
+ object_class->set_property = zenity_tree_item_set_property;
+ object_class->get_property = zenity_tree_item_get_property;
+
+ zenity_tree_item_properties[TEXT] = g_param_spec_string ("text", NULL, NULL, NULL, flags);
+ zenity_tree_item_properties[CHILD] = g_param_spec_object ("child", NULL, NULL, GTK_TYPE_WIDGET, flags);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES_ZENITY_TREE_ITEM, zenity_tree_item_properties);
}
GtkWidget *
@@ -35,10 +125,23 @@ zenity_tree_item_get_text (ZenityTreeItem *item)
}
void
-zenity_tree_item_set_text (ZenityTreeItem *item, const char *text)
+zenity_tree_item_set_text (ZenityTreeItem *self, const char *text)
+{
+ g_clear_pointer (&self->text, g_free);
+ self->text = g_strdup (text);
+
+ g_object_notify_by_pspec (G_OBJECT(self), zenity_tree_item_properties[TEXT]);
+}
+
+void
+zenity_tree_item_set_child (ZenityTreeItem *self, GtkWidget *child)
{
- g_clear_pointer (&item->text, g_free);
- item->text = g_strdup (text);
+ if (self->child)
+ g_object_unref (self->child);
+
+ self->child = g_object_ref (child);
+
+ g_object_notify_by_pspec (G_OBJECT(self), zenity_tree_item_properties[CHILD]);
}
ZenityTreeItem *
@@ -48,15 +151,15 @@ zenity_tree_item_new (const char *text, GtkWidget *child)
g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
- item = g_object_new (ZENITY_TREE_TYPE_ITEM, NULL);
-
- item->child = child;
- zenity_tree_item_set_text (item, text);
+ item = g_object_new (ZENITY_TREE_TYPE_ITEM,
+ "text", text,
+ "child", child,
+ NULL);
return item;
}
-/* --- */
+/* ZenityTreeRow */
struct _ZenityTreeRow
{
@@ -103,7 +206,7 @@ zenity_tree_row_get_item (ZenityTreeRow *row, guint index)
return row->items->pdata[index];
}
-/* --- */
+/* ZenityTreeColumnView */
enum zenity_tree_column_view_signal_enum {
ACTIVATED,
@@ -112,9 +215,7 @@ enum zenity_tree_column_view_signal_enum {
static guint zenity_tree_column_view_signals[LAST_SIGNAL];
-/* --- */
-
-enum zenity_tree_column_view_props
+enum zenity_tree_column_view_prop_enum
{
MULTI = 1,
LIST_TYPE,
@@ -132,25 +233,69 @@ struct _ZenityTreeColumnView
gboolean multi;
ZenityTreeListType list_type;
GListModel *model;
+ GtkStringFilter *filter;
GtkCheckButton *checkbutton_group;
};
G_DEFINE_TYPE (ZenityTreeColumnView, zenity_tree_column_view, GTK_TYPE_WIDGET)
+/* Callback for the GClosure defined below. Just cram the text from all row
+ * items into a single string; that way, if the string in the searchbar matches
+ * any text in a given row, there will be a match, and only those rows will be
+ * shown.
+ */
+static char *
+eval_str (ZenityTreeRow *row)
+{
+ GString *gstring;
+
+ g_return_val_if_fail (ZENITY_TREE_IS_ROW (row), NULL);
+
+ gstring = g_string_new (NULL);
+
+ for (guint i = 0; i < row->items->len; ++i)
+ {
+ ZenityTreeItem *item = row->items->pdata[i];
+ g_string_append_printf (gstring, "%s ", item->text);
+ }
+
+ return g_string_free (gstring, FALSE);
+}
+
void
zenity_tree_column_view_set_model (ZenityTreeColumnView *self, GListModel *model)
{
+ GtkStringFilter *filter;
+ GtkFilterListModel *filter_model;
+
+ GtkExpression *expr;
+
+ /* This tells the column view to use a callback with 'this' (ZenityTreeRow)
+ * as the instance and no other params or user_data, with a string retval.
+ */
+ expr = gtk_cclosure_expression_new (G_TYPE_STRING,
+ NULL, /* GClosureMarshal marshal, */
+ 0, /* guint n_params, */
+ NULL, /* GtkExpression** params, */
+ G_CALLBACK(eval_str), /* GCallback callback_func, */
+ NULL, /* gpointer user_data, */
+ NULL); /* GClosureNotify user_destroy) */
+
+ filter = gtk_string_filter_new (expr);
+ filter_model = gtk_filter_list_model_new (model, GTK_FILTER(filter));
+
self->model = model;
+ self->filter = filter;
if (self->multi)
{
gtk_column_view_set_model (self->child_cv,
- GTK_SELECTION_MODEL(gtk_multi_selection_new (self->model)));
+ GTK_SELECTION_MODEL(gtk_multi_selection_new (G_LIST_MODEL(filter_model))));
}
else
{
gtk_column_view_set_model (self->child_cv,
- GTK_SELECTION_MODEL(gtk_single_selection_new (self->model)));
+ GTK_SELECTION_MODEL(gtk_single_selection_new (G_LIST_MODEL(filter_model))));
}
g_object_notify_by_pspec (G_OBJECT(self), zenity_tree_column_view_properties[MODEL]);
@@ -264,7 +409,7 @@ zenity_tree_column_view_dispose (GObject *object)
g_clear_pointer (&self->scrolled_window, gtk_widget_unparent);
- G_OBJECT_CLASS(zenity_tree_column_view_parent_class)->dispose(object);
+ G_OBJECT_CLASS(zenity_tree_column_view_parent_class)->dispose (object);
}
static void
@@ -476,3 +621,9 @@ zenity_tree_column_view_is_selected (ZenityTreeColumnView *self, guint pos)
{
return gtk_selection_model_is_selected (gtk_column_view_get_model (self->child_cv), pos);
}
+
+void
+zenity_tree_column_view_set_search (ZenityTreeColumnView *self, const char *search_str)
+{
+ gtk_string_filter_set_search (self->filter, search_str);
+}
diff --git a/src/zenity-tree-column-view.h b/src/zenity-tree-column-view.h
index c66e323..3d49a0e 100644
--- a/src/zenity-tree-column-view.h
+++ b/src/zenity-tree-column-view.h
@@ -23,6 +23,7 @@ ZenityTreeItem * zenity_tree_item_new (const char *text, GtkWidget *child);
GtkWidget * zenity_tree_item_get_child (ZenityTreeItem *item);
const char * zenity_tree_item_get_text (ZenityTreeItem *item);
void zenity_tree_item_set_text (ZenityTreeItem *item, const char *text);
+void zenity_tree_item_set_child (ZenityTreeItem *item, GtkWidget *child);
/* ZenityTreeRow */
@@ -50,5 +51,6 @@ int zenity_tree_column_view_get_n_columns (ZenityTreeColumnView *self);
gboolean zenity_tree_column_view_get_editable (ZenityTreeColumnView *self);
gboolean zenity_tree_column_view_get_multi (ZenityTreeColumnView *self);
gboolean zenity_tree_column_view_is_selected (ZenityTreeColumnView *self, guint pos);
+void zenity_tree_column_view_set_search (ZenityTreeColumnView *self, const char *search_str);
G_END_DECLS
diff --git a/src/zenity.ui b/src/zenity.ui
index 1f26eba..e4e6a5b 100644
--- a/src/zenity.ui
+++ b/src/zenity.ui
@@ -388,6 +388,17 @@
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
+ <object class="GtkSearchBar" id="zenity_tree_search_bar">
+ <property name="show-close-button">true</property>
+ <property name="key-capture-widget">zenity_tree_cv</property>
+ <child>
+ <object class="GtkSearchEntry" id="zenity_tree_search_entry">
+ <property name="hexpand">true</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
<object class="GtkLabel" id="zenity_tree_text">
<property name="valign">center</property>
<property name="label" translatable="yes">Select items from the list below.</property>