mirror of
https://github.com/VibedByKaKi/yad.git
synced 2026-08-25 21:51:14 +02:00
1613 lines
47 KiB
C
1613 lines
47 KiB
C
/*
|
|
* This file is part of YAD.
|
|
*
|
|
* YAD is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* YAD is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with YAD. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Copyright (C) 2008-2025, Victor Ananjevsky <victor@sanana.kiev.ua>
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "yad.h"
|
|
|
|
static GtkWidget *list_view;
|
|
|
|
static GHashTable *row_hash = NULL;
|
|
|
|
static gint fore_col, back_col, font_col;
|
|
static guint n_cols = 0;
|
|
|
|
static gulong select_hndl = 0;
|
|
|
|
static gchar *column_align = NULL;
|
|
static gchar *header_align = NULL;
|
|
|
|
static inline void
|
|
yad_list_add_row (GtkTreeStore *m, GtkTreeIter *it, gchar *row_id, gchar *par_id)
|
|
{
|
|
GtkTreePath *row_path;
|
|
GtkTreeIter pit, *parent = NULL;
|
|
|
|
if (par_id && par_id[0])
|
|
{
|
|
GtkTreePath *par_path = g_hash_table_lookup (row_hash, par_id);
|
|
if (par_path)
|
|
{
|
|
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (m), &pit, par_path))
|
|
parent = &pit;
|
|
}
|
|
}
|
|
|
|
if (options.list_data.add_on_top)
|
|
gtk_tree_store_prepend (m, it, parent);
|
|
else
|
|
gtk_tree_store_append (m, it, parent);
|
|
|
|
row_path = gtk_tree_model_get_path (GTK_TREE_MODEL (m), it);
|
|
if (row_id && row_id[0])
|
|
g_hash_table_insert (row_hash, row_id, row_path);
|
|
if (options.common_data.tail)
|
|
gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (list_view), row_path, NULL, FALSE, 1.0, 1.0);
|
|
}
|
|
|
|
static gboolean
|
|
list_activate_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
|
|
{
|
|
if (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter)
|
|
{
|
|
if (options.action_data.dclick)
|
|
{
|
|
/* FIXME: check this under gtk-3.0 */
|
|
if (event->state & GDK_CONTROL_MASK)
|
|
{
|
|
if (options.plug == -1)
|
|
yad_exit (options.data.def_resp);
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (options.plug == -1)
|
|
yad_exit (options.data.def_resp);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* custom tooltip signal handler for no-markup mode */
|
|
static gboolean
|
|
tooltip_cb (GtkWidget *w, gint x, gint y, gboolean mode, GtkTooltip *tip, gpointer data)
|
|
{
|
|
gchar *str;
|
|
gint bx, by;
|
|
GtkTreePath *path;
|
|
GtkTreeIter iter;
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (w));
|
|
|
|
gtk_tree_view_convert_widget_to_bin_window_coords (GTK_TREE_VIEW (w), x, y, &bx, &by);
|
|
if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (w), bx, by, &path, NULL, NULL, NULL))
|
|
return FALSE;
|
|
|
|
gtk_tree_model_get_iter (model, &iter, path);
|
|
gtk_tree_path_free (path);
|
|
|
|
gtk_tree_model_get (model, &iter, options.list_data.tooltip_column - 1, &str, -1);
|
|
if (str)
|
|
{
|
|
gtk_tooltip_set_text (tip, str);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
toggled_cb (GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
|
|
{
|
|
gint column;
|
|
gboolean fixed;
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
|
|
column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));
|
|
gtk_tree_model_get_iter (model, &iter, path);
|
|
gtk_tree_model_get (model, &iter, column, &fixed, -1);
|
|
|
|
fixed ^= 1;
|
|
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column, fixed, -1);
|
|
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
static gboolean
|
|
runtoggle (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
|
|
{
|
|
gint col = GPOINTER_TO_INT (data);
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), iter, col, FALSE, -1);
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
rtoggled_cb (GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
|
|
{
|
|
gint column;
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
|
|
column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));
|
|
|
|
gtk_tree_model_foreach (model, runtoggle, GINT_TO_POINTER (column));
|
|
|
|
gtk_tree_model_get_iter (model, &iter, path);
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column, TRUE, -1);
|
|
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
static void
|
|
cell_edited_cb (GtkCellRendererText *cell, const gchar *path_string, const gchar *new_text, gpointer data)
|
|
{
|
|
gint column;
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
YadColumn *col;
|
|
|
|
column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));
|
|
gtk_tree_model_get_iter (model, &iter, path);
|
|
col = (YadColumn *) g_slist_nth_data (options.list_data.columns, column);
|
|
|
|
if (col->type == YAD_COLUMN_NUM)
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column, g_ascii_strtoll (new_text, NULL, 10), -1);
|
|
else if (col->type == YAD_COLUMN_FLOAT)
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column, g_ascii_strtod (new_text, NULL), -1);
|
|
else
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column, new_text, -1);
|
|
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
static gboolean
|
|
regex_search (GtkTreeModel *model, gint col, const gchar *key, GtkTreeIter *iter, gpointer data)
|
|
{
|
|
static GRegex *pattern = NULL;
|
|
static guint pos = 0;
|
|
gchar *str;
|
|
|
|
if (key[pos])
|
|
{
|
|
if (pattern)
|
|
g_regex_unref (pattern);
|
|
pattern = g_regex_new (key, G_REGEX_CASELESS | G_REGEX_EXTENDED | G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, NULL);
|
|
pos = strlen (key);
|
|
}
|
|
|
|
if (pattern)
|
|
{
|
|
gboolean ret;
|
|
|
|
gtk_tree_model_get (model, iter, col, &str, -1);
|
|
|
|
ret = g_regex_match (pattern, str, G_REGEX_MATCH_NOTEMPTY, NULL);
|
|
/* if get it, clear key end position */
|
|
if (!ret)
|
|
pos = 0;
|
|
|
|
return !ret;
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
static GtkTreeModel *
|
|
create_model ()
|
|
{
|
|
GtkTreeStore *store;
|
|
GType *ctypes;
|
|
gint i;
|
|
|
|
ctypes = g_new0 (GType, n_cols);
|
|
|
|
if (options.list_data.checkbox)
|
|
{
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, 0);
|
|
col->type = YAD_COLUMN_CHECK;
|
|
}
|
|
else if (options.list_data.radiobox)
|
|
{
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, 0);
|
|
col->type = YAD_COLUMN_RADIO;
|
|
}
|
|
|
|
for (i = 0; i < n_cols; i++)
|
|
{
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, i);
|
|
|
|
switch (col->type)
|
|
{
|
|
case YAD_COLUMN_CHECK:
|
|
case YAD_COLUMN_RADIO:
|
|
ctypes[i] = G_TYPE_BOOLEAN;
|
|
break;
|
|
case YAD_COLUMN_NUM:
|
|
case YAD_COLUMN_SIZE:
|
|
case YAD_COLUMN_BAR:
|
|
ctypes[i] = G_TYPE_INT64;
|
|
break;
|
|
case YAD_COLUMN_FLOAT:
|
|
ctypes[i] = G_TYPE_DOUBLE;
|
|
break;
|
|
case YAD_COLUMN_IMAGE:
|
|
ctypes[i] = GDK_TYPE_PIXBUF;
|
|
break;
|
|
case YAD_COLUMN_ATTR_FORE:
|
|
ctypes[i] = G_TYPE_STRING;
|
|
fore_col = i;
|
|
break;
|
|
case YAD_COLUMN_ATTR_BACK:
|
|
ctypes[i] = G_TYPE_STRING;
|
|
back_col = i;
|
|
break;
|
|
case YAD_COLUMN_ATTR_FONT:
|
|
ctypes[i] = G_TYPE_STRING;
|
|
font_col = i;
|
|
break;
|
|
default:
|
|
ctypes[i] = G_TYPE_STRING;
|
|
break;
|
|
}
|
|
}
|
|
|
|
store = gtk_tree_store_newv (n_cols, ctypes);
|
|
|
|
return GTK_TREE_MODEL (store);
|
|
}
|
|
|
|
static void
|
|
float_col_format (GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *model,
|
|
GtkTreeIter *iter, gpointer data)
|
|
{
|
|
gdouble val;
|
|
gchar buf[20];
|
|
|
|
gtk_tree_model_get (model, iter, GPOINTER_TO_INT (data), &val, -1);
|
|
g_snprintf (buf, sizeof (buf), "%.*f", options.common_data.float_precision, val);
|
|
g_object_set (cell, "text", buf, NULL);
|
|
}
|
|
|
|
static void
|
|
size_col_format (GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *model,
|
|
GtkTreeIter *iter, gpointer data)
|
|
{
|
|
guint64 val;
|
|
gchar buf[20], *sz;
|
|
|
|
gtk_tree_model_get (model, iter, GPOINTER_TO_INT (data), &val, -1);
|
|
#if GLIB_CHECK_VERSION(2,30,0)
|
|
sz = g_format_size_full (val, options.common_data.size_fmt);
|
|
#elif GLIB_CHECK_VERSION(2,16,0)
|
|
sz = g_format_size_for_display (val);
|
|
#else
|
|
sz = g_strdup_printf ("%d", val);
|
|
#endif
|
|
g_snprintf (buf, sizeof (buf), "%s", sz);
|
|
g_free (sz);
|
|
g_object_set (cell, "text", buf, NULL);
|
|
}
|
|
|
|
static void
|
|
set_column_title (GtkTreeViewColumn *col, gchar *title)
|
|
{
|
|
GtkWidget *lbl;
|
|
gchar **str;
|
|
|
|
str = g_strsplit (title, options.common_data.item_separator, 2);
|
|
lbl = gtk_label_new (NULL);
|
|
|
|
if (options.data.no_markup)
|
|
{
|
|
gtk_label_set_text (GTK_LABEL (lbl), str[0]);
|
|
if (str[1] || options.list_data.header_tips)
|
|
gtk_widget_set_tooltip_text (lbl, str[1] ? str[1] : str[0]);
|
|
}
|
|
else
|
|
{
|
|
gtk_label_set_markup (GTK_LABEL (lbl), str[0]);
|
|
if (str[1] || options.list_data.header_tips)
|
|
gtk_widget_set_tooltip_markup (lbl, str[1] ? str[1] : str[0]);
|
|
}
|
|
|
|
gtk_widget_show (lbl);
|
|
gtk_tree_view_column_set_widget (col, lbl);
|
|
}
|
|
|
|
static void
|
|
add_columns ()
|
|
{
|
|
gint i;
|
|
GtkCellRenderer *renderer;
|
|
GtkTreeViewColumn *column;
|
|
|
|
for (i = 0; i < n_cols; i++)
|
|
{
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, i);
|
|
|
|
if (i == options.list_data.hide_column - 1 || col->type == YAD_COLUMN_HIDDEN ||
|
|
i == fore_col || i == back_col || i == font_col)
|
|
continue;
|
|
|
|
switch (col->type)
|
|
{
|
|
case YAD_COLUMN_CHECK:
|
|
case YAD_COLUMN_RADIO:
|
|
renderer = gtk_cell_renderer_toggle_new ();
|
|
column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "active", i, NULL);
|
|
set_column_title (column, col->name);
|
|
if (back_col != -1)
|
|
gtk_tree_view_column_add_attribute (column, renderer, "cell-background", back_col);
|
|
if (col->type == YAD_COLUMN_RADIO)
|
|
{
|
|
gtk_cell_renderer_toggle_set_radio (GTK_CELL_RENDERER_TOGGLE (renderer), TRUE);
|
|
g_signal_connect (renderer, "toggled", G_CALLBACK (rtoggled_cb), NULL);
|
|
}
|
|
else
|
|
g_signal_connect (renderer, "toggled", G_CALLBACK (toggled_cb), NULL);
|
|
break;
|
|
case YAD_COLUMN_IMAGE:
|
|
renderer = gtk_cell_renderer_pixbuf_new ();
|
|
column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "pixbuf", i, NULL);
|
|
set_column_title (column, col->name);
|
|
if (back_col != -1)
|
|
gtk_tree_view_column_add_attribute (column, renderer, "cell-background", back_col);
|
|
break;
|
|
case YAD_COLUMN_NUM:
|
|
case YAD_COLUMN_SIZE:
|
|
case YAD_COLUMN_FLOAT:
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
if (col->editable)
|
|
{
|
|
g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
|
|
g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited_cb), NULL);
|
|
}
|
|
column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "text", i, NULL);
|
|
set_column_title (column, col->name);
|
|
if (fore_col != -1)
|
|
gtk_tree_view_column_add_attribute (column, renderer, "foreground", fore_col);
|
|
if (back_col != -1)
|
|
gtk_tree_view_column_add_attribute (column, renderer, "cell-background", back_col);
|
|
if (font_col != -1)
|
|
gtk_tree_view_column_add_attribute (column, renderer, "font", font_col);
|
|
gtk_tree_view_column_set_sort_column_id (column, i);
|
|
gtk_tree_view_column_set_resizable (column, TRUE);
|
|
if (col->type == YAD_COLUMN_FLOAT)
|
|
gtk_tree_view_column_set_cell_data_func (column, renderer, float_col_format, GINT_TO_POINTER (i), NULL);
|
|
else if (col->type == YAD_COLUMN_SIZE)
|
|
gtk_tree_view_column_set_cell_data_func (column, renderer, size_col_format, GINT_TO_POINTER (i), NULL);
|
|
break;
|
|
case YAD_COLUMN_BAR:
|
|
renderer = gtk_cell_renderer_progress_new ();
|
|
column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "value", i, NULL);
|
|
set_column_title (column, col->name);
|
|
if (back_col != -1)
|
|
gtk_tree_view_column_add_attribute (column, renderer, "cell-background", back_col);
|
|
gtk_tree_view_column_set_sort_column_id (column, i);
|
|
gtk_tree_view_column_set_resizable (column, TRUE);
|
|
break;
|
|
default:
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
if (col->editable)
|
|
{
|
|
g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
|
|
g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited_cb), NULL);
|
|
}
|
|
if (options.data.no_markup)
|
|
column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "text", i, NULL);
|
|
else
|
|
column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "markup", i, NULL);
|
|
set_column_title (column, col->name);
|
|
if (col->ellipsize)
|
|
g_object_set (G_OBJECT (renderer), "ellipsize", options.list_data.ellipsize, NULL);
|
|
if (col->wrap)
|
|
{
|
|
g_object_set (G_OBJECT (renderer), "wrap-width", options.list_data.wrap_width, NULL);
|
|
g_object_set (G_OBJECT (renderer), "wrap-mode", PANGO_WRAP_WORD_CHAR, NULL);
|
|
}
|
|
if (fore_col != -1)
|
|
gtk_tree_view_column_add_attribute (column, renderer, "foreground", fore_col);
|
|
if (back_col != -1)
|
|
gtk_tree_view_column_add_attribute (column, renderer, "cell-background", back_col);
|
|
if (font_col != -1)
|
|
gtk_tree_view_column_add_attribute (column, renderer, "font", font_col);
|
|
gtk_tree_view_column_set_sort_column_id (column, i);
|
|
gtk_tree_view_column_set_resizable (column, TRUE);
|
|
|
|
if (col->type == YAD_COLUMN_TIP)
|
|
options.list_data.tooltip_column = i + 1;
|
|
break;
|
|
}
|
|
|
|
gtk_cell_renderer_set_alignment (renderer, col->c_align, 0.5);
|
|
g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (i));
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
|
|
|
|
gtk_tree_view_column_set_clickable (column, options.list_data.clickable);
|
|
gtk_tree_view_column_set_alignment (column, col->h_align);
|
|
|
|
if (col->type != YAD_COLUMN_CHECK && col->type != YAD_COLUMN_IMAGE)
|
|
{
|
|
if (i == options.list_data.expand_column - 1 || options.list_data.expand_column == 0)
|
|
gtk_tree_view_column_set_expand (column, TRUE);
|
|
}
|
|
}
|
|
|
|
if (options.list_data.checkbox && !options.list_data.search_column)
|
|
options.list_data.search_column += 1;
|
|
if (options.list_data.search_column <= n_cols)
|
|
{
|
|
options.list_data.search_column -= 1;
|
|
gtk_tree_view_set_search_column (GTK_TREE_VIEW (list_view), options.list_data.search_column);
|
|
}
|
|
}
|
|
|
|
static void
|
|
cell_set_data (GtkTreeIter *it, guint num, gchar *data)
|
|
{
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num);
|
|
|
|
switch (col->type)
|
|
{
|
|
case YAD_COLUMN_CHECK:
|
|
case YAD_COLUMN_RADIO:
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), it, num, get_bool_val (data), -1);
|
|
break;
|
|
case YAD_COLUMN_NUM:
|
|
case YAD_COLUMN_SIZE:
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), it, num, g_ascii_strtoll (data, NULL, 10), -1);
|
|
break;
|
|
case YAD_COLUMN_FLOAT:
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), it, num, g_ascii_strtod (data, NULL), -1);
|
|
break;
|
|
case YAD_COLUMN_BAR:
|
|
{
|
|
gint64 val = g_ascii_strtoll (data, NULL, 10);
|
|
if (val < 0)
|
|
val = 0;
|
|
if (val > 100)
|
|
val = 100;
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), it, num, val, -1);
|
|
break;
|
|
}
|
|
case YAD_COLUMN_IMAGE:
|
|
{
|
|
GdkPixbuf *pb;
|
|
|
|
if (g_file_test (data, G_FILE_TEST_EXISTS))
|
|
pb = get_pixbuf (data, YAD_SMALL_ICON, FALSE);
|
|
else
|
|
pb = get_pixbuf (data, YAD_SMALL_ICON, TRUE);
|
|
if (pb)
|
|
{
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), it, num, pb, -1);
|
|
g_object_unref (pb);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
if (data && *data)
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), it, num, data, -1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gchar *
|
|
cell_get_data (GtkTreeIter *it, guint num)
|
|
{
|
|
gchar *data = NULL;
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num);
|
|
|
|
switch (col->type)
|
|
{
|
|
case YAD_COLUMN_CHECK:
|
|
case YAD_COLUMN_RADIO:
|
|
{
|
|
gboolean bval;
|
|
gtk_tree_model_get (model, it, num, &bval, -1);
|
|
data = g_strdup (print_bool_val (bval));
|
|
break;
|
|
}
|
|
case YAD_COLUMN_NUM:
|
|
case YAD_COLUMN_SIZE:
|
|
case YAD_COLUMN_BAR:
|
|
{
|
|
gint64 nval;
|
|
gtk_tree_model_get (model, it, num, &nval, -1);
|
|
data = g_strdup_printf ("%ld", (long) nval);
|
|
break;
|
|
}
|
|
case YAD_COLUMN_FLOAT:
|
|
{
|
|
gdouble nval;
|
|
gtk_tree_model_get (model, it, num, &nval, -1);
|
|
data = g_strdup_printf ("%lf", nval);
|
|
break;
|
|
}
|
|
case YAD_COLUMN_IMAGE:
|
|
{
|
|
data = g_strdup ("''");
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
gchar *cval;
|
|
gtk_tree_model_get (model, it, num, &cval, -1);
|
|
if (cval)
|
|
data = g_shell_quote (cval);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
static gboolean
|
|
handle_stdin (GIOChannel *channel, GIOCondition condition, gpointer data)
|
|
{
|
|
static GtkTreeIter iter;
|
|
static gulong column_count = 0;
|
|
static gulong row_count = 0;
|
|
static gboolean node_added = FALSE;
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
|
|
if ((condition == G_IO_IN) || (condition == G_IO_IN + G_IO_HUP))
|
|
{
|
|
GError *err = NULL;
|
|
GString *string = g_string_new (NULL);
|
|
|
|
while (channel->is_readable != TRUE)
|
|
usleep (100);
|
|
|
|
do
|
|
{
|
|
gint status;
|
|
|
|
do
|
|
{
|
|
status = g_io_channel_read_line_string (channel, string, NULL, &err);
|
|
}
|
|
while (status == G_IO_STATUS_AGAIN);
|
|
|
|
if (status != G_IO_STATUS_NORMAL)
|
|
{
|
|
if (err)
|
|
{
|
|
g_printerr ("yad_list_handle_stdin(): %s\n", err->message);
|
|
g_error_free (err);
|
|
err = NULL;
|
|
}
|
|
/* stop handling */
|
|
g_io_channel_shutdown (channel, TRUE, NULL);
|
|
return FALSE;
|
|
}
|
|
|
|
strip_new_line (string->str);
|
|
|
|
/* clear list if ^L received */
|
|
if (string->str[0] == '\014')
|
|
{
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
|
|
if (select_hndl)
|
|
g_signal_handler_block (G_OBJECT (sel), select_hndl);
|
|
gtk_tree_store_clear (GTK_TREE_STORE (model));
|
|
row_count = column_count = 0;
|
|
if (row_hash)
|
|
g_hash_table_remove_all (row_hash);
|
|
if (select_hndl)
|
|
g_signal_handler_unblock (G_OBJECT (sel), select_hndl);
|
|
continue;
|
|
}
|
|
|
|
if (row_count == 0 && column_count == 0)
|
|
{
|
|
if (options.list_data.tree_mode)
|
|
{
|
|
if (!node_added)
|
|
{
|
|
gchar **ids = g_strsplit (string->str, ":", 2);
|
|
yad_list_add_row (GTK_TREE_STORE (model), &iter, ids[0], ids[1]);
|
|
node_added = TRUE;
|
|
continue;
|
|
}
|
|
else
|
|
node_added = FALSE;
|
|
}
|
|
else
|
|
yad_list_add_row (GTK_TREE_STORE (model), &iter, NULL, NULL);
|
|
}
|
|
else if (column_count == n_cols)
|
|
{
|
|
/* We're starting a new row */
|
|
if (options.list_data.tree_mode)
|
|
{
|
|
if (!node_added)
|
|
{
|
|
gchar **ids = g_strsplit (string->str, ":", 2);
|
|
yad_list_add_row (GTK_TREE_STORE (model), &iter, ids[0], ids[1]);
|
|
node_added = TRUE;
|
|
continue;
|
|
}
|
|
else
|
|
node_added = FALSE;
|
|
}
|
|
else
|
|
yad_list_add_row (GTK_TREE_STORE (model), &iter, NULL, NULL);
|
|
column_count = 0;
|
|
row_count++;
|
|
if (options.list_data.limit && row_count >= options.list_data.limit)
|
|
{
|
|
gtk_tree_model_get_iter_first (model, &iter);
|
|
gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
|
|
}
|
|
}
|
|
|
|
cell_set_data (&iter, column_count, string->str);
|
|
column_count++;
|
|
}
|
|
while (g_io_channel_get_buffer_condition (channel) == G_IO_IN);
|
|
g_string_free (string, TRUE);
|
|
}
|
|
|
|
if (options.list_data.tree_expanded)
|
|
gtk_tree_view_expand_all (GTK_TREE_VIEW (list_view));
|
|
|
|
if ((condition != G_IO_IN) && (condition != G_IO_IN + G_IO_HUP))
|
|
{
|
|
g_io_channel_shutdown (channel, TRUE, NULL);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
fill_data ()
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreeStore *model = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (list_view)));
|
|
GIOChannel *channel;
|
|
|
|
if (options.extra_data && *options.extra_data)
|
|
{
|
|
gchar **args = options.extra_data;
|
|
gint i = 0;
|
|
|
|
gtk_widget_freeze_child_notify (list_view);
|
|
|
|
while (args[i] != NULL)
|
|
{
|
|
gint j;
|
|
|
|
if (options.list_data.tree_mode)
|
|
{
|
|
gchar **ids = g_strsplit (args[i], ":", 2);
|
|
yad_list_add_row (model, &iter, ids[0], ids[1]);
|
|
i++;
|
|
}
|
|
else
|
|
yad_list_add_row (model, &iter, NULL, NULL);
|
|
for (j = 0; j < n_cols; j++, i++)
|
|
{
|
|
if (args[i] == NULL)
|
|
break;
|
|
|
|
cell_set_data (&iter, j, args[i]);
|
|
}
|
|
}
|
|
|
|
gtk_widget_thaw_child_notify (list_view);
|
|
}
|
|
|
|
if (options.common_data.listen || !(options.extra_data && *options.extra_data))
|
|
{
|
|
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, handle_stdin, NULL);
|
|
}
|
|
}
|
|
|
|
static gchar *
|
|
get_data_as_string (GtkTreeIter *iter)
|
|
{
|
|
GString *str;
|
|
gchar *res;
|
|
guint i;
|
|
|
|
str = g_string_new (NULL);
|
|
|
|
for (i = 0; i < n_cols; i++)
|
|
{
|
|
gchar *val = cell_get_data (iter, i);
|
|
if (val)
|
|
{
|
|
g_string_append_printf (str, "%s ", val);
|
|
g_free (val);
|
|
}
|
|
}
|
|
|
|
str->str[str->len-1] = '\0';
|
|
#if GLIB_CHECK_VERSION(2,76,0)
|
|
res = g_string_free_and_steal (str);
|
|
#else
|
|
res = g_string_free (str, FALSE);
|
|
#endif
|
|
|
|
return res;
|
|
}
|
|
|
|
static void edit_row_cb (GtkMenuItem *item, gpointer data);
|
|
|
|
static void
|
|
double_click_cb (GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer d)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
|
|
model = gtk_tree_view_get_model (view);
|
|
|
|
if (options.action_data.dclick)
|
|
{
|
|
gchar *cmd, *args = NULL;
|
|
|
|
if (gtk_tree_model_get_iter (model, &iter, path))
|
|
args = get_data_as_string (&iter);
|
|
else
|
|
args = g_strdup ("");
|
|
|
|
if (g_strstr_len (options.action_data.dclick, -1, "%s"))
|
|
{
|
|
static GRegex *regex = NULL;
|
|
|
|
if (!regex)
|
|
regex = g_regex_new ("\%s", G_REGEX_OPTIMIZE, 0, NULL);
|
|
cmd = g_regex_replace_literal (regex, options.action_data.dclick, -1, 0, args, 0, NULL);
|
|
}
|
|
else
|
|
cmd = g_strdup_printf ("%s %s", options.action_data.dclick, args);
|
|
g_free (args);
|
|
|
|
if (cmd[0] == '@')
|
|
{
|
|
gchar *data = NULL;
|
|
gint exit;
|
|
|
|
exit = run_command_sync (cmd + 1, &data);
|
|
if (exit == 0)
|
|
{
|
|
gint i;
|
|
gchar **lines = g_strsplit (data, "\n", 0);
|
|
|
|
for (i = 0; i < n_cols; i++)
|
|
{
|
|
if (lines[i] == NULL)
|
|
break;
|
|
|
|
cell_set_data (&iter, i, lines[i]);
|
|
}
|
|
g_strfreev (lines);
|
|
}
|
|
g_free (data);
|
|
}
|
|
else
|
|
run_command_async (cmd);
|
|
|
|
g_free (cmd);
|
|
}
|
|
else if (options.common_data.editable && options.action_data.row)
|
|
edit_row_cb (NULL, NULL);
|
|
else
|
|
{
|
|
if (options.list_data.checkbox)
|
|
{
|
|
if (gtk_tree_model_get_iter (model, &iter, path))
|
|
{
|
|
gboolean chk;
|
|
|
|
gtk_tree_model_get (model, &iter, 0, &chk, -1);
|
|
chk = !chk;
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, chk, -1);
|
|
}
|
|
}
|
|
else if (options.list_data.radiobox)
|
|
{
|
|
if (gtk_tree_model_get_iter (model, &iter, path))
|
|
{
|
|
gtk_tree_model_foreach (model, runtoggle, GINT_TO_POINTER (0));
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, TRUE, -1);
|
|
}
|
|
}
|
|
else if (options.plug == -1)
|
|
yad_exit (options.data.def_resp);
|
|
}
|
|
}
|
|
|
|
static void
|
|
select_cb (GtkTreeSelection *sel, gpointer data)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
gchar *cmd, *args;
|
|
|
|
if (!gtk_tree_selection_get_selected (sel, &model, &iter))
|
|
return;
|
|
|
|
args = get_data_as_string (&iter);
|
|
if (!args)
|
|
args = g_strdup ("");
|
|
|
|
if (g_strstr_len (options.action_data.select, -1, "%s"))
|
|
{
|
|
static GRegex *regex = NULL;
|
|
|
|
if (!regex)
|
|
regex = g_regex_new ("\%s", G_REGEX_OPTIMIZE, 0, NULL);
|
|
cmd = g_regex_replace_literal (regex, options.action_data.select, -1, 0, args, 0, NULL);
|
|
}
|
|
else
|
|
cmd = g_strdup_printf ("%s %s", options.action_data.select, args);
|
|
g_free (args);
|
|
|
|
run_command_async (cmd);
|
|
|
|
g_free (cmd);
|
|
}
|
|
|
|
static void
|
|
add_row_cb (GtkMenuItem *item, gpointer data)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
gchar *cmd;
|
|
|
|
model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
if (g_object_get_data (G_OBJECT (item), "child") != NULL)
|
|
{
|
|
GtkTreeIter parent;
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
|
|
|
|
if (gtk_tree_selection_get_selected (sel, NULL, &parent))
|
|
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent);
|
|
else
|
|
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
|
|
}
|
|
else
|
|
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
|
|
|
|
if (options.action_data.row)
|
|
{
|
|
gchar *out = NULL;
|
|
gint exit;
|
|
|
|
/* hide menu first */
|
|
if (data)
|
|
{
|
|
gtk_menu_popdown (GTK_MENU (data));
|
|
while (gtk_events_pending ())
|
|
gtk_main_iteration ();
|
|
}
|
|
|
|
/* run command */
|
|
cmd = g_strdup_printf ("%s add", options.action_data.row);
|
|
exit = run_command_sync (cmd, &out);
|
|
g_free (cmd);
|
|
if (exit == 0)
|
|
{
|
|
guint i;
|
|
gchar **lines = g_strsplit (out, "\n", 0);
|
|
|
|
for (i = 0; i < n_cols; i++)
|
|
{
|
|
if (lines[i] == NULL)
|
|
break;
|
|
|
|
cell_set_data (&iter, i, lines[i]);
|
|
}
|
|
g_strfreev (lines);
|
|
}
|
|
g_free (out);
|
|
}
|
|
}
|
|
|
|
static void
|
|
edit_row_cb (GtkMenuItem *item, gpointer data)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
|
|
|
|
if (!gtk_tree_selection_get_selected (sel, NULL, &iter))
|
|
return;
|
|
|
|
if (options.action_data.row)
|
|
{
|
|
gchar *cmd, *args, *out = NULL;
|
|
gint exit;
|
|
|
|
/* hide menu first */
|
|
if (data)
|
|
{
|
|
gtk_menu_popdown (GTK_MENU (data));
|
|
while (gtk_events_pending ())
|
|
gtk_main_iteration ();
|
|
}
|
|
|
|
/* run command */
|
|
args = get_data_as_string (&iter);
|
|
cmd = g_strdup_printf ("%s edit %s", options.action_data.row, args);
|
|
g_free (args);
|
|
exit = run_command_sync (cmd, &out);
|
|
g_free (cmd);
|
|
if (exit == 0)
|
|
{
|
|
guint i;
|
|
gchar **lines = g_strsplit (out, "\n", 0);
|
|
|
|
for (i = 0; i < n_cols; i++)
|
|
{
|
|
if (lines[i] == NULL)
|
|
break;
|
|
|
|
cell_set_data (&iter, i, lines[i]);
|
|
}
|
|
g_strfreev (lines);
|
|
}
|
|
g_free (out);
|
|
}
|
|
}
|
|
|
|
static void
|
|
del_row_cb (GtkMenuItem *item, gpointer data)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
|
|
|
|
if (gtk_tree_selection_get_selected (sel, NULL, &iter))
|
|
{
|
|
if (options.action_data.row)
|
|
{
|
|
gchar *cmd, *args;
|
|
gint exit;
|
|
|
|
/* hide menu first */
|
|
gtk_menu_popdown (GTK_MENU (data));
|
|
while (gtk_events_pending ())
|
|
gtk_main_iteration ();
|
|
|
|
/* run command */
|
|
args = get_data_as_string (&iter);
|
|
cmd = g_strdup_printf ("%s del %s", options.action_data.row, args);
|
|
g_free (args);
|
|
exit = run_command_sync (cmd, NULL);
|
|
g_free (cmd);
|
|
if (exit == 0)
|
|
gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
|
|
}
|
|
else
|
|
gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
|
|
}
|
|
}
|
|
|
|
static void
|
|
copy_row_cb (GtkMenuItem *item, gpointer data)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
|
|
|
|
if (gtk_tree_selection_get_selected (sel, NULL, &iter))
|
|
{
|
|
GtkTreeIter new_iter, parent;
|
|
gint i;
|
|
|
|
if (gtk_tree_model_iter_parent (model, &parent, &iter))
|
|
gtk_tree_store_insert_after (GTK_TREE_STORE (model), &new_iter, &parent, &iter);
|
|
else
|
|
gtk_tree_store_insert_after (GTK_TREE_STORE (model), &new_iter, NULL, &iter);
|
|
|
|
for (i = 0; i < n_cols; i++)
|
|
{
|
|
GdkPixbuf *pb;
|
|
gchar *tv;
|
|
gint64 iv;
|
|
gfloat fv;
|
|
gboolean bv;
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, i);
|
|
|
|
switch (col->type)
|
|
{
|
|
case YAD_COLUMN_CHECK:
|
|
case YAD_COLUMN_RADIO:
|
|
gtk_tree_model_get (model, &iter, i, &bv, -1);
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, i, bv, -1);
|
|
break;
|
|
case YAD_COLUMN_NUM:
|
|
case YAD_COLUMN_SIZE:
|
|
case YAD_COLUMN_BAR:
|
|
gtk_tree_model_get (model, &iter, i, &iv, -1);
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, i, iv, -1);
|
|
break;
|
|
case YAD_COLUMN_FLOAT:
|
|
gtk_tree_model_get (model, &iter, i, &fv, -1);
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, i, fv, -1);
|
|
break;
|
|
case YAD_COLUMN_IMAGE:
|
|
gtk_tree_model_get (model, &iter, i, &pb, -1);
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, i, g_object_ref (pb), -1);
|
|
break;
|
|
default:
|
|
gtk_tree_model_get (model, &iter, i, &tv, -1);
|
|
gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, i, g_strdup (tv), -1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
move_row_up_cb (GtkMenuItem *item, gpointer data)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
|
|
|
|
if (gtk_tree_selection_get_selected (sel, NULL, &iter))
|
|
{
|
|
GtkTreeIter *prev = gtk_tree_iter_copy (&iter);
|
|
if (gtk_tree_model_iter_previous (model, prev))
|
|
gtk_tree_store_move_before (GTK_TREE_STORE (model), &iter, prev);
|
|
gtk_tree_iter_free (prev);
|
|
}
|
|
}
|
|
|
|
static void
|
|
move_row_down_cb (GtkMenuItem *item, gpointer data)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
|
|
|
|
if (gtk_tree_selection_get_selected (sel, NULL, &iter))
|
|
{
|
|
GtkTreeIter *next = gtk_tree_iter_copy (&iter);
|
|
if (gtk_tree_model_iter_next (model, next))
|
|
gtk_tree_store_move_after (GTK_TREE_STORE (model), &iter, next);
|
|
gtk_tree_iter_free (next);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
popup_menu_cb (GtkWidget *w, GdkEventButton *ev, gpointer data)
|
|
{
|
|
static GtkWidget *menu = NULL;
|
|
if (ev->button == 3)
|
|
{
|
|
GtkWidget *item;
|
|
|
|
if (menu == NULL)
|
|
{
|
|
menu = gtk_menu_new ();
|
|
gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE);
|
|
|
|
item = gtk_menu_item_new_with_label (_("Add row"));
|
|
gtk_widget_show (item);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (add_row_cb), menu);
|
|
|
|
if (options.list_data.tree_mode)
|
|
{
|
|
item = gtk_menu_item_new_with_label (_("Add child row"));
|
|
gtk_widget_show (item);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
g_object_set_data (G_OBJECT (item), "child", "1");
|
|
g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (add_row_cb), menu);
|
|
}
|
|
|
|
item = gtk_menu_item_new_with_label (_("Delete row"));
|
|
gtk_widget_show (item);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (del_row_cb), menu);
|
|
|
|
if (options.action_data.row)
|
|
{
|
|
item = gtk_menu_item_new_with_label (_("Edit row"));
|
|
gtk_widget_show (item);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (edit_row_cb), menu);
|
|
}
|
|
|
|
item = gtk_menu_item_new_with_label (_("Duplicate row"));
|
|
gtk_widget_show (item);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (copy_row_cb), menu);
|
|
|
|
item = gtk_separator_menu_item_new ();
|
|
gtk_widget_show (item);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
|
|
item = gtk_menu_item_new_with_label (_("Move row up"));
|
|
gtk_widget_show (item);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (move_row_up_cb), menu);
|
|
|
|
item = gtk_menu_item_new_with_label (_("Move row down"));
|
|
gtk_widget_show (item);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (move_row_down_cb), menu);
|
|
|
|
gtk_widget_show (menu);
|
|
}
|
|
gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
row_sep_func (GtkTreeModel *m, GtkTreeIter *it, gpointer data)
|
|
{
|
|
gchar *name;
|
|
|
|
if (!options.list_data.sep_value)
|
|
return FALSE;
|
|
|
|
gtk_tree_model_get (m, it, options.list_data.sep_column - 1, &name, -1);
|
|
return (name && strcmp (name, options.list_data.sep_value) == 0);
|
|
}
|
|
|
|
static inline void
|
|
parse_cols_props ()
|
|
{
|
|
GSList *c;
|
|
guint i;
|
|
|
|
/* set editable property for columns */
|
|
if (options.common_data.editable)
|
|
{
|
|
if (options.list_data.editable_cols)
|
|
{
|
|
gchar **cnum;
|
|
|
|
i = 0;
|
|
cnum = g_strsplit (options.list_data.editable_cols, ",", -1);
|
|
|
|
while (cnum[i])
|
|
{
|
|
gint num = atoi (cnum[i]);
|
|
if (num)
|
|
{
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num - 1);
|
|
if (col)
|
|
col->editable = TRUE;
|
|
}
|
|
i++;
|
|
}
|
|
g_strfreev (cnum);
|
|
}
|
|
else
|
|
{
|
|
for (c = options.list_data.columns; c; c = c->next)
|
|
{
|
|
YadColumn *col = (YadColumn *) c->data;
|
|
col->editable = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* set wrap property for columns */
|
|
if (options.list_data.wrap_width > 0)
|
|
{
|
|
if (options.list_data.wrap_cols)
|
|
{
|
|
gchar **cnum;
|
|
|
|
i = 0;
|
|
cnum = g_strsplit (options.list_data.wrap_cols, ",", -1);
|
|
|
|
while (cnum[i])
|
|
{
|
|
gint num = atoi (cnum[i]);
|
|
if (num)
|
|
{
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num - 1);
|
|
if (col)
|
|
col->wrap = TRUE;
|
|
}
|
|
i++;
|
|
}
|
|
g_strfreev (cnum);
|
|
}
|
|
else
|
|
{
|
|
for (c = options.list_data.columns; c; c = c->next)
|
|
{
|
|
YadColumn *col = (YadColumn *) c->data;
|
|
col->wrap = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* set ellipsize property for columns */
|
|
if (options.list_data.ellipsize)
|
|
{
|
|
if (options.list_data.ellipsize_cols)
|
|
{
|
|
gchar **cnum;
|
|
|
|
i = 0;
|
|
cnum = g_strsplit (options.list_data.ellipsize_cols, ",", -1);
|
|
|
|
while (cnum[i])
|
|
{
|
|
gint num = atoi (cnum[i]);
|
|
if (num)
|
|
{
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num - 1);
|
|
if (col)
|
|
col->ellipsize = TRUE;
|
|
}
|
|
i++;
|
|
}
|
|
g_strfreev (cnum);
|
|
}
|
|
else
|
|
{
|
|
for (c = options.list_data.columns; c; c = c->next)
|
|
{
|
|
YadColumn *col = (YadColumn *) c->data;
|
|
col->ellipsize = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* set alignment */
|
|
i = 0;
|
|
for (c = options.list_data.columns; c; c = c->next)
|
|
{
|
|
YadColumn *col = (YadColumn *) c->data;
|
|
|
|
if (column_align)
|
|
{
|
|
switch (column_align[i])
|
|
{
|
|
case 'l':
|
|
col->c_align = 0.0;
|
|
break;
|
|
case 'r':
|
|
col->c_align = 1.0;
|
|
break;
|
|
case 'c':
|
|
col->c_align = 0.5;
|
|
break;
|
|
}
|
|
}
|
|
if (header_align)
|
|
{
|
|
switch (header_align[i])
|
|
{
|
|
case 'l':
|
|
col->h_align = 0.0;
|
|
break;
|
|
case 'r':
|
|
col->h_align = 1.0;
|
|
break;
|
|
case 'c':
|
|
col->h_align = 0.5;
|
|
break;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
GtkWidget *
|
|
list_create_widget (GtkWidget *dlg)
|
|
{
|
|
GtkWidget *w;
|
|
GtkTreeModel *model;
|
|
|
|
fore_col = back_col = font_col = -1;
|
|
|
|
if (options.debug)
|
|
{
|
|
if (options.list_data.checkbox || options.list_data.radiobox)
|
|
g_printerr (_("WARNING: You are use --checklist or --radiolist option. Those options obsoleted and will be removed in the future\n"));
|
|
}
|
|
|
|
n_cols = g_slist_length (options.list_data.columns);
|
|
if (n_cols == 0)
|
|
{
|
|
g_printerr (_("No column titles specified for List dialog.\n"));
|
|
return NULL;
|
|
}
|
|
|
|
if (options.list_data.tree_mode)
|
|
row_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gtk_tree_path_free);
|
|
|
|
/* set normalized alignment array for list keaders and columns content */
|
|
if (options.list_data.col_align)
|
|
{
|
|
column_align = g_new0 (gchar, n_cols);
|
|
strncpy (column_align, options.list_data.col_align, n_cols);
|
|
}
|
|
if (options.list_data.hdr_align)
|
|
{
|
|
header_align = g_new0 (gchar, n_cols);
|
|
strncpy (header_align, options.list_data.hdr_align, n_cols);
|
|
}
|
|
|
|
parse_cols_props ();
|
|
|
|
/* create widget */
|
|
w = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_ETCHED_IN);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), options.data.hscroll_policy, options.data.vscroll_policy);
|
|
|
|
model = create_model ();
|
|
|
|
list_view = gtk_tree_view_new_with_model (model);
|
|
gtk_widget_set_name (list_view, "yad-list-widget");
|
|
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list_view), !options.list_data.no_headers);
|
|
gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (list_view), options.list_data.grid_lines);
|
|
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (list_view), options.common_data.editable);
|
|
g_object_unref (model);
|
|
|
|
gtk_container_add (GTK_CONTAINER (w), list_view);
|
|
|
|
add_columns ();
|
|
|
|
/* add popup menu */
|
|
if (options.common_data.editable)
|
|
g_signal_connect_swapped (G_OBJECT (list_view), "button_press_event", G_CALLBACK (popup_menu_cb), NULL);
|
|
|
|
/* add tooltip column */
|
|
if (options.list_data.tooltip_column > 0)
|
|
{
|
|
if (options.list_data.simple_tips || options.data.no_markup)
|
|
{
|
|
gtk_widget_set_has_tooltip (list_view, TRUE);
|
|
g_signal_connect (G_OBJECT (list_view), "query-tooltip", G_CALLBACK (tooltip_cb), NULL);
|
|
}
|
|
else
|
|
gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (list_view), options.list_data.tooltip_column - 1);
|
|
}
|
|
|
|
/* set search function for regex search */
|
|
if (options.list_data.search_column != -1 && options.list_data.regex_search)
|
|
{
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns,
|
|
options.list_data.search_column);
|
|
|
|
if (col->type == YAD_COLUMN_TEXT)
|
|
gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (list_view), regex_search, NULL, NULL);
|
|
}
|
|
|
|
/* add row separator function */
|
|
if (options.list_data.sep_column > 0)
|
|
gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (list_view), row_sep_func, NULL, NULL);
|
|
|
|
if (options.list_data.no_selection)
|
|
{
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
|
|
gtk_tree_selection_set_mode (sel, GTK_SELECTION_NONE);
|
|
gtk_widget_set_can_focus (list_view, FALSE);
|
|
}
|
|
else
|
|
{
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
|
|
|
|
if (options.common_data.multi && !options.list_data.checkbox && !options.list_data.radiobox)
|
|
gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
|
|
|
|
if (!options.common_data.multi && options.action_data.select)
|
|
select_hndl = g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (select_cb), NULL);
|
|
|
|
g_signal_connect (G_OBJECT (list_view), "row-activated", G_CALLBACK (double_click_cb), dlg);
|
|
g_signal_connect (G_OBJECT (list_view), "key-press-event", G_CALLBACK (list_activate_cb), dlg);
|
|
}
|
|
|
|
/* load data */
|
|
fill_data ();
|
|
|
|
if (options.list_data.tree_expanded)
|
|
gtk_tree_view_expand_all (GTK_TREE_VIEW (list_view));
|
|
|
|
return w;
|
|
}
|
|
|
|
static void
|
|
print_col (GtkTreeModel *model, GtkTreeIter *iter, gint num)
|
|
{
|
|
YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num);
|
|
|
|
/* don't print attributes */
|
|
if (col->type == YAD_COLUMN_ATTR_FORE || col->type == YAD_COLUMN_ATTR_BACK || col->type == YAD_COLUMN_ATTR_FONT)
|
|
return;
|
|
|
|
switch (col->type)
|
|
{
|
|
case YAD_COLUMN_CHECK:
|
|
case YAD_COLUMN_RADIO:
|
|
{
|
|
gboolean bval;
|
|
gtk_tree_model_get (model, iter, num, &bval, -1);
|
|
if (options.common_data.quoted_output)
|
|
g_printf ("'%s'", print_bool_val (bval));
|
|
else
|
|
g_printf ("%s", print_bool_val (bval));
|
|
break;
|
|
}
|
|
case YAD_COLUMN_NUM:
|
|
case YAD_COLUMN_SIZE:
|
|
case YAD_COLUMN_BAR:
|
|
{
|
|
gint64 nval;
|
|
gtk_tree_model_get (model, iter, num, &nval, -1);
|
|
if (options.common_data.quoted_output)
|
|
g_printf ("'%ld'", (long) nval);
|
|
else
|
|
g_printf ("%ld", (long) nval);
|
|
break;
|
|
}
|
|
case YAD_COLUMN_FLOAT:
|
|
{
|
|
gdouble nval;
|
|
gtk_tree_model_get (model, iter, num, &nval, -1);
|
|
if (options.common_data.quoted_output)
|
|
g_printf ("'%.*f'", options.common_data.float_precision, nval);
|
|
else
|
|
g_printf ("%.*f", options.common_data.float_precision, nval);
|
|
break;
|
|
}
|
|
case YAD_COLUMN_IMAGE:
|
|
if (options.common_data.quoted_output)
|
|
g_printf ("''");
|
|
break;
|
|
default:
|
|
{
|
|
gchar *val;
|
|
gtk_tree_model_get (model, iter, num, &val, -1);
|
|
if (options.common_data.quoted_output)
|
|
{
|
|
gchar *buf = g_shell_quote (val ? val : "");
|
|
g_printf ("%s", buf);
|
|
g_free (buf);
|
|
}
|
|
else
|
|
g_printf ("%s", val ? val : "");
|
|
break;
|
|
}
|
|
}
|
|
g_printf ("%s", options.common_data.separator);
|
|
}
|
|
|
|
static void
|
|
print_selected (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
|
|
{
|
|
gint i,col;
|
|
|
|
col = options.list_data.print_column;
|
|
|
|
if (col && col <= n_cols)
|
|
print_col (model, iter, col - 1);
|
|
else
|
|
{
|
|
for (i = 0; i < n_cols; i++)
|
|
print_col (model, iter, i);
|
|
}
|
|
g_printf ("\n");
|
|
}
|
|
|
|
static void
|
|
print_all (GtkTreeModel *model, GtkTreeIter *parent)
|
|
{
|
|
GtkTreeIter iter;
|
|
gint i;
|
|
|
|
if (gtk_tree_model_iter_children (model, &iter, parent))
|
|
{
|
|
do
|
|
{
|
|
for (i = 0; i < n_cols; i++)
|
|
print_col (model, &iter, i);
|
|
g_printf ("\n");
|
|
/* print children */
|
|
print_all (model, &iter);
|
|
}
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
}
|
|
}
|
|
|
|
void
|
|
list_print_result (void)
|
|
{
|
|
GtkTreeModel *model;
|
|
gint col = options.list_data.print_column;
|
|
|
|
model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
|
|
|
|
if (options.list_data.print_all)
|
|
{
|
|
print_all (model, NULL);
|
|
return;
|
|
}
|
|
|
|
if (options.list_data.checkbox || options.list_data.radiobox)
|
|
{
|
|
// don't check in cycle
|
|
if (col > 0)
|
|
{
|
|
GtkTreeIter iter;
|
|
|
|
if (gtk_tree_model_get_iter_first (model, &iter))
|
|
{
|
|
do
|
|
{
|
|
gboolean chk;
|
|
gtk_tree_model_get (model, &iter, 0, &chk, -1);
|
|
if (chk)
|
|
{
|
|
print_col (model, &iter, col - 1);
|
|
g_printf ("\n");
|
|
}
|
|
}
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GtkTreeIter iter;
|
|
|
|
if (gtk_tree_model_get_iter_first (model, &iter))
|
|
{
|
|
do
|
|
{
|
|
gboolean chk;
|
|
gtk_tree_model_get (model, &iter, 0, &chk, -1);
|
|
if (chk)
|
|
{
|
|
gint i;
|
|
for (i = 0; i < n_cols; i++)
|
|
print_col (model, &iter, i);
|
|
g_printf ("\n");
|
|
}
|
|
}
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
|
|
gtk_tree_selection_selected_foreach (sel, print_selected, NULL);
|
|
}
|
|
}
|