summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/meson.build7
-rw-r--r--src/option.c15
-rw-r--r--src/tree.c716
-rw-r--r--src/util.c4
-rw-r--r--src/util.h2
-rw-r--r--src/zenity-tree-column-view.c478
-rw-r--r--src/zenity-tree-column-view.h54
-rw-r--r--src/zenity-tree-column-view.ui21
-rw-r--r--src/zenity.gresource.xml.in1
-rw-r--r--src/zenity.h4
-rw-r--r--src/zenity.ui16
11 files changed, 767 insertions, 551 deletions
diff --git a/src/meson.build b/src/meson.build
index 2ee1889..e2395ca 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -16,10 +16,11 @@ zenity_sources = [
'text.c',
'tree.c',
'util.c',
+ 'zenity-tree-column-view.c',
]
-zenity_enums = gnome.mkenums_simple('zenity-enums',
- sources: 'zenity.h',
+zenity_cv_enums = gnome.mkenums_simple('zenity-tree-column-view-enums',
+ sources: 'zenity-tree-column-view.h',
)
zenity_res_conf = configuration_data()
@@ -43,7 +44,7 @@ zenity_c_args = [
zenity = executable(
meson.project_name(),
- zenity_sources + zenity_enums + zenity_res,
+ zenity_sources + zenity_cv_enums + zenity_res,
include_directories: zenity_root_dir,
c_args: zenity_c_args,
dependencies: [adw_dep, webkitgtk_dep],
diff --git a/src/option.c b/src/option.c
index ee58af1..d638839 100644
--- a/src/option.c
+++ b/src/option.c
@@ -85,7 +85,6 @@ static char *zenity_list_print_column;
static char *zenity_list_hide_column;
static gboolean zenity_list_hide_header;
static gboolean zenity_list_imagelist;
-static gboolean zenity_list_mid_search;
/* Notification Dialog Options */
static gboolean zenity_notification_active;
@@ -153,6 +152,7 @@ static gboolean zenity_misc_version;
/* DEPRECATED Options */
static char *zenity_general_icon_DEPRECATED;
+static gboolean zenity_list_mid_search_DEPRECATED;
static gboolean zenity_forms_callback (const char *option_name,
const char *value, gpointer data, GError **error);
@@ -547,9 +547,8 @@ static GOptionEntry list_options[] =
'\0',
G_OPTION_FLAG_NOALIAS,
G_OPTION_ARG_NONE,
- &zenity_list_mid_search,
- N_ ("Change list default search function searching for text in the "
- "middle, not on the beginning"),
+ &zenity_list_mid_search_DEPRECATED,
+ N_ ("DEPRECATED; does nothing"),
NULL},
{NULL}};
@@ -1239,7 +1238,7 @@ zenity_list_pre_callback (GOptionContext *context, GOptionGroup *group,
zenity_list_hide_header = FALSE;
zenity_list_print_column = NULL;
zenity_list_hide_column = NULL;
- zenity_list_mid_search = FALSE;
+ zenity_list_mid_search_DEPRECATED = FALSE;
return TRUE;
}
@@ -1602,7 +1601,7 @@ zenity_list_post_callback (GOptionContext *context, GOptionGroup *group,
results->tree_data->hide_column = zenity_list_hide_column;
results->tree_data->hide_header = zenity_list_hide_header;
results->tree_data->separator = zenity_general_separator;
- results->tree_data->mid_search = zenity_list_mid_search;
+ results->tree_data->mid_search_DEPRECATED = zenity_list_mid_search_DEPRECATED;
}
else
{
@@ -1640,9 +1639,9 @@ zenity_list_post_callback (GOptionContext *context, GOptionGroup *group,
zenity_option_error (
zenity_option_get_name (list_options, &zenity_list_hide_header),
ERROR_SUPPORT);
- if (zenity_list_mid_search)
+ if (zenity_list_mid_search_DEPRECATED)
zenity_option_error (
- zenity_option_get_name (list_options, &zenity_list_mid_search),
+ zenity_option_get_name (list_options, &zenity_list_mid_search_DEPRECATED),
ERROR_SUPPORT);
}
return TRUE;
diff --git a/src/tree.c b/src/tree.c
index 163e90a..cebbd99 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -29,6 +29,7 @@
#include "util.h"
#include "zenity.h"
+#include "zenity-tree-column-view.h"
#include <stdlib.h>
#include <string.h>
@@ -37,7 +38,8 @@
#define PRINT_HIDE_COLUMN_SEPARATOR ","
-static GtkTreeView *tree_view;
+static ZenityTreeColumnView *col_view;
+static gboolean editable;
static GSList *selected;
static char *separator;
static gboolean print_all_columns = FALSE;
@@ -46,134 +48,53 @@ static int *hide_columns = NULL;
static GIOChannel *channel;
static int *zenity_tree_extract_column_indexes (char *indexes, int n_columns);
-static gboolean zenity_tree_column_is_hidden (int column_index);
static void zenity_tree_dialog_response (GtkWidget *widget, char *rstr, gpointer data);
-static void zenity_tree_row_activated (GtkTreeView *tree_view,
- GtkTreePath *tree_path, GtkTreeViewColumn *tree_col, gpointer data);
-
-static gboolean
-zenity_tree_dialog_untoggle (GtkTreeModel *model, GtkTreePath *path,
- GtkTreeIter *iter, gpointer data)
-{
- GValue toggle_value = G_VALUE_INIT;
-
- gtk_tree_model_get_value (model, iter, 0, &toggle_value);
-
- if (g_value_get_boolean (&toggle_value))
- gtk_list_store_set (GTK_LIST_STORE (model), iter, 0, FALSE, -1);
-
- return FALSE;
-}
-
-static void
-check_or_radio_label_activated_cb (GtkTreeView *tree_view,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- gpointer user_data)
-{
- GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
- GtkTreeIter iter;
- gboolean value;
-
- /* Because this is a radio list, we should untoggle the previous toggle so
- * that we only have one selection at any given time
- */
- if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model), "radio")) == 1)
- {
- gtk_tree_model_foreach (model, zenity_tree_dialog_untoggle, NULL);
- }
-
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_model_get (model, &iter, 0, &value, -1);
-
- value = !value;
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, value, -1);
-}
+static void zenity_tree_dialog_output (void);
static void
-zenity_load_pixbuf (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
- GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+show_mid_search_deprecation_warning (void)
{
- static GHashTable *pixbuf_cache = NULL;
- GError *error = NULL;
- GdkPixbuf *pixbuf;
- g_autofree char *str = NULL;
-
- gtk_tree_model_get (tree_model, iter, 0, &str, -1);
-
- if (! str)
- return;
-
- if (! pixbuf_cache)
- {
- pixbuf_cache = g_hash_table_new (g_str_hash, g_str_equal);
- g_assert (pixbuf_cache);
- }
-
- pixbuf = g_hash_table_lookup (pixbuf_cache, str);
-
- if (! pixbuf)
- {
- pixbuf = gdk_pixbuf_new_from_file (str, &error);
-
- if (! pixbuf)
- g_warning ("Failed to load '%s'", str);
-
- g_hash_table_insert (pixbuf_cache, g_strdup (str), pixbuf);
- }
-
- if (pixbuf)
- g_object_set (cell, "pixbuf", pixbuf, NULL);
+ g_printerr ("Warning: --mid-search is deprecated and will be removed in a "
+ "future version of zenity. Ignoring.\n");
}
-
static gboolean
-zenity_tree_handle_stdin (GIOChannel *channel, GIOCondition condition,
- gpointer data)
+zenity_tree_handle_stdin (GIOChannel *channel, GIOCondition condition, gpointer data)
{
- GtkTreeModel *model;
- static GtkTreeIter iter;
static int column_count = 0;
static int row_count = 0;
- static int n_columns;
- static gboolean editable;
- static gboolean toggles;
static gboolean first_time = TRUE;
GIOStatus status = G_IO_STATUS_NORMAL;
-
- /* Make sure global is properly defined */
- g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
-
- n_columns =
- GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_view), "n_columns"));
- editable =
- GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_view), "editable"));
- toggles =
- GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_view), "toggles"));
-
- model = gtk_tree_view_get_model (tree_view);
+ int n_columns = zenity_tree_column_view_get_n_columns (col_view);
+ gboolean toggles = FALSE;
+ ZenityTreeListType list_type = zenity_tree_column_view_get_list_type (col_view);
+ GListStore *store = G_LIST_STORE(zenity_tree_column_view_get_model (col_view));
if (first_time)
- {
first_time = FALSE;
- gtk_list_store_append (GTK_LIST_STORE (model), &iter);
- }
+
+ if (list_type == ZENITY_TREE_LIST_RADIO || list_type == ZENITY_TREE_LIST_CHECK)
+ toggles = TRUE;
if ((condition & G_IO_IN) == G_IO_IN)
{
- g_autoptr(GString) string = NULL;
+ ZenityTreeRow *row = NULL;
+ g_autoptr(GString) gstring = g_string_new (NULL);
g_autoptr(GError) error = NULL;
- string = g_string_new (NULL);
-
while ((g_io_channel_get_flags (channel) & G_IO_FLAG_IS_READABLE) !=
G_IO_FLAG_IS_READABLE)
;
+
+ row = zenity_tree_row_new ();
do {
+ ZenityTreeItem *item;
+
do {
if (g_io_channel_get_flags (channel) & G_IO_FLAG_IS_READABLE) {
- status = g_io_channel_read_line_string (channel,
- string, NULL, &error);
- } else {
+ status = g_io_channel_read_line_string (channel, gstring, NULL, &error);
+ g_strchomp (gstring->str);
+ }
+ else {
return FALSE;
}
@@ -188,9 +109,8 @@ zenity_tree_handle_stdin (GIOChannel *channel, GIOCondition condition,
if (status != G_IO_STATUS_NORMAL)
{
if (error) {
- g_warning ("%s: %s",
- __func__, error->message);
- error = NULL;
+ g_warning ("%s: %s", __func__, error->message);
+ g_clear_error (&error);
}
continue;
}
@@ -200,42 +120,32 @@ zenity_tree_handle_stdin (GIOChannel *channel, GIOCondition condition,
/* We're starting a new row */
column_count = 0;
row_count++;
- gtk_list_store_append (GTK_LIST_STORE (model), &iter);
}
if (toggles && column_count == 0)
{
- if (strcmp (g_ascii_strdown (
- zenity_util_strip_newline (string->str), -1),
- "true") == 0)
- {
- gtk_list_store_set (GTK_LIST_STORE(model),
- &iter, column_count, TRUE, -1);
- }
- else {
- gtk_list_store_set (
- GTK_LIST_STORE (model), &iter, column_count, FALSE, -1);
- }
+ item = zenity_tree_item_new (gstring->str, gtk_check_button_new ());
}
- else
+ else if (list_type == ZENITY_TREE_LIST_IMAGE && column_count == 0)
{
- gtk_list_store_set (GTK_LIST_STORE (model),
- &iter,
- column_count,
- zenity_util_strip_newline (string->str),
- -1);
+ item = zenity_tree_item_new (gstring->str, gtk_image_new ());
}
-
- if (editable) {
- gtk_list_store_set (GTK_LIST_STORE(model),
- &iter, n_columns, TRUE, -1);
+ else
+ {
+ if (editable)
+ item = zenity_tree_item_new (gstring->str, gtk_editable_label_new (NULL));
+ else
+ item = zenity_tree_item_new (gstring->str, gtk_label_new (NULL));
}
+ zenity_tree_row_add (row, item);
column_count++;
- } while ((g_io_channel_get_buffer_condition (channel) & G_IO_IN) ==
- G_IO_IN &&
+ } while ((g_io_channel_get_buffer_condition (channel) & G_IO_IN) == G_IO_IN &&
status != G_IO_STATUS_EOF); /* !do while */
+
+ if (row)
+ g_list_store_append (store, row);
}
if ((condition & G_IO_IN) != G_IO_IN || status == G_IO_STATUS_EOF)
@@ -247,100 +157,67 @@ zenity_tree_handle_stdin (GIOChannel *channel, GIOCondition condition,
}
static void
-zenity_tree_fill_entries_from_stdin (GtkTreeView *loc_tv, int n_columns,
- gboolean toggles, gboolean editable)
+zenity_tree_fill_entries_from_stdin (void)
{
- /* No reason this should fail. Sanity check. */
- g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
- g_assert (loc_tv == tree_view);
-
- g_object_set_data (
- G_OBJECT (tree_view), "n_columns", GINT_TO_POINTER (n_columns));
- g_object_set_data (
- G_OBJECT (tree_view), "toggles", GINT_TO_POINTER (toggles));
- g_object_set_data (
- G_OBJECT (tree_view), "editable", GINT_TO_POINTER (editable));
-
channel = g_io_channel_unix_new (0);
g_io_channel_set_encoding (channel, NULL, NULL);
g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
- g_io_add_watch (channel,
- G_IO_IN | G_IO_HUP, zenity_tree_handle_stdin, NULL);
+ g_io_add_watch (channel, G_IO_IN | G_IO_HUP, zenity_tree_handle_stdin, NULL);
}
static void
-zenity_tree_fill_entries (GtkTreeView *loc_tv, const char **args,
- int n_columns, gboolean toggles, gboolean editable)
+zenity_tree_fill_entries (const char **args)
{
- GtkTreeModel *model;
- GtkTreeIter iter;
- int i = 0;
-
- /* No reason this should fail. Sanity check. */
- g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
- g_assert (loc_tv == tree_view);
-
- model = gtk_tree_view_get_model (tree_view);
-
- g_object_set_data (
- G_OBJECT (tree_view), "n_columns", GINT_TO_POINTER (n_columns));
+ int n_columns = zenity_tree_column_view_get_n_columns (col_view);
+ ZenityTreeListType list_type = zenity_tree_column_view_get_list_type (col_view);
+ GListStore *store = G_LIST_STORE(zenity_tree_column_view_get_model (col_view));
+ gboolean toggles = FALSE;
- while (args[i] != NULL) {
- int j;
+ if (list_type == ZENITY_TREE_LIST_RADIO || list_type == ZENITY_TREE_LIST_CHECK)
+ toggles = TRUE;
- gtk_list_store_append (GTK_LIST_STORE (model), &iter);
-
- for (j = 0; j < n_columns; j++) {
+ for (int i = 0; args[i]; i+= n_columns)
+ {
+ ZenityTreeRow *row = zenity_tree_row_new ();
- if (toggles && j == 0) {
- if (strcmp (g_ascii_strdown ((gchar *) args[i + j], -1),
- "true") == 0)
- gtk_list_store_set (
- GTK_LIST_STORE (model), &iter, j, TRUE, -1);
+ for (int j = 0; j < n_columns; j++)
+ {
+ ZenityTreeItem *item;
+ const char *str = args[i + j];
+
+ if (toggles && j == 0)
+ {
+ item = zenity_tree_item_new (str, gtk_check_button_new ());
+ }
+ else if (list_type == ZENITY_TREE_LIST_IMAGE && j == 0)
+ {
+ item = zenity_tree_item_new (str, gtk_image_new ());
+ }
+ else
+ {
+ if (editable)
+ item = zenity_tree_item_new (str, gtk_editable_label_new (""));
else
- gtk_list_store_set (
- GTK_LIST_STORE (model), &iter, j, FALSE, -1);
- } else
- gtk_list_store_set (
- GTK_LIST_STORE (model), &iter, j, args[i + j], -1);
- }
-
- if (editable) {
- gtk_list_store_set (GTK_LIST_STORE(model),
- &iter, n_columns, TRUE, -1);
+ item = zenity_tree_item_new (str, gtk_label_new (NULL));
+ }
+ zenity_tree_row_add (row, item);
}
- i += n_columns;
+ g_list_store_append (store, row);
}
}
-static gboolean
-zenity_mid_search_func (GtkTreeModel *model, int column, const char *key,
- GtkTreeIter *iter, gpointer search_data)
-{
- char *iter_string = NULL;
-
- gtk_tree_model_get (model, iter, column, &iter_string, -1);
-
- return !(g_strrstr (g_utf8_strdown (iter_string, -1),
- g_utf8_strdown (key, -1)) != NULL);
-}
-
static void
-zenity_cell_edited_callback (GtkCellRendererText *cell,
- const char *path_string, const char *new_text, gpointer data)
+cv_activated_cb (ZenityTreeColumnView *cv, gpointer data)
{
- GtkTreeModel *model;
- g_autoptr(GtkTreePath) path = NULL;
- GtkTreeIter iter;
- int column;
+ GtkWindow *parent;
+ ZenityData *zen_data = data;
- model = GTK_TREE_MODEL (data);
- path = gtk_tree_path_new_from_string (path_string);
+ zenity_tree_dialog_output ();
+ zen_data->exit_code = zenity_util_return_exit_code (ZENITY_OK);
- column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));
- gtk_tree_model_get_iter (model, &iter, path);
+ parent = GTK_WINDOW(gtk_widget_get_native (GTK_WIDGET(col_view)));
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, new_text, -1);
+ zenity_util_gapp_quit (parent, zen_data);
}
void
@@ -349,12 +226,13 @@ zenity_tree (ZenityData *data, ZenityTreeData *tree_data)
g_autoptr(GtkBuilder) builder = NULL;
GtkWidget *dialog;
GObject *text;
- GtkTreeViewColumn *column;
- GtkListStore *model;
- GType *column_types;
+ GListStore *store;
+ ZenityTreeListType list_type;
GSList *tmp;
- gboolean first_column = FALSE;
- int i, column_index, n_columns;
+ int n_columns;
+
+ if (tree_data->mid_search_DEPRECATED)
+ show_mid_search_deprecation_warning ();
builder = zenity_util_load_ui_file ("zenity_tree_dialog", "zenity_tree_box", NULL);
@@ -401,8 +279,7 @@ zenity_tree (ZenityData *data, ZenityTreeData *tree_data)
return;
}
- dialog = GTK_WIDGET(gtk_builder_get_object (builder,
- "zenity_tree_dialog"));
+ dialog = GTK_WIDGET(gtk_builder_get_object (builder, "zenity_tree_dialog"));
g_signal_connect (dialog, "response", G_CALLBACK(zenity_tree_dialog_response), data);
@@ -439,243 +316,55 @@ zenity_tree (ZenityData *data, ZenityTreeData *tree_data)
data->width, data->height);
}
- /* Define global tree_view. */
- tree_view = GTK_TREE_VIEW(gtk_builder_get_object (builder,
- "zenity_tree_view"));
+ /* Create a list store */
+ store = g_list_store_new (ZENITY_TREE_TYPE_ROW);
- if (tree_data->radiobox || tree_data->checkbox)
- {
- gtk_tree_view_set_activate_on_single_click (GTK_TREE_VIEW(tree_view),
- TRUE);
+ /* Define global col_view */
+ col_view = ZENITY_TREE_COLUMN_VIEW(gtk_builder_get_object (builder, "zenity_tree_cv"));
- g_signal_connect (tree_view,
- "row-activated",
- G_CALLBACK (check_or_radio_label_activated_cb),
- data);
- }
- else
- {
- g_signal_connect (tree_view,
- "row-activated",
- G_CALLBACK (zenity_tree_row_activated),
- data);
- }
-
- /* Create an empty list store */
- model = g_object_new (GTK_TYPE_LIST_STORE, NULL);
-
- if (tree_data->editable)
- column_types = g_new (GType, n_columns + 1);
- else
- column_types = g_new (GType, n_columns);
+ /* This signal will only get emitted for certain kinds of lists, but if
+ * applicable, it should finish the job.
+ */
+ g_signal_connect (col_view, "activated", G_CALLBACK(cv_activated_cb), data);
- for (i = 0; i < n_columns; i++)
- {
- /* Have the limitation that the radioboxes and checkboxes are in the
- * first column */
- if (i == 0 && (tree_data->checkbox || tree_data->radiobox))
- column_types[i] = G_TYPE_BOOLEAN;
- else
- column_types[i] = G_TYPE_STRING;
+ if (tree_data->radiobox) {
+ list_type = ZENITY_TREE_LIST_RADIO;
}
-
- if (tree_data->editable)
- column_types[n_columns] = G_TYPE_BOOLEAN;
-
- if (tree_data->editable)
- gtk_list_store_set_column_types (model, n_columns + 1, column_types);
- else
- gtk_list_store_set_column_types (model, n_columns, column_types);
-
- gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL(model));
-
- if (tree_data->radiobox || tree_data->checkbox)
- {
- gtk_tree_selection_set_mode (
- gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)),
- GTK_SELECTION_SINGLE);
+ else if (tree_data->checkbox) {
+ list_type = ZENITY_TREE_LIST_CHECK;
}
- else
- {
- if (tree_data->multi)
- gtk_tree_selection_set_mode (
- gtk_tree_view_get_selection (tree_view),
- GTK_SELECTION_MULTIPLE);
- else
- gtk_tree_selection_set_mode (
- gtk_tree_view_get_selection (tree_view),
- GTK_SELECTION_SINGLE);
+ else if (tree_data->imagebox) {
+ list_type = ZENITY_TREE_LIST_IMAGE;
+ }
+ else {
+ list_type = ZENITY_TREE_LIST_NONE;
}
- column_index = 0;
+ editable = tree_data->editable;
+ g_object_set (col_view,
+ "list-type", list_type,
+ "multi", tree_data->multi,
+ "model", G_LIST_MODEL(store),
+ NULL);
for (tmp = tree_data->columns; tmp; tmp = tmp->next)
{
- if (! first_column)
- {
- if (tree_data->checkbox || tree_data->radiobox)
- {
- GtkCellRenderer *cell_renderer;
-
- cell_renderer = gtk_cell_renderer_toggle_new ();
-
- if (tree_data->radiobox) {
- g_object_set (
- G_OBJECT (cell_renderer), "radio", TRUE, NULL);
- g_object_set_data (
- G_OBJECT (model), "radio", GINT_TO_POINTER (1));
- }
-
- column = gtk_tree_view_column_new_with_attributes (
- tmp->data, cell_renderer, "active", column_index, NULL);
- }
- else if (tree_data->imagebox)
- {
- GtkCellRenderer *cell_renderer =
- gtk_cell_renderer_pixbuf_new ();
-
- column = gtk_tree_view_column_new_with_attributes (
- tmp->data, cell_renderer, NULL);
- gtk_tree_view_column_set_cell_data_func (
- column, cell_renderer, zenity_load_pixbuf, NULL, NULL);
- }
- else
- {
- if (tree_data->editable)
- {
- GtkCellRenderer *cell_renderer;
-
- cell_renderer = gtk_cell_renderer_text_new ();
- g_signal_connect (cell_renderer, "edited",
- G_CALLBACK (zenity_cell_edited_callback),
- gtk_tree_view_get_model (tree_view));
-
- g_object_set_data (G_OBJECT (cell_renderer),
- "column",
- GINT_TO_POINTER (column_index));
-
- column =
- gtk_tree_view_column_new_with_attributes (tmp->data,
- cell_renderer,
- "text",
- column_index,
- "editable",
- n_columns,
- NULL);
- }
- else
- {
- column =
- gtk_tree_view_column_new_with_attributes (tmp->data,
- gtk_cell_renderer_text_new (),
- "text",
- column_index,
- NULL);
- }
-
- gtk_tree_view_column_set_sort_column_id (column, column_index);
- gtk_tree_view_column_set_resizable (column, TRUE);
- }
- if (zenity_tree_column_is_hidden (1))
- gtk_tree_view_column_set_visible (column, FALSE);
-
- first_column = TRUE;
- }
- else
- {
- if (tree_data->editable)
- {
- GtkCellRenderer *cell_renderer;
-
- cell_renderer = gtk_cell_renderer_text_new ();
- g_signal_connect (cell_renderer, "edited",
- G_CALLBACK (zenity_cell_edited_callback),
- gtk_tree_view_get_model (tree_view));
-
- g_object_set_data (G_OBJECT (cell_renderer),
- "column",
- GINT_TO_POINTER (column_index));
-
- column = gtk_tree_view_column_new_with_attributes (tmp->data,
- cell_renderer,
- "text",
- column_index,
- "editable",
- n_columns,
- NULL);
- }
- else
- {
- column = gtk_tree_view_column_new_with_attributes (tmp->data,
- gtk_cell_renderer_text_new (),
- "text",
- column_index,
- NULL);
- }
-
- gtk_tree_view_column_set_sort_column_id (column, column_index);
- gtk_tree_view_column_set_resizable (column, TRUE);
-
- if (zenity_tree_column_is_hidden (column_index + 1))
- gtk_tree_view_column_set_visible (column, FALSE);
- }
-
- gtk_tree_view_append_column (tree_view, column);
- column_index++;
+ zenity_tree_column_view_add_column (col_view, tmp->data);
}
- if (tree_data->hide_header)
- gtk_tree_view_set_headers_visible (tree_view, FALSE);
-
- if (tree_data->radiobox || tree_data->checkbox)
+ if (tree_data->data && *tree_data->data) /* we have argv after opts */
{
- if (tree_data->data && *tree_data->data) {
- zenity_tree_fill_entries (tree_view,
- tree_data->data,
- n_columns,
- TRUE,
- tree_data->editable);
- }
- else {
- zenity_tree_fill_entries_from_stdin (tree_view,
- n_columns,
- TRUE,
- tree_data->editable);
- }
+ zenity_tree_fill_entries (tree_data->data);
}
else
{
- if (tree_data->data && *tree_data->data) {
- zenity_tree_fill_entries (tree_view,
- tree_data->data,
- n_columns,
- FALSE,
- tree_data->editable);
- } else {
- zenity_tree_fill_entries_from_stdin (tree_view,
- n_columns,
- FALSE,
- tree_data->editable);
- }
+ zenity_tree_fill_entries_from_stdin ();
}
- /* GTK will automatically pick the image column as the search column
- * despite it not containing any user readable text.
- * Set it to second column instead if it exists. */
- if (tree_data->imagebox && n_columns > 1) {
- gtk_tree_view_set_search_column (GTK_TREE_VIEW (tree_view),
- 1);
- }
+ // FIXME - make stuff searchable
zenity_util_show_dialog (dialog);
- if (tree_data->mid_search) {
- gtk_tree_view_set_search_equal_func (tree_view,
- (GtkTreeViewSearchEqualFunc) zenity_mid_search_func,
- model,
- NULL);
- }
-
if (data->timeout_delay > 0) {
g_timeout_add_seconds (data->timeout_delay,
(GSourceFunc) zenity_util_timeout_handle,
@@ -685,103 +374,115 @@ zenity_tree (ZenityData *data, ZenityTreeData *tree_data)
zenity_util_gapp_main (GTK_WINDOW(dialog));
}
-static void
-zenity_tree_dialog_get_selected (GtkTreeModel *model, GtkTreePath *path_buf,
- GtkTreeIter *iter, gpointer user_data)
+static gboolean
+get_row_checkbtn_toggled (ZenityTreeRow *row)
{
- GValue value = G_VALUE_INIT;
- int n_columns, i;
+ ZenityTreeItem *item = zenity_tree_row_get_item (row, 0);
+ GtkWidget *child = zenity_tree_item_get_child (item);
- n_columns =
- GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_view), "n_columns"));
-
- if (print_all_columns)
+ if (GTK_IS_CHECK_BUTTON (child))
{
- for (i = 0; i < n_columns; i++)
- {
- gtk_tree_model_get_value (model, iter, i, &value);
-
- selected = g_slist_append (selected, g_value_dup_string (&value));
- g_value_unset (&value);
- }
- return;
+ return gtk_check_button_get_active (GTK_CHECK_BUTTON(child));
}
- for (i = 0; print_columns[i] != 0; i++)
- {
- gtk_tree_model_get_value (model, iter, print_columns[i] - 1, &value);
- selected = g_slist_append (selected, g_value_dup_string (&value));
-
- g_value_unset (&value);
- }
+ return FALSE;
}
-static gboolean
-zenity_tree_dialog_toggle_get_selected (GtkTreeModel *model, GtkTreePath *path,
- GtkTreeIter *iter, gpointer user_data)
+static void
+zenity_tree_dialog_get_selected (void)
{
- GValue toggle_value = G_VALUE_INIT;
- int n_columns, i;
+ int n_columns = zenity_tree_column_view_get_n_columns (col_view);
+ GListModel *model = zenity_tree_column_view_get_model (col_view);
+ ZenityTreeItem *item;
- n_columns =
- GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_view), "n_columns"));
+ for (guint i = 0; i < g_list_model_get_n_items (model); ++i)
+ {
+ ZenityTreeRow *row;
- gtk_tree_model_get_value (model, iter, 0, &toggle_value);
+ if (! zenity_tree_column_view_is_selected (col_view, i))
+ continue;
- if (g_value_get_boolean (&toggle_value))
- {
- GValue value = G_VALUE_INIT;
+ row = g_list_model_get_item (model, i);
if (print_all_columns)
{
- for (i = 1; i < n_columns; i++)
+ for (int j = 0; j < n_columns; j++)
{
- gtk_tree_model_get_value (model, iter, i, &value);
+ item = zenity_tree_row_get_item (row, j);
- selected =
- g_slist_append (selected, g_value_dup_string (&value));
- g_value_unset (&value);
+ selected = g_slist_append (selected,
+ g_strdup (zenity_tree_item_get_text (item)));
}
- g_value_unset (&toggle_value);
- return FALSE;
}
-
- for (i = 0; print_columns[i] != 0; i++)
+ else
{
- gtk_tree_model_get_value (
- model, iter, print_columns[i] - 1, &value);
+ for (int j = 0; print_columns[j] != 0; j++)
+ {
+ /* columns in CLI count from 1 and are allocated as 0-terminated
+ * arrays, so account for that here with -1. */
+ item = zenity_tree_row_get_item (row, print_columns[j] - 1);
- selected = g_slist_append (selected, g_value_dup_string (&value));
- g_value_unset (&value);
+ selected = g_slist_append (selected,
+ g_strdup (zenity_tree_item_get_text (item)));
+ }
}
}
- g_value_unset (&toggle_value);
-
- return FALSE;
}
static void
-zenity_tree_dialog_output (void)
+zenity_tree_dialog_toggle_get_selected (ZenityTreeRow *row, gpointer unused)
{
- GtkTreeSelection *selection;
- GtkTreeModel *model;
+ int n_columns;
+ ZenityTreeItem *item;
- g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ if (! get_row_checkbtn_toggled (row))
+ return;
- model = gtk_tree_view_get_model (tree_view);
+ n_columns = zenity_tree_column_view_get_n_columns (col_view);
- if (gtk_tree_model_get_column_type (model, 0) == G_TYPE_BOOLEAN)
+ if (print_all_columns)
{
- gtk_tree_model_foreach (model,
- (GtkTreeModelForeachFunc) zenity_tree_dialog_toggle_get_selected,
- NULL);
+ /* start at 1 because we're not printing the checklist column string
+ */
+ for (int i = 1; i < n_columns; i++)
+ {
+ item = zenity_tree_row_get_item (row, i);
+
+ selected = g_slist_append (selected,
+ g_strdup (zenity_tree_item_get_text (item)));
+ }
}
else
{
- selection = gtk_tree_view_get_selection (tree_view);
- gtk_tree_selection_selected_foreach (selection,
- (GtkTreeSelectionForeachFunc) zenity_tree_dialog_get_selected,
- NULL);
+ for (int i = 0; print_columns[i] != 0; i++)
+ {
+ /* columns in CLI count from 1 and are allocated as 0-terminated
+ * arrays, so account for that here with -1. */
+ item = zenity_tree_row_get_item (row, print_columns[i] - 1);
+
+ selected = g_slist_append (selected,
+ g_strdup (zenity_tree_item_get_text (item)));
+ }
+ }
+}
+
+static void
+zenity_tree_dialog_output (void)
+{
+ gboolean multi = zenity_tree_column_view_get_multi (col_view);
+ ZenityTreeListType list_type = zenity_tree_column_view_get_list_type (col_view);
+
+ if (list_type == ZENITY_TREE_LIST_RADIO || list_type == ZENITY_TREE_LIST_CHECK)
+ {
+ zenity_tree_column_view_foreach_row (col_view,
+ (GFunc)zenity_tree_dialog_toggle_get_selected, NULL);
+ }
+ else if (multi)
+ {
+ }
+ else
+ {
+ zenity_tree_dialog_get_selected ();
}
@@ -840,39 +541,6 @@ zenity_tree_dialog_response (GtkWidget *widget, char *rstr, gpointer data)
zenity_util_gapp_quit (GTK_WINDOW(widget), zen_data);
}
-static void
-zenity_tree_row_activated (GtkTreeView *loc_tv, GtkTreePath *tree_path,
- GtkTreeViewColumn *tree_col, gpointer data)
-{
- GtkWindow *parent;
- ZenityData *zen_data = data;
-
- /* No reason this should fail. Sanity check. */
- g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
- g_assert (loc_tv == tree_view);
-
- zenity_tree_dialog_output ();
- zen_data->exit_code = zenity_util_return_exit_code (ZENITY_OK);
-
- parent = GTK_WINDOW(gtk_widget_get_native (GTK_WIDGET(tree_view)));
-
- zenity_util_gapp_quit (parent, zen_data);
-}
-
-static gboolean
-zenity_tree_column_is_hidden (int column_index)
-{
- if (hide_columns != NULL)
- {
- for (int i = 0; hide_columns[i] != 0; i++)
- {
- if (hide_columns[i] == column_index)
- return TRUE;
- }
- }
- return FALSE;
-}
-
static int *
zenity_tree_extract_column_indexes (char *indexes, int n_columns)
{
diff --git a/src/util.c b/src/util.c
index 1cc21af..8cfae93 100644
--- a/src/util.c
+++ b/src/util.c
@@ -105,6 +105,10 @@ zenity_util_load_ui_file (const char *root_widget, ...)
g_ptr_array_add (ptrarray, NULL);
objects = (char **)g_ptr_array_free (ptrarray, FALSE);
+ /* Make sure this custom widget type is registered before this initial
+ * GtkBuilder method call. */
+ g_type_ensure (ZENITY_TREE_TYPE_COLUMN_VIEW);
+
result = gtk_builder_add_objects_from_resource (builder,
ZENITY_UI_RESOURCE_PATH,
(const char **)objects,
diff --git a/src/util.h b/src/util.h
index 5ea703d..54081a6 100644
--- a/src/util.h
+++ b/src/util.h
@@ -36,6 +36,8 @@
#pragma once
#include "zenity.h"
+#include "zenity-tree-column-view.h"
+
#include <gtk/gtk.h>
G_BEGIN_DECLS
diff --git a/src/zenity-tree-column-view.c b/src/zenity-tree-column-view.c
new file mode 100644
index 0000000..2e12122
--- /dev/null
+++ b/src/zenity-tree-column-view.c
@@ -0,0 +1,478 @@
+#include "zenity-tree-column-view.h"
+#include <config.h>
+
+#define UI_FILE RESOURCE_BASE_PATH "/zenity-tree-column-view.ui"
+
+struct _ZenityTreeItem
+{
+ GObject parent_instance;
+ GtkWidget *child;
+ char *text;
+};
+
+G_DEFINE_TYPE (ZenityTreeItem, zenity_tree_item, G_TYPE_OBJECT)
+
+static void
+zenity_tree_item_init (ZenityTreeItem *item)
+{
+}
+
+static void
+zenity_tree_item_class_init (ZenityTreeItemClass *klass)
+{
+}
+
+GtkWidget *
+zenity_tree_item_get_child (ZenityTreeItem *item)
+{
+ return item->child;
+}
+
+const char *
+zenity_tree_item_get_text (ZenityTreeItem *item)
+{
+ return item->text;
+}
+
+void
+zenity_tree_item_set_text (ZenityTreeItem *item, const char *text)
+{
+ g_clear_pointer (&item->text, g_free);
+ item->text = g_strdup (text);
+}
+
+ZenityTreeItem *
+zenity_tree_item_new (const char *text, GtkWidget *child)
+{
+ ZenityTreeItem *item;
+
+ 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);
+
+ return item;
+}
+
+/* --- */
+
+struct _ZenityTreeRow
+{
+ GObject parent_instance;
+ GPtrArray *items;
+};
+
+G_DEFINE_TYPE (ZenityTreeRow, zenity_tree_row, G_TYPE_OBJECT)
+
+static void
+zenity_tree_row_init (ZenityTreeRow *self)
+{
+ self->items = g_ptr_array_new ();
+}
+
+static void
+zenity_tree_row_class_init (ZenityTreeRowClass *klass)
+{
+}
+
+ZenityTreeRow *
+zenity_tree_row_new (void)
+{
+ return g_object_new (ZENITY_TREE_TYPE_ROW, NULL);
+}
+
+void
+zenity_tree_row_add (ZenityTreeRow *row, ZenityTreeItem *item)
+{
+ g_ptr_array_add (row->items, item);
+}
+
+guint
+zenity_tree_row_get_n_items (ZenityTreeRow *row)
+{
+ return row->items->len;
+}
+
+ZenityTreeItem *
+zenity_tree_row_get_item (ZenityTreeRow *row, guint index)
+{
+ g_return_val_if_fail (index < row->items->len, NULL);
+
+ return row->items->pdata[index];
+}
+
+/* --- */
+
+enum zenity_tree_column_view_signal_enum {
+ ACTIVATED,
+ LAST_SIGNAL
+};
+
+static guint zenity_tree_column_view_signals[LAST_SIGNAL];
+
+/* --- */
+
+enum zenity_tree_column_view_props
+{
+ MULTI = 1,
+ LIST_TYPE,
+ MODEL,
+ N_PROPERTIES_ZENITY_TREE_COLUMN_VIEW
+};
+
+static GParamSpec *zenity_tree_column_view_properties[N_PROPERTIES_ZENITY_TREE_COLUMN_VIEW];
+
+struct _ZenityTreeColumnView
+{
+ GtkWidget parent_instance;
+ GtkWidget *scrolled_window;
+ GtkColumnView *child_cv;
+ gboolean multi;
+ ZenityTreeListType list_type;
+ GListModel *model;
+ GtkCheckButton *checkbutton_group;
+};
+
+G_DEFINE_TYPE (ZenityTreeColumnView, zenity_tree_column_view, GTK_TYPE_WIDGET)
+
+void
+zenity_tree_column_view_set_model (ZenityTreeColumnView *self, GListModel *model)
+{
+ self->model = model;
+
+ if (self->multi)
+ {
+ gtk_column_view_set_model (self->child_cv,
+ GTK_SELECTION_MODEL(gtk_multi_selection_new (self->model)));
+ }
+ else
+ {
+ gtk_column_view_set_model (self->child_cv,
+ GTK_SELECTION_MODEL(gtk_single_selection_new (self->model)));
+ }
+
+ g_object_notify_by_pspec (G_OBJECT(self), zenity_tree_column_view_properties[MODEL]);
+}
+
+GListModel *
+zenity_tree_column_view_get_model (ZenityTreeColumnView *self)
+{
+ return self->model;
+}
+
+static void
+zenity_tree_column_view_emit_activated (ZenityTreeColumnView *self)
+{
+ g_signal_emit (self, zenity_tree_column_view_signals[ACTIVATED], 0);
+}
+
+void
+zenity_tree_column_view_set_list_type (ZenityTreeColumnView *self, ZenityTreeListType type)
+{
+ self->list_type = type;
+
+ g_signal_handlers_disconnect_by_func (self->child_cv, zenity_tree_column_view_emit_activated, self);
+
+ switch (self->list_type)
+ {
+ case ZENITY_TREE_LIST_NONE:
+ case ZENITY_TREE_LIST_IMAGE:
+ g_signal_connect_swapped (self->child_cv, "activate", G_CALLBACK(zenity_tree_column_view_emit_activated), self);
+ break;
+
+ default:
+ break;
+ }
+
+ g_object_notify_by_pspec (G_OBJECT(self), zenity_tree_column_view_properties[LIST_TYPE]);
+}
+
+ZenityTreeListType
+zenity_tree_column_view_get_list_type (ZenityTreeColumnView *self)
+{
+ return self->list_type;
+}
+
+gboolean
+zenity_tree_column_view_get_multi (ZenityTreeColumnView *self)
+{
+ return self->multi;
+}
+
+static void
+zenity_tree_column_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ZenityTreeColumnView *self = ZENITY_TREE_COLUMN_VIEW(object);
+
+ switch (property_id)
+ {
+ case MULTI:
+ self->multi = g_value_get_boolean (value);
+ break;
+
+ case LIST_TYPE:
+ zenity_tree_column_view_set_list_type (self, g_value_get_enum (value));
+ break;
+
+ case MODEL:
+ zenity_tree_column_view_set_model (self, G_LIST_MODEL(g_value_get_object (value)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+zenity_tree_column_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ZenityTreeColumnView *self = ZENITY_TREE_COLUMN_VIEW(object);
+
+ switch (property_id)
+ {
+ case MULTI:
+ g_value_set_boolean (value, self->multi);
+ break;
+
+ case LIST_TYPE:
+ g_value_set_enum (value, zenity_tree_column_view_get_list_type (self));
+ break;
+
+ case MODEL:
+ g_value_set_object (value, G_OBJECT(zenity_tree_column_view_get_model (self)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+zenity_tree_column_view_dispose (GObject *object)
+{
+ ZenityTreeColumnView *self = ZENITY_TREE_COLUMN_VIEW(object);
+
+ g_clear_pointer (&self->scrolled_window, gtk_widget_unparent);
+
+ G_OBJECT_CLASS(zenity_tree_column_view_parent_class)->dispose(object);
+}
+
+static void
+zenity_tree_column_view_init (ZenityTreeColumnView *self)
+{
+ GtkWidget *widget = GTK_WIDGET(self);
+
+ gtk_widget_init_template (widget);
+
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_widget_set_vexpand (widget, TRUE);
+}
+
+static void
+zenity_tree_column_view_class_init (ZenityTreeColumnViewClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(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_column_view_dispose;
+ object_class->set_property = zenity_tree_column_view_set_property;
+ object_class->get_property = zenity_tree_column_view_get_property;
+
+ zenity_tree_column_view_properties[MULTI] = g_param_spec_boolean ("multi", NULL, NULL,
+ FALSE, flags);
+ zenity_tree_column_view_properties[LIST_TYPE] = g_param_spec_enum ("list-type", NULL, NULL,
+ ZENITY_TYPE_TREE_LIST_TYPE, ZENITY_TREE_LIST_NONE, flags);
+ zenity_tree_column_view_properties[MODEL] = g_param_spec_object ("model", NULL, NULL,
+ G_TYPE_LIST_MODEL, flags);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES_ZENITY_TREE_COLUMN_VIEW, zenity_tree_column_view_properties);
+
+ zenity_tree_column_view_signals[ACTIVATED] = g_signal_new_class_handler ("activated",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ /* no default C function */
+ NULL,
+ /* defaults for accumulator, marshaller &c. */
+ NULL, NULL, NULL,
+ /* No return type or params. */
+ G_TYPE_NONE, 0);
+
+ gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+
+ gtk_widget_class_set_template_from_resource (widget_class, UI_FILE);
+
+ gtk_widget_class_bind_template_child (widget_class, ZenityTreeColumnView, scrolled_window);
+ gtk_widget_class_bind_template_child (widget_class, ZenityTreeColumnView, child_cv);
+}
+
+#if 0
+static GtkWidget *
+zenity_tree_column_view_new (GListModel *model)
+{
+ g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
+
+ return g_object_new (ZENITY_TREE_TYPE_COLUMN_VIEW,
+ "model", model,
+ NULL);
+}
+#endif
+
+static void
+editable_notify_text_cb (GtkEditable *editable, GParamSpec *pspec, ZenityTreeItem *item)
+{
+ const char *str = gtk_editable_get_text (editable);
+ zenity_tree_item_set_text (item, str);
+}
+
+static void
+factory_bind_cb (ZenityTreeColumnView *self,
+ GtkListItem *list_item,
+ GtkSignalListItemFactory *factory)
+{
+ ZenityTreeRow *row = gtk_list_item_get_item (list_item);
+ int col_index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(factory), "col_index"));
+ ZenityTreeItem *item;
+ GtkWidget *item_child;
+ const char *item_text;
+
+ item = zenity_tree_row_get_item (row, col_index);
+ item_child = zenity_tree_item_get_child (item);
+ item_text = zenity_tree_item_get_text (item);
+ gtk_list_item_set_child (list_item, item_child);
+
+ gtk_widget_set_halign (item_child, GTK_ALIGN_START);
+
+ if (GTK_IS_EDITABLE (item_child)) /* handle first to capture anything editable */
+ {
+ gtk_editable_set_text (GTK_EDITABLE(item_child), item_text);
+ g_signal_connect (item_child, "notify::text", G_CALLBACK(editable_notify_text_cb), item);
+ }
+ else if (GTK_IS_LABEL (item_child))
+ {
+ gtk_label_set_text (GTK_LABEL(item_child), item_text);
+ }
+ else if (GTK_IS_CHECK_BUTTON (item_child) && item_text)
+ {
+ gboolean initialized = FALSE;
+ gboolean checked = FALSE;
+
+ if (g_object_get_data (G_OBJECT(item_child), "initialized"))
+ initialized = TRUE;
+
+ /* Radio-button-ize our check buttons if radio list requested
+ */
+ if (self->list_type == ZENITY_TREE_LIST_RADIO)
+ {
+ if (!self->checkbutton_group)
+ self->checkbutton_group = GTK_CHECK_BUTTON(item_child);
+
+ /* Annoying - if you try to add checkbtn to its own group, gtk
+ * spews errors instead of just returning silently.
+ */
+ if (GTK_CHECK_BUTTON(item_child) != self->checkbutton_group)
+ gtk_check_button_set_group (GTK_CHECK_BUTTON(item_child), self->checkbutton_group);
+ }
+
+ if (! initialized)
+ {
+ if (g_ascii_strcasecmp (item_text, "true") == 0)
+ checked = TRUE;
+
+ gtk_check_button_set_active (GTK_CHECK_BUTTON(item_child), checked);
+
+ g_object_set_data (G_OBJECT(item_child), "initialized", GINT_TO_POINTER(TRUE));
+ }
+ }
+ else if (GTK_IS_IMAGE (item_child) && item_text)
+ {
+ gtk_image_set_from_file (GTK_IMAGE(item_child), item_text);
+ }
+ else
+ {
+ g_warning ("%s: Widget type of child not implemented.", __func__);
+ }
+}
+
+void
+zenity_tree_column_view_add_column (ZenityTreeColumnView *self, const char *col_name)
+{
+ int new_col_index;
+ GtkListItemFactory *factory;
+ GtkColumnViewColumn *column;
+
+ new_col_index = zenity_tree_column_view_get_n_columns (self);
+
+ factory = gtk_signal_list_item_factory_new ();
+ g_object_set_data (G_OBJECT(factory), "col_index", GINT_TO_POINTER(new_col_index));
+ g_signal_connect_swapped (factory, "bind", G_CALLBACK (factory_bind_cb), self);
+
+ /* nb: seems the signals for the factory need to be setup first *before* creating the column. */
+
+ column = gtk_column_view_column_new (col_name, factory);
+
+ if (new_col_index == 0 &&
+ (self->list_type == ZENITY_TREE_LIST_CHECK || self->list_type == ZENITY_TREE_LIST_RADIO))
+ {
+ gtk_column_view_column_set_resizable (column, FALSE);
+ }
+ else
+ {
+ gtk_column_view_column_set_resizable (column, TRUE);
+ gtk_column_view_column_set_expand (column, TRUE);
+ }
+
+ gtk_column_view_append_column (self->child_cv, column);
+}
+
+void
+zenity_tree_column_view_foreach_item (ZenityTreeColumnView *self, GFunc func, gpointer user_data)
+{
+ GListModel *model = zenity_tree_column_view_get_model (self);
+
+ for (guint i = 0; i < g_list_model_get_n_items (model); ++i)
+ {
+ ZenityTreeRow *row = g_list_model_get_item (model, i);
+
+ for (guint j = 0; j < zenity_tree_row_get_n_items (row); ++j)
+ {
+ ZenityTreeItem *item = zenity_tree_row_get_item (row, j);
+
+ func (item, user_data);
+ }
+ }
+}
+
+void
+zenity_tree_column_view_foreach_row (ZenityTreeColumnView *self, GFunc func, gpointer user_data)
+{
+ GListModel *model = zenity_tree_column_view_get_model (self);
+
+ for (guint i = 0; i < g_list_model_get_n_items (model); ++i)
+ {
+ ZenityTreeRow *row = g_list_model_get_item (model, i);
+ func (row, user_data);
+ }
+}
+
+int
+zenity_tree_column_view_get_n_columns (ZenityTreeColumnView *self)
+{
+ return g_list_model_get_n_items (gtk_column_view_get_columns (self->child_cv));
+}
+
+gboolean
+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);
+}
diff --git a/src/zenity-tree-column-view.h b/src/zenity-tree-column-view.h
new file mode 100644
index 0000000..c66e323
--- /dev/null
+++ b/src/zenity-tree-column-view.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "zenity-tree-column-view-enums.h" /* auto-generated by build system */
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ ZENITY_TREE_LIST_NONE,
+ ZENITY_TREE_LIST_CHECK,
+ ZENITY_TREE_LIST_RADIO,
+ ZENITY_TREE_LIST_IMAGE
+} ZenityTreeListType;
+
+/* ZenityTreeItem */
+
+#define ZENITY_TREE_TYPE_ITEM (zenity_tree_item_get_type ())
+G_DECLARE_FINAL_TYPE (ZenityTreeItem, zenity_tree_item, ZENITY_TREE, ITEM, GObject)
+
+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);
+
+/* ZenityTreeRow */
+
+#define ZENITY_TREE_TYPE_ROW (zenity_tree_row_get_type ())
+G_DECLARE_FINAL_TYPE (ZenityTreeRow, zenity_tree_row, ZENITY_TREE, ROW, GObject)
+
+ZenityTreeRow * zenity_tree_row_new (void);
+void zenity_tree_row_add (ZenityTreeRow *row, ZenityTreeItem *item);
+guint zenity_tree_row_get_n_items (ZenityTreeRow *row);
+ZenityTreeItem * zenity_tree_row_get_item (ZenityTreeRow *row, guint index);
+
+/* ZenityTreeColumnView */
+
+#define ZENITY_TREE_TYPE_COLUMN_VIEW (zenity_tree_column_view_get_type ())
+G_DECLARE_FINAL_TYPE (ZenityTreeColumnView, zenity_tree_column_view, ZENITY_TREE, COLUMN_VIEW, GtkWidget)
+
+void zenity_tree_column_view_set_model (ZenityTreeColumnView *self, GListModel *model);
+GListModel * zenity_tree_column_view_get_model (ZenityTreeColumnView *self);
+void zenity_tree_column_view_set_list_type (ZenityTreeColumnView *self, ZenityTreeListType type);
+ZenityTreeListType zenity_tree_column_view_get_list_type (ZenityTreeColumnView *self);
+void zenity_tree_column_view_add_column (ZenityTreeColumnView *self, const char *col_name);
+void zenity_tree_column_view_foreach_item (ZenityTreeColumnView *self, GFunc func, gpointer user_data);
+void zenity_tree_column_view_foreach_row (ZenityTreeColumnView *self, GFunc func, gpointer user_data);
+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);
+
+G_END_DECLS
diff --git a/src/zenity-tree-column-view.ui b/src/zenity-tree-column-view.ui
new file mode 100644
index 0000000..fcfdd28
--- /dev/null
+++ b/src/zenity-tree-column-view.ui
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- vim: ts=2 sw=2
+-->
+
+<interface>
+ <template class="ZenityTreeColumnView" parent="GtkWidget">
+ <child>
+ <object class="GtkScrolledWindow" id="scrolled_window">
+ <child>
+ <object class="GtkViewport">
+ <property name="scroll-to-focus">true</property> <!-- good to explicitly set to true for backwards compatibility, acc. to TFM. -->
+ <child>
+ <object class="GtkColumnView" id="child_cv" />
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/zenity.gresource.xml.in b/src/zenity.gresource.xml.in
index 4671d46..12e4b45 100644
--- a/src/zenity.gresource.xml.in
+++ b/src/zenity.gresource.xml.in
@@ -24,5 +24,6 @@
<gresources>
<gresource prefix="@resource_base_path@">
<file preprocess="xml-stripblanks" compressed="true">zenity.ui</file>
+ <file preprocess="xml-stripblanks" compressed="true">zenity-tree-column-view.ui</file>
</gresource>
</gresources>
diff --git a/src/zenity.h b/src/zenity.h
index 20cac9f..ac8b902 100644
--- a/src/zenity.h
+++ b/src/zenity.h
@@ -5,8 +5,6 @@
#include <adwaita.h>
#include <glib/gi18n.h>
-#include "zenity-enums.h" /* auto-generated by build system */
-
#include <config.h>
G_BEGIN_DECLS
@@ -121,7 +119,7 @@ typedef struct {
char *separator;
gboolean multi;
gboolean editable;
- gboolean mid_search;
+ gboolean mid_search_DEPRECATED;
char *print_column;
char *hide_column;
const char **data;
diff --git a/src/zenity.ui b/src/zenity.ui
index f2bb9b4..1f26eba 100644
--- a/src/zenity.ui
+++ b/src/zenity.ui
@@ -373,8 +373,8 @@
</object>
<object class="AdwMessageDialog" id="zenity_tree_dialog">
<property name="title" translatable="yes">Select items from the list</property>
- <property name="default_width">300</property>
- <property name="default_height">196</property>
+ <property name="default_width">480</property>
+ <property name="default_height">320</property>
<property name="extra-child">zenity_tree_box</property>
<property name="resizable">true</property>
<responses>
@@ -395,17 +395,7 @@
</object>
</child>
<child>
- <object class="GtkScrolledWindow" id="zenity_tree_window">
- <property name="hexpand">1</property>
- <property name="vexpand">1</property>
- <property name="child">
- <object class="GtkTreeView" id="zenity_tree_view">
- <child internal-child="selection">
- <object class="GtkTreeSelection" id="treeview-selection1"/>
- </child>
- </object>
- </property>
- </object>
+ <object class="ZenityTreeColumnView" id="zenity_tree_cv" />
</child>
</object>
</child>