1 /*
2 * This file is part of YAD.
3 *
4 * YAD is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * YAD is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with YAD. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Copyright (C) 2008-2019, Victor Ananjevsky <ananasik@gmail.com>
18 */
19
20 #include <string.h>
21 #include <stdlib.h>
22
23 #include "yad.h"
24
25 static GtkWidget *list_view;
26
27 static GHashTable *row_hash = NULL;
28
29 static gint fore_col, back_col, font_col;
30 static guint n_cols = 0;
31
32 static gulong select_hndl = 0;
33
34 static inline void
yad_list_add_row(GtkTreeStore * m,GtkTreeIter * it,gchar * row_id,gchar * par_id)35 yad_list_add_row (GtkTreeStore *m, GtkTreeIter *it, gchar *row_id, gchar *par_id)
36 {
37 GtkTreePath *row_path;
38 GtkTreeIter pit, *parent = NULL;
39
40 if (par_id && par_id[0])
41 {
42 GtkTreePath *par_path = g_hash_table_lookup (row_hash, par_id);
43 if (par_path)
44 {
45 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (m), &pit, par_path))
46 parent = &pit;
47 }
48 }
49
50 if (options.list_data.add_on_top)
51 gtk_tree_store_prepend (m, it, parent);
52 else
53 gtk_tree_store_append (m, it, parent);
54
55 row_path = gtk_tree_model_get_path (GTK_TREE_MODEL (m), it);
56 if (row_id && row_id[0])
57 g_hash_table_insert (row_hash, row_id, row_path);
58 if (options.common_data.tail)
59 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (list_view), row_path, NULL, FALSE, 1.0, 1.0);
60 }
61
62 static gboolean
list_activate_cb(GtkWidget * widget,GdkEventKey * event,gpointer data)63 list_activate_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
64 {
65 if (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter)
66 {
67 if (options.list_data.dclick_action)
68 {
69 /* FIXME: check this under gtk-3.0 */
70 if (event->state & GDK_CONTROL_MASK)
71 {
72 if (options.plug == -1)
73 yad_exit (options.data.def_resp);
74 }
75 else
76 return FALSE;
77 }
78 else
79 {
80 if (options.plug == -1)
81 yad_exit (options.data.def_resp);
82 }
83
84 return TRUE;
85 }
86
87 return FALSE;
88 }
89
90 /* custom tooltip signal handler for no-markup mode */
91 static gboolean
tooltip_cb(GtkWidget * w,gint x,gint y,gboolean mode,GtkTooltip * tip,gpointer data)92 tooltip_cb (GtkWidget *w, gint x, gint y, gboolean mode, GtkTooltip *tip, gpointer data)
93 {
94 gchar *str;
95 gint bx, by;
96 GtkTreePath *path;
97 GtkTreeIter iter;
98 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (w));
99
100 gtk_tree_view_convert_widget_to_bin_window_coords (GTK_TREE_VIEW (w), x, y, &bx, &by);
101 if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (w), bx, by, &path, NULL, NULL, NULL))
102 return FALSE;
103
104 gtk_tree_model_get_iter (model, &iter, path);
105 gtk_tree_path_free (path);
106
107 gtk_tree_model_get (model, &iter, options.list_data.tooltip_column - 1, &str, -1);
108 if (str)
109 {
110 gtk_tooltip_set_text (tip, str);
111 return TRUE;
112 }
113
114 return FALSE;
115 }
116
117 static void
toggled_cb(GtkCellRendererToggle * cell,gchar * path_str,gpointer data)118 toggled_cb (GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
119 {
120 gint column;
121 gboolean fixed;
122 GtkTreeIter iter;
123 GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
124 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
125
126 column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));
127 gtk_tree_model_get_iter (model, &iter, path);
128 gtk_tree_model_get (model, &iter, column, &fixed, -1);
129
130 fixed ^= 1;
131
132 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column, fixed, -1);
133
134 gtk_tree_path_free (path);
135 }
136
137 static gboolean
runtoggle(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)138 runtoggle (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
139 {
140 gint col = GPOINTER_TO_INT (data);
141 gtk_tree_store_set (GTK_TREE_STORE (model), iter, col, FALSE, -1);
142 return FALSE;
143 }
144
145 static void
rtoggled_cb(GtkCellRendererToggle * cell,gchar * path_str,gpointer data)146 rtoggled_cb (GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
147 {
148 gint column;
149 GtkTreeIter iter;
150 GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
151 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
152
153 column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));
154
155 gtk_tree_model_foreach (model, runtoggle, GINT_TO_POINTER (column));
156
157 gtk_tree_model_get_iter (model, &iter, path);
158 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column, TRUE, -1);
159
160 gtk_tree_path_free (path);
161 }
162
163 static void
cell_edited_cb(GtkCellRendererText * cell,const gchar * path_string,const gchar * new_text,gpointer data)164 cell_edited_cb (GtkCellRendererText *cell, const gchar *path_string, const gchar *new_text, gpointer data)
165 {
166 gint column;
167 GtkTreeIter iter;
168 GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
169 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
170 YadColumn *col;
171
172 column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));
173 gtk_tree_model_get_iter (model, &iter, path);
174 col = (YadColumn *) g_slist_nth_data (options.list_data.columns, column);
175
176 if (col->type == YAD_COLUMN_NUM)
177 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column, g_ascii_strtoll (new_text, NULL, 10), -1);
178 else if (col->type == YAD_COLUMN_FLOAT)
179 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column, g_ascii_strtod (new_text, NULL), -1);
180 else
181 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column, new_text, -1);
182
183 gtk_tree_path_free (path);
184 }
185
186 static gboolean
regex_search(GtkTreeModel * model,gint col,const gchar * key,GtkTreeIter * iter,gpointer data)187 regex_search (GtkTreeModel *model, gint col, const gchar *key, GtkTreeIter *iter, gpointer data)
188 {
189 static GRegex *pattern = NULL;
190 static guint pos = 0;
191 gchar *str;
192
193 if (key[pos])
194 {
195 if (pattern)
196 g_regex_unref (pattern);
197 pattern = g_regex_new (key, G_REGEX_CASELESS | G_REGEX_EXTENDED | G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, NULL);
198 pos = strlen (key);
199 }
200
201 if (pattern)
202 {
203 gboolean ret;
204
205 gtk_tree_model_get (model, iter, col, &str, -1);
206
207 ret = g_regex_match (pattern, str, G_REGEX_MATCH_NOTEMPTY, NULL);
208 /* if get it, clear key end position */
209 if (!ret)
210 pos = 0;
211
212 return !ret;
213 }
214 else
215 return TRUE;
216 }
217
218 static GtkTreeModel *
create_model()219 create_model ()
220 {
221 GtkTreeStore *store;
222 GType *ctypes;
223 gint i;
224
225 ctypes = g_new0 (GType, n_cols);
226
227 if (options.list_data.checkbox)
228 {
229 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, 0);
230 col->type = YAD_COLUMN_CHECK;
231 }
232 else if (options.list_data.radiobox)
233 {
234 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, 0);
235 col->type = YAD_COLUMN_RADIO;
236 }
237
238 for (i = 0; i < n_cols; i++)
239 {
240 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, i);
241
242 switch (col->type)
243 {
244 case YAD_COLUMN_CHECK:
245 case YAD_COLUMN_RADIO:
246 ctypes[i] = G_TYPE_BOOLEAN;
247 break;
248 case YAD_COLUMN_NUM:
249 case YAD_COLUMN_SIZE:
250 case YAD_COLUMN_BAR:
251 ctypes[i] = G_TYPE_INT64;
252 break;
253 case YAD_COLUMN_FLOAT:
254 ctypes[i] = G_TYPE_DOUBLE;
255 break;
256 case YAD_COLUMN_IMAGE:
257 ctypes[i] = GDK_TYPE_PIXBUF;
258 break;
259 case YAD_COLUMN_ATTR_FORE:
260 ctypes[i] = G_TYPE_STRING;
261 fore_col = i;
262 break;
263 case YAD_COLUMN_ATTR_BACK:
264 ctypes[i] = G_TYPE_STRING;
265 back_col = i;
266 break;
267 case YAD_COLUMN_ATTR_FONT:
268 ctypes[i] = G_TYPE_STRING;
269 font_col = i;
270 break;
271 default:
272 ctypes[i] = G_TYPE_STRING;
273 break;
274 }
275 }
276
277 store = gtk_tree_store_newv (n_cols, ctypes);
278
279 return GTK_TREE_MODEL (store);
280 }
281
282 static void
float_col_format(GtkTreeViewColumn * col,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)283 float_col_format (GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *model,
284 GtkTreeIter *iter, gpointer data)
285 {
286 gdouble val;
287 gchar buf[20];
288
289 gtk_tree_model_get (model, iter, GPOINTER_TO_INT (data), &val, -1);
290 g_snprintf (buf, sizeof (buf), "%.*f", options.common_data.float_precision, val);
291 g_object_set (cell, "text", buf, NULL);
292 }
293
294 static void
size_col_format(GtkTreeViewColumn * col,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)295 size_col_format (GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *model,
296 GtkTreeIter *iter, gpointer data)
297 {
298 guint64 val;
299 gchar buf[20], *sz;
300
301 gtk_tree_model_get (model, iter, GPOINTER_TO_INT (data), &val, -1);
302 #if GLIB_CHECK_VERSION(2,30,0)
303 sz = g_format_size_full (val, options.common_data.size_fmt);
304 #elif GLIB_CHECK_VERSION(2,16,0)
305 sz = g_format_size_for_display (val);
306 #else
307 sz = g_strdup_printf ("%d", val);
308 #endif
309 g_snprintf (buf, sizeof (buf), "%s", sz);
310 g_free (sz);
311 g_object_set (cell, "text", buf, NULL);
312 }
313
314 static void
set_column_title(GtkTreeViewColumn * col,gchar * title)315 set_column_title (GtkTreeViewColumn *col, gchar *title)
316 {
317 GtkWidget *lbl;
318 gchar **str;
319
320 str = g_strsplit (title, options.common_data.item_separator, 2);
321 lbl = gtk_label_new (NULL);
322
323 if (options.data.no_markup)
324 {
325 gtk_label_set_text (GTK_LABEL (lbl), str[0]);
326 if (str[1] || options.list_data.header_tips)
327 gtk_widget_set_tooltip_text (lbl, str[1] ? str[1] : str[0]);
328 }
329 else
330 {
331 gtk_label_set_markup (GTK_LABEL (lbl), str[0]);
332 if (str[1] || options.list_data.header_tips)
333 gtk_widget_set_tooltip_markup (lbl, str[1] ? str[1] : str[0]);
334 }
335
336 gtk_widget_show (lbl);
337 gtk_tree_view_column_set_widget (col, lbl);
338 }
339
340 static void
add_columns()341 add_columns ()
342 {
343 gint i;
344 GtkCellRenderer *renderer;
345 GtkTreeViewColumn *column;
346
347 for (i = 0; i < n_cols; i++)
348 {
349 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, i);
350
351 if (i == options.list_data.hide_column - 1 || col->type == YAD_COLUMN_HIDDEN ||
352 i == fore_col || i == back_col || i == font_col)
353 continue;
354
355 switch (col->type)
356 {
357 case YAD_COLUMN_CHECK:
358 case YAD_COLUMN_RADIO:
359 renderer = gtk_cell_renderer_toggle_new ();
360 column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "active", i, NULL);
361 set_column_title (column, col->name);
362 if (back_col != -1)
363 gtk_tree_view_column_add_attribute (column, renderer, "cell-background", back_col);
364 if (col->type == YAD_COLUMN_RADIO)
365 {
366 gtk_cell_renderer_toggle_set_radio (GTK_CELL_RENDERER_TOGGLE (renderer), TRUE);
367 g_signal_connect (renderer, "toggled", G_CALLBACK (rtoggled_cb), NULL);
368 }
369 else
370 g_signal_connect (renderer, "toggled", G_CALLBACK (toggled_cb), NULL);
371 break;
372 case YAD_COLUMN_IMAGE:
373 renderer = gtk_cell_renderer_pixbuf_new ();
374 column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "pixbuf", i, NULL);
375 set_column_title (column, col->name);
376 if (back_col != -1)
377 gtk_tree_view_column_add_attribute (column, renderer, "cell-background", back_col);
378 break;
379 case YAD_COLUMN_NUM:
380 case YAD_COLUMN_SIZE:
381 case YAD_COLUMN_FLOAT:
382 renderer = gtk_cell_renderer_text_new ();
383 if (col->editable)
384 {
385 g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
386 g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited_cb), NULL);
387 }
388 column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "text", i, NULL);
389 set_column_title (column, col->name);
390 if (fore_col != -1)
391 gtk_tree_view_column_add_attribute (column, renderer, "foreground", fore_col);
392 if (back_col != -1)
393 gtk_tree_view_column_add_attribute (column, renderer, "cell-background", back_col);
394 if (font_col != -1)
395 gtk_tree_view_column_add_attribute (column, renderer, "font", font_col);
396 gtk_tree_view_column_set_sort_column_id (column, i);
397 gtk_tree_view_column_set_resizable (column, TRUE);
398 if (col->type == YAD_COLUMN_FLOAT)
399 gtk_tree_view_column_set_cell_data_func (column, renderer, float_col_format, GINT_TO_POINTER (i), NULL);
400 else if (col->type == YAD_COLUMN_SIZE)
401 gtk_tree_view_column_set_cell_data_func (column, renderer, size_col_format, GINT_TO_POINTER (i), NULL);
402 break;
403 case YAD_COLUMN_BAR:
404 renderer = gtk_cell_renderer_progress_new ();
405 column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "value", i, NULL);
406 set_column_title (column, col->name);
407 if (back_col != -1)
408 gtk_tree_view_column_add_attribute (column, renderer, "cell-background", back_col);
409 gtk_tree_view_column_set_sort_column_id (column, i);
410 gtk_tree_view_column_set_resizable (column, TRUE);
411 break;
412 default:
413 renderer = gtk_cell_renderer_text_new ();
414 if (col->editable)
415 {
416 g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
417 g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited_cb), NULL);
418 }
419 if (options.data.no_markup)
420 column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "text", i, NULL);
421 else
422 column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "markup", i, NULL);
423 set_column_title (column, col->name);
424 if (col->ellipsize)
425 g_object_set (G_OBJECT (renderer), "ellipsize", options.list_data.ellipsize, NULL);
426 if (col->wrap)
427 {
428 g_object_set (G_OBJECT (renderer), "wrap-width", options.list_data.wrap_width, NULL);
429 g_object_set (G_OBJECT (renderer), "wrap-mode", PANGO_WRAP_WORD_CHAR, NULL);
430 }
431 if (fore_col != -1)
432 gtk_tree_view_column_add_attribute (column, renderer, "foreground", fore_col);
433 if (back_col != -1)
434 gtk_tree_view_column_add_attribute (column, renderer, "cell-background", back_col);
435 if (font_col != -1)
436 gtk_tree_view_column_add_attribute (column, renderer, "font", font_col);
437 gtk_tree_view_column_set_sort_column_id (column, i);
438 gtk_tree_view_column_set_resizable (column, TRUE);
439
440 if (col->type == YAD_COLUMN_TIP)
441 options.list_data.tooltip_column = i + 1;
442 break;
443 }
444 g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (i));
445 gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
446
447 gtk_tree_view_column_set_clickable (column, options.list_data.clickable);
448
449 if (col->type != YAD_COLUMN_CHECK && col->type != YAD_COLUMN_IMAGE)
450 {
451 if (i == options.list_data.expand_column - 1 || options.list_data.expand_column == 0)
452 gtk_tree_view_column_set_expand (column, TRUE);
453 }
454 }
455
456 if (options.list_data.checkbox && !options.list_data.search_column)
457 options.list_data.search_column += 1;
458 if (options.list_data.search_column <= n_cols)
459 {
460 options.list_data.search_column -= 1;
461 gtk_tree_view_set_search_column (GTK_TREE_VIEW (list_view), options.list_data.search_column);
462 }
463 }
464
465 static void
cell_set_data(GtkTreeIter * it,guint num,gchar * data)466 cell_set_data (GtkTreeIter *it, guint num, gchar *data)
467 {
468 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
469 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num);
470
471 switch (col->type)
472 {
473 case YAD_COLUMN_CHECK:
474 case YAD_COLUMN_RADIO:
475 gtk_tree_store_set (GTK_TREE_STORE (model), it, num, get_bool_val (data), -1);
476 break;
477 case YAD_COLUMN_NUM:
478 case YAD_COLUMN_SIZE:
479 gtk_tree_store_set (GTK_TREE_STORE (model), it, num, g_ascii_strtoll (data, NULL, 10), -1);
480 break;
481 case YAD_COLUMN_FLOAT:
482 gtk_tree_store_set (GTK_TREE_STORE (model), it, num, g_ascii_strtod (data, NULL), -1);
483 break;
484 case YAD_COLUMN_BAR:
485 {
486 gint64 val = g_ascii_strtoll (data, NULL, 10);
487 if (val < 0)
488 val = 0;
489 if (val > 100)
490 val = 100;
491 gtk_tree_store_set (GTK_TREE_STORE (model), it, num, val, -1);
492 break;
493 }
494 case YAD_COLUMN_IMAGE:
495 {
496 GdkPixbuf *pb = get_pixbuf (data, YAD_SMALL_ICON, FALSE);
497 if (pb)
498 {
499 gtk_tree_store_set (GTK_TREE_STORE (model), it, num, pb, -1);
500 g_object_unref (pb);
501 }
502 break;
503 }
504 default:
505 if (data && *data)
506 gtk_tree_store_set (GTK_TREE_STORE (model), it, num, data, -1);
507 break;
508 }
509 }
510
511 static gchar *
cell_get_data(GtkTreeIter * it,guint num)512 cell_get_data (GtkTreeIter *it, guint num)
513 {
514 gchar *data = NULL;
515 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
516 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num);
517
518 switch (col->type)
519 {
520 case YAD_COLUMN_CHECK:
521 case YAD_COLUMN_RADIO:
522 {
523 gboolean bval;
524 gtk_tree_model_get (model, it, num, &bval, -1);
525 data = g_strdup (print_bool_val (bval));
526 break;
527 }
528 case YAD_COLUMN_NUM:
529 case YAD_COLUMN_SIZE:
530 case YAD_COLUMN_BAR:
531 {
532 gint64 nval;
533 gtk_tree_model_get (model, it, num, &nval, -1);
534 data = g_strdup_printf ("%ld", (long) nval);
535 break;
536 }
537 case YAD_COLUMN_FLOAT:
538 {
539 gdouble nval;
540 gtk_tree_model_get (model, it, num, &nval, -1);
541 data = g_strdup_printf ("%lf", nval);
542 break;
543 }
544 case YAD_COLUMN_IMAGE:
545 {
546 data = g_strdup ("''");
547 break;
548 }
549 default:
550 {
551 gchar *cval;
552 gtk_tree_model_get (model, it, num, &cval, -1);
553 if (cval)
554 data = g_shell_quote (cval);
555 break;
556 }
557 }
558
559 return data;
560 }
561
562 static gboolean
handle_stdin(GIOChannel * channel,GIOCondition condition,gpointer data)563 handle_stdin (GIOChannel *channel, GIOCondition condition, gpointer data)
564 {
565 static GtkTreeIter iter;
566 static gint column_count = 0;
567 static gint row_count = 0;
568 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
569
570 if ((condition == G_IO_IN) || (condition == G_IO_IN + G_IO_HUP))
571 {
572 GError *err = NULL;
573 GString *string = g_string_new (NULL);
574 gboolean node_added = FALSE;
575
576 while (channel->is_readable != TRUE)
577 usleep (100);
578
579 do
580 {
581 gint status;
582
583 do
584 {
585 status = g_io_channel_read_line_string (channel, string, NULL, &err);
586
587 while (gtk_events_pending ())
588 gtk_main_iteration ();
589 }
590 while (status == G_IO_STATUS_AGAIN);
591
592 if (status != G_IO_STATUS_NORMAL)
593 {
594 if (err)
595 {
596 g_printerr ("yad_list_handle_stdin(): %s\n", err->message);
597 g_error_free (err);
598 err = NULL;
599 }
600 /* stop handling */
601 g_io_channel_shutdown (channel, TRUE, NULL);
602 return FALSE;
603 }
604
605 strip_new_line (string->str);
606
607 /* clear list if ^L received */
608 if (string->str[0] == '\014')
609 {
610 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
611 if (select_hndl)
612 g_signal_handler_block (G_OBJECT (sel), select_hndl);
613 gtk_tree_store_clear (GTK_TREE_STORE (model));
614 row_count = column_count = 0;
615 if (row_hash)
616 g_hash_table_remove_all (row_hash);
617 if (select_hndl)
618 g_signal_handler_unblock (G_OBJECT (sel), select_hndl);
619 continue;
620 }
621
622 if (row_count == 0 && column_count == 0)
623 {
624 if (options.list_data.tree_mode)
625 {
626 if (!node_added)
627 {
628 gchar **ids = g_strsplit (string->str, ":", 2);
629 yad_list_add_row (GTK_TREE_STORE (model), &iter, ids[0], ids[1]);
630 node_added = TRUE;
631 continue;
632 }
633 else
634 node_added = FALSE;
635 }
636 else
637 yad_list_add_row (GTK_TREE_STORE (model), &iter, NULL, NULL);
638 }
639 else if (column_count == n_cols)
640 {
641 /* We're starting a new row */
642 if (options.list_data.tree_mode)
643 {
644 if (!node_added)
645 {
646 gchar **ids = g_strsplit (string->str, ":", 2);
647 yad_list_add_row (GTK_TREE_STORE (model), &iter, ids[0], ids[1]);
648 node_added = TRUE;
649 continue;
650 }
651 else
652 node_added = FALSE;
653 }
654 else
655 yad_list_add_row (GTK_TREE_STORE (model), &iter, NULL, NULL);
656 column_count = 0;
657 row_count++;
658 if (options.list_data.limit && row_count >= options.list_data.limit)
659 {
660 gtk_tree_model_get_iter_first (model, &iter);
661 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
662 }
663 }
664
665 cell_set_data (&iter, column_count, string->str);
666 column_count++;
667 }
668 while (g_io_channel_get_buffer_condition (channel) == G_IO_IN);
669 g_string_free (string, TRUE);
670 }
671
672 if (options.list_data.tree_expanded)
673 gtk_tree_view_expand_all (GTK_TREE_VIEW (list_view));
674
675 if ((condition != G_IO_IN) && (condition != G_IO_IN + G_IO_HUP))
676 {
677 g_io_channel_shutdown (channel, TRUE, NULL);
678 return FALSE;
679 }
680
681 return TRUE;
682 }
683
684 static void
fill_data()685 fill_data ()
686 {
687 GtkTreeIter iter;
688 GtkTreeStore *model = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (list_view)));
689 GIOChannel *channel;
690
691 if (options.extra_data && *options.extra_data)
692 {
693 gchar **args = options.extra_data;
694 gint i = 0;
695
696 gtk_widget_freeze_child_notify (list_view);
697
698 while (args[i] != NULL)
699 {
700 gint j;
701
702 if (options.list_data.tree_mode)
703 {
704 gchar **ids = g_strsplit (args[i], ":", 2);
705 yad_list_add_row (model, &iter, ids[0], ids[1]);
706 i++;
707 }
708 else
709 yad_list_add_row (model, &iter, NULL, NULL);
710 for (j = 0; j < n_cols; j++, i++)
711 {
712 if (args[i] == NULL)
713 break;
714
715 cell_set_data (&iter, j, args[i]);
716 }
717 }
718
719 gtk_widget_thaw_child_notify (list_view);
720 }
721
722 if (options.common_data.listen || !(options.extra_data && *options.extra_data))
723 {
724 channel = g_io_channel_unix_new (0);
725 g_io_channel_set_encoding (channel, NULL, NULL);
726 g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
727 g_io_add_watch (channel, G_IO_IN | G_IO_HUP, handle_stdin, NULL);
728 }
729 }
730
731 static gchar *
get_data_as_string(GtkTreeIter * iter)732 get_data_as_string (GtkTreeIter *iter)
733 {
734 GString *str;
735 gchar *res;
736 guint i;
737
738 str = g_string_new (NULL);
739
740 for (i = 0; i < n_cols; i++)
741 {
742 gchar *val = cell_get_data (iter, i);
743 if (val)
744 {
745 g_string_append_printf (str, "%s ", val);
746 g_free (val);
747 }
748 }
749
750 str->str[str->len-1] = '\0';
751 res = str->str;
752 g_string_free (str, FALSE);
753
754 return res;
755 }
756
757 static void edit_row_cb (GtkMenuItem *item, gpointer data);
758
759 static void
double_click_cb(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer data)760 double_click_cb (GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data)
761 {
762 GtkTreeModel *model;
763 GtkTreeIter iter;
764
765 model = gtk_tree_view_get_model (view);
766
767 if (options.list_data.dclick_action)
768 {
769 gchar *cmd, *args = NULL;
770
771 if (gtk_tree_model_get_iter (model, &iter, path))
772 args = get_data_as_string (&iter);
773 else
774 args = g_strdup ("");
775
776 if (g_strstr_len (options.list_data.dclick_action, -1, "%s"))
777 {
778 static GRegex *regex = NULL;
779
780 if (!regex)
781 regex = g_regex_new ("\%s", G_REGEX_OPTIMIZE, 0, NULL);
782 cmd = g_regex_replace_literal (regex, options.list_data.dclick_action, -1, 0, args, 0, NULL);
783 }
784 else
785 cmd = g_strdup_printf ("%s %s", options.list_data.dclick_action, args);
786 g_free (args);
787
788 if (cmd[0] == '@')
789 {
790 gchar *data = NULL;
791 gint exit;
792
793 exit = run_command_sync (cmd + 1, &data);
794 if (exit == 0)
795 {
796 gint i;
797 gchar **lines = g_strsplit (data, "\n", 0);
798
799 for (i = 0; i < n_cols; i++)
800 {
801 if (lines[i] == NULL)
802 break;
803
804 cell_set_data (&iter, i, lines[i]);
805 }
806 g_strfreev (lines);
807 }
808 g_free (data);
809 }
810 else
811 run_command_async (cmd);
812
813 g_free (cmd);
814 }
815 else if (options.common_data.editable && options.list_data.row_action)
816 edit_row_cb (NULL, NULL);
817 else
818 {
819 if (options.list_data.checkbox)
820 {
821 if (gtk_tree_model_get_iter (model, &iter, path))
822 {
823 gboolean chk;
824
825 gtk_tree_model_get (model, &iter, 0, &chk, -1);
826 chk = !chk;
827 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, chk, -1);
828 }
829 }
830 else if (options.list_data.radiobox)
831 {
832 if (gtk_tree_model_get_iter (model, &iter, path))
833 {
834 gtk_tree_model_foreach (model, runtoggle, GINT_TO_POINTER (0));
835 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, TRUE, -1);
836 }
837 }
838 else if (options.plug == -1)
839 yad_exit (options.data.def_resp);
840 }
841 }
842
843 static void
select_cb(GtkTreeSelection * sel,gpointer data)844 select_cb (GtkTreeSelection *sel, gpointer data)
845 {
846 GtkTreeModel *model;
847 GtkTreeIter iter;
848 gchar *cmd, *args;
849
850 if (!gtk_tree_selection_get_selected (sel, &model, &iter))
851 return;
852
853 args = get_data_as_string (&iter);
854 if (!args)
855 args = g_strdup ("");
856
857 if (g_strstr_len (options.list_data.select_action, -1, "%s"))
858 {
859 static GRegex *regex = NULL;
860
861 if (!regex)
862 regex = g_regex_new ("\%s", G_REGEX_OPTIMIZE, 0, NULL);
863 cmd = g_regex_replace_literal (regex, options.list_data.select_action, -1, 0, args, 0, NULL);
864 }
865 else
866 cmd = g_strdup_printf ("%s %s", options.list_data.select_action, args);
867 g_free (args);
868
869 run_command_async (cmd);
870
871 g_free (cmd);
872 }
873
874 static void
add_row_cb(GtkMenuItem * item,gpointer data)875 add_row_cb (GtkMenuItem *item, gpointer data)
876 {
877 GtkTreeModel *model;
878 GtkTreeIter iter;
879 gchar *cmd;
880
881 model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
882 if (g_object_get_data (G_OBJECT (item), "child") != NULL)
883 {
884 GtkTreeIter parent;
885 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
886
887 if (gtk_tree_selection_get_selected (sel, NULL, &parent))
888 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent);
889 else
890 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
891 }
892 else
893 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
894
895 if (options.list_data.row_action)
896 {
897 gchar *out = NULL;
898 gint exit;
899
900 /* hide menu first */
901 gtk_menu_popdown (GTK_MENU (data));
902 while (gtk_events_pending ())
903 gtk_main_iteration ();
904
905 /* run command */
906 cmd = g_strdup_printf ("%s add", options.list_data.row_action);
907 exit = run_command_sync (cmd, &out);
908 g_free (cmd);
909 if (exit == 0)
910 {
911 guint i;
912 gchar **lines = g_strsplit (out, "\n", 0);
913
914 for (i = 0; i < n_cols; i++)
915 {
916 if (lines[i] == NULL)
917 break;
918
919 cell_set_data (&iter, i, lines[i]);
920 }
921 g_strfreev (lines);
922 }
923 g_free (out);
924 }
925 }
926
927 static void
edit_row_cb(GtkMenuItem * item,gpointer data)928 edit_row_cb (GtkMenuItem *item, gpointer data)
929 {
930 GtkTreeIter iter;
931 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
932
933 if (!gtk_tree_selection_get_selected (sel, NULL, &iter))
934 return;
935
936 if (options.list_data.row_action)
937 {
938 gchar *cmd, *args, *out = NULL;
939 gint exit;
940
941 /* hide menu first */
942 gtk_menu_popdown (GTK_MENU (data));
943 while (gtk_events_pending ())
944 gtk_main_iteration ();
945
946 /* run command */
947 args = get_data_as_string (&iter);
948 cmd = g_strdup_printf ("%s edit %s", options.list_data.row_action, args);
949 g_free (args);
950 exit = run_command_sync (cmd, &out);
951 g_free (cmd);
952 if (exit == 0)
953 {
954 guint i;
955 gchar **lines = g_strsplit (out, "\n", 0);
956
957 for (i = 0; i < n_cols; i++)
958 {
959 if (lines[i] == NULL)
960 break;
961
962 cell_set_data (&iter, i, lines[i]);
963 }
964 g_strfreev (lines);
965 }
966 g_free (out);
967 }
968 }
969
970 static void
del_row_cb(GtkMenuItem * item,gpointer data)971 del_row_cb (GtkMenuItem *item, gpointer data)
972 {
973 GtkTreeIter iter;
974 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
975 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
976
977 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
978 {
979 if (options.list_data.row_action)
980 {
981 gchar *cmd, *args;
982 gint exit;
983
984 /* hide menu first */
985 gtk_menu_popdown (GTK_MENU (data));
986 while (gtk_events_pending ())
987 gtk_main_iteration ();
988
989 /* run command */
990 args = get_data_as_string (&iter);
991 cmd = g_strdup_printf ("%s del %s", options.list_data.row_action, args);
992 g_free (args);
993 exit = run_command_sync (cmd, NULL);
994 g_free (cmd);
995 if (exit == 0)
996 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
997 }
998 else
999 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
1000 }
1001 }
1002
1003 static void
copy_row_cb(GtkMenuItem * item,gpointer data)1004 copy_row_cb (GtkMenuItem *item, gpointer data)
1005 {
1006 GtkTreeIter iter;
1007 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
1008 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
1009
1010 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
1011 {
1012 GtkTreeIter new_iter, parent;
1013 gint i;
1014
1015 if (gtk_tree_model_iter_parent (model, &parent, &iter))
1016 gtk_tree_store_insert_after (GTK_TREE_STORE (model), &new_iter, &parent, &iter);
1017 else
1018 gtk_tree_store_insert_after (GTK_TREE_STORE (model), &new_iter, NULL, &iter);
1019
1020 for (i = 0; i < n_cols; i++)
1021 {
1022 GdkPixbuf *pb;
1023 gchar *tv;
1024 gint64 iv;
1025 gfloat fv;
1026 gboolean bv;
1027 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, i);
1028
1029 switch (col->type)
1030 {
1031 case YAD_COLUMN_CHECK:
1032 case YAD_COLUMN_RADIO:
1033 gtk_tree_model_get (model, &iter, i, &bv, -1);
1034 gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, i, bv, -1);
1035 break;
1036 case YAD_COLUMN_NUM:
1037 case YAD_COLUMN_SIZE:
1038 case YAD_COLUMN_BAR:
1039 gtk_tree_model_get (model, &iter, i, &iv, -1);
1040 gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, i, iv, -1);
1041 break;
1042 case YAD_COLUMN_FLOAT:
1043 gtk_tree_model_get (model, &iter, i, &fv, -1);
1044 gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, i, fv, -1);
1045 break;
1046 case YAD_COLUMN_IMAGE:
1047 gtk_tree_model_get (model, &iter, i, &pb, -1);
1048 gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, i, g_object_ref (pb), -1);
1049 break;
1050 default:
1051 gtk_tree_model_get (model, &iter, i, &tv, -1);
1052 gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, i, g_strdup (tv), -1);
1053 break;
1054 }
1055 }
1056 }
1057 }
1058
1059 static gboolean
popup_menu_cb(GtkWidget * w,GdkEventButton * ev,gpointer data)1060 popup_menu_cb (GtkWidget *w, GdkEventButton *ev, gpointer data)
1061 {
1062 static GtkWidget *menu = NULL;
1063 if (ev->button == 3)
1064 {
1065 GtkWidget *item;
1066
1067 if (menu == NULL)
1068 {
1069 menu = gtk_menu_new ();
1070 gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE);
1071
1072 item = gtk_menu_item_new_with_label (_("Add row"));
1073 gtk_widget_show (item);
1074 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1075 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (add_row_cb), menu);
1076
1077 if (options.list_data.tree_mode)
1078 {
1079 item = gtk_menu_item_new_with_label (_("Add child row"));
1080 gtk_widget_show (item);
1081 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1082 g_object_set_data (G_OBJECT (item), "child", "1");
1083 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (add_row_cb), menu);
1084 }
1085
1086 item = gtk_menu_item_new_with_label (_("Delete row"));
1087 gtk_widget_show (item);
1088 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1089 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (del_row_cb), menu);
1090
1091 if (options.list_data.row_action)
1092 {
1093 item = gtk_menu_item_new_with_label (_("Edit row"));
1094 gtk_widget_show (item);
1095 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1096 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (del_row_cb), menu);
1097 }
1098
1099 item = gtk_menu_item_new_with_label (_("Duplicate row"));
1100 gtk_widget_show (item);
1101 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1102 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (copy_row_cb), menu);
1103
1104 gtk_widget_show (menu);
1105 }
1106 gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
1107 }
1108 return FALSE;
1109 }
1110
1111 static gboolean
row_sep_func(GtkTreeModel * m,GtkTreeIter * it,gpointer data)1112 row_sep_func (GtkTreeModel *m, GtkTreeIter *it, gpointer data)
1113 {
1114 gchar *name;
1115
1116 if (!options.list_data.sep_value)
1117 return FALSE;
1118
1119 gtk_tree_model_get (m, it, options.list_data.sep_column - 1, &name, -1);
1120 return (strcmp (name, options.list_data.sep_value) == 0);
1121 }
1122
1123 static inline void
parse_cols_props()1124 parse_cols_props ()
1125 {
1126 /* set editable property for columns */
1127 if (options.common_data.editable)
1128 {
1129 if (options.list_data.editable_cols)
1130 {
1131 gchar **cnum;
1132 guint i = 0;
1133
1134 cnum = g_strsplit (options.list_data.editable_cols, ",", -1);
1135
1136 while (cnum[i])
1137 {
1138 gint num = atoi (cnum[i]);
1139 if (num)
1140 {
1141 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num - 1);
1142 if (col)
1143 col->editable = TRUE;
1144 }
1145 i++;
1146 }
1147 g_strfreev (cnum);
1148 }
1149 else
1150 {
1151 GSList *c;
1152 for (c = options.list_data.columns; c; c = c->next)
1153 {
1154 YadColumn *col = (YadColumn *) c->data;
1155 col->editable = TRUE;
1156 }
1157 }
1158 }
1159
1160 /* set wrap property for columns */
1161 if (options.list_data.wrap_width > 0)
1162 {
1163 if (options.list_data.wrap_cols)
1164 {
1165 gchar **cnum;
1166 guint i = 0;
1167
1168 cnum = g_strsplit (options.list_data.wrap_cols, ",", -1);
1169
1170 while (cnum[i])
1171 {
1172 gint num = atoi (cnum[i]);
1173 if (num)
1174 {
1175 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num - 1);
1176 if (col)
1177 col->wrap = TRUE;
1178 }
1179 i++;
1180 }
1181 g_strfreev (cnum);
1182 }
1183 else
1184 {
1185 GSList *c;
1186 for (c = options.list_data.columns; c; c = c->next)
1187 {
1188 YadColumn *col = (YadColumn *) c->data;
1189 col->wrap = TRUE;
1190 }
1191 }
1192 }
1193
1194 /* set ellipsize property for columns */
1195 if (options.list_data.ellipsize)
1196 {
1197 if (options.list_data.ellipsize_cols)
1198 {
1199 gchar **cnum;
1200 guint i = 0;
1201
1202 cnum = g_strsplit (options.list_data.ellipsize_cols, ",", -1);
1203
1204 while (cnum[i])
1205 {
1206 gint num = atoi (cnum[i]);
1207 if (num)
1208 {
1209 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num - 1);
1210 if (col)
1211 col->ellipsize = TRUE;
1212 }
1213 i++;
1214 }
1215 g_strfreev (cnum);
1216 }
1217 else
1218 {
1219 GSList *c;
1220 for (c = options.list_data.columns; c; c = c->next)
1221 {
1222 YadColumn *col = (YadColumn *) c->data;
1223 col->ellipsize = TRUE;
1224 }
1225 }
1226 }
1227 }
1228
1229 GtkWidget *
list_create_widget(GtkWidget * dlg)1230 list_create_widget (GtkWidget *dlg)
1231 {
1232 GtkWidget *w;
1233 GtkTreeModel *model;
1234
1235 fore_col = back_col = font_col = -1;
1236
1237 if (options.debug)
1238 {
1239 if (options.list_data.checkbox || options.list_data.radiobox)
1240 g_printerr (_("WARNING: You are use --checklist or --radiolist option. Those options obsoleted and will be removed in the future\n"));
1241 }
1242
1243 n_cols = g_slist_length (options.list_data.columns);
1244 if (n_cols == 0)
1245 {
1246 g_printerr (_("No column titles specified for List dialog.\n"));
1247 return NULL;
1248 }
1249
1250 if (options.list_data.tree_mode)
1251 row_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gtk_tree_path_free);
1252
1253 parse_cols_props ();
1254
1255 /* create widget */
1256 w = gtk_scrolled_window_new (NULL, NULL);
1257 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_ETCHED_IN);
1258 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), options.hscroll_policy, options.vscroll_policy);
1259
1260 model = create_model ();
1261
1262 list_view = gtk_tree_view_new_with_model (model);
1263 gtk_widget_set_name (list_view, "yad-list-widget");
1264 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list_view), !options.list_data.no_headers);
1265 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (list_view), options.list_data.grid_lines);
1266 gtk_tree_view_set_reorderable (GTK_TREE_VIEW (list_view), options.common_data.editable);
1267 g_object_unref (model);
1268
1269 gtk_container_add (GTK_CONTAINER (w), list_view);
1270
1271 add_columns ();
1272
1273 /* add popup menu */
1274 if (options.common_data.editable)
1275 g_signal_connect_swapped (G_OBJECT (list_view), "button_press_event", G_CALLBACK (popup_menu_cb), NULL);
1276
1277 /* add tooltip column */
1278 if (options.list_data.tooltip_column > 0)
1279 {
1280 if (options.list_data.simple_tips || options.data.no_markup)
1281 {
1282 gtk_widget_set_has_tooltip (list_view, TRUE);
1283 g_signal_connect (G_OBJECT (list_view), "query-tooltip", G_CALLBACK (tooltip_cb), NULL);
1284 }
1285 else
1286 gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (list_view), options.list_data.tooltip_column - 1);
1287 }
1288
1289 /* set search function for regex search */
1290 if (options.list_data.search_column != -1 && options.list_data.regex_search)
1291 {
1292 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns,
1293 options.list_data.search_column);
1294
1295 if (col->type == YAD_COLUMN_TEXT)
1296 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (list_view), regex_search, NULL, NULL);
1297 }
1298
1299 /* add row separator function */
1300 if (options.list_data.sep_column > 0)
1301 gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (list_view), row_sep_func, NULL, NULL);
1302
1303 if (options.list_data.no_selection)
1304 {
1305 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
1306 gtk_tree_selection_set_mode (sel, GTK_SELECTION_NONE);
1307 gtk_widget_set_can_focus (list_view, FALSE);
1308 }
1309 else
1310 {
1311 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
1312
1313 if (options.common_data.multi && !options.list_data.checkbox && !options.list_data.radiobox)
1314 gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
1315
1316 if (!options.common_data.multi && options.list_data.select_action)
1317 select_hndl = g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (select_cb), NULL);
1318
1319 g_signal_connect (G_OBJECT (list_view), "row-activated", G_CALLBACK (double_click_cb), dlg);
1320 g_signal_connect (G_OBJECT (list_view), "key-press-event", G_CALLBACK (list_activate_cb), dlg);
1321 }
1322
1323 /* load data */
1324 fill_data ();
1325
1326 if (options.list_data.tree_expanded)
1327 gtk_tree_view_expand_all (GTK_TREE_VIEW (list_view));
1328
1329 return w;
1330 }
1331
1332 static void
print_col(GtkTreeModel * model,GtkTreeIter * iter,gint num)1333 print_col (GtkTreeModel *model, GtkTreeIter *iter, gint num)
1334 {
1335 YadColumn *col = (YadColumn *) g_slist_nth_data (options.list_data.columns, num);
1336
1337 /* don't print attributes */
1338 if (col->type == YAD_COLUMN_ATTR_FORE || col->type == YAD_COLUMN_ATTR_BACK || col->type == YAD_COLUMN_ATTR_FONT)
1339 return;
1340
1341 switch (col->type)
1342 {
1343 case YAD_COLUMN_CHECK:
1344 case YAD_COLUMN_RADIO:
1345 {
1346 gboolean bval;
1347 gtk_tree_model_get (model, iter, num, &bval, -1);
1348 if (options.common_data.quoted_output)
1349 g_printf ("'%s'", print_bool_val (bval));
1350 else
1351 g_printf ("%s", print_bool_val (bval));
1352 break;
1353 }
1354 case YAD_COLUMN_NUM:
1355 case YAD_COLUMN_SIZE:
1356 case YAD_COLUMN_BAR:
1357 {
1358 gint64 nval;
1359 gtk_tree_model_get (model, iter, num, &nval, -1);
1360 if (options.common_data.quoted_output)
1361 g_printf ("'%ld'", (long) nval);
1362 else
1363 g_printf ("%ld", (long) nval);
1364 break;
1365 }
1366 case YAD_COLUMN_FLOAT:
1367 {
1368 gdouble nval;
1369 gtk_tree_model_get (model, iter, num, &nval, -1);
1370 if (options.common_data.quoted_output)
1371 g_printf ("'%.*f'", options.common_data.float_precision, nval);
1372 else
1373 g_printf ("%.*f", options.common_data.float_precision, nval);
1374 break;
1375 }
1376 case YAD_COLUMN_IMAGE:
1377 if (options.common_data.quoted_output)
1378 g_printf ("''");
1379 break;
1380 default:
1381 {
1382 gchar *val;
1383 gtk_tree_model_get (model, iter, num, &val, -1);
1384 if (options.common_data.quoted_output)
1385 {
1386 gchar *buf = g_shell_quote (val);
1387 g_printf ("%s", buf);
1388 g_free (buf);
1389 }
1390 else
1391 g_printf ("%s", val ? val : "");
1392 break;
1393 }
1394 }
1395 g_printf ("%s", options.common_data.separator);
1396 }
1397
1398 static void
print_selected(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1399 print_selected (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1400 {
1401 gint i,col;
1402
1403 col = options.list_data.print_column;
1404
1405 if (col && col <= n_cols)
1406 print_col (model, iter, col - 1);
1407 else
1408 {
1409 for (i = 0; i < n_cols; i++)
1410 print_col (model, iter, i);
1411 }
1412 g_printf ("\n");
1413 }
1414
1415 static void
print_all(GtkTreeModel * model,GtkTreeIter * parent)1416 print_all (GtkTreeModel *model, GtkTreeIter *parent)
1417 {
1418 GtkTreeIter iter;
1419 gint i;
1420
1421 if (gtk_tree_model_iter_children (model, &iter, parent))
1422 {
1423 do
1424 {
1425 for (i = 0; i < n_cols; i++)
1426 print_col (model, &iter, i);
1427 g_printf ("\n");
1428 /* print children */
1429 print_all (model, &iter);
1430 }
1431 while (gtk_tree_model_iter_next (model, &iter));
1432 }
1433 }
1434
1435 void
list_print_result(void)1436 list_print_result (void)
1437 {
1438 GtkTreeModel *model;
1439 gint col = options.list_data.print_column;
1440
1441 model = gtk_tree_view_get_model (GTK_TREE_VIEW (list_view));
1442
1443 if (options.list_data.print_all)
1444 {
1445 print_all (model, NULL);
1446 return;
1447 }
1448
1449 if (options.list_data.checkbox || options.list_data.radiobox)
1450 {
1451 // don't check in cycle
1452 if (col > 0)
1453 {
1454 GtkTreeIter iter;
1455
1456 if (gtk_tree_model_get_iter_first (model, &iter))
1457 {
1458 do
1459 {
1460 gboolean chk;
1461 gtk_tree_model_get (model, &iter, 0, &chk, -1);
1462 if (chk)
1463 {
1464 print_col (model, &iter, col - 1);
1465 g_printf ("\n");
1466 }
1467 }
1468 while (gtk_tree_model_iter_next (model, &iter));
1469 }
1470 }
1471 else
1472 {
1473 GtkTreeIter iter;
1474
1475 if (gtk_tree_model_get_iter_first (model, &iter))
1476 {
1477 do
1478 {
1479 gboolean chk;
1480 gtk_tree_model_get (model, &iter, 0, &chk, -1);
1481 if (chk)
1482 {
1483 gint i;
1484 for (i = 0; i < n_cols; i++)
1485 print_col (model, &iter, i);
1486 g_printf ("\n");
1487 }
1488 }
1489 while (gtk_tree_model_iter_next (model, &iter));
1490 }
1491 }
1492 }
1493 else
1494 {
1495 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
1496 gtk_tree_selection_selected_foreach (sel, print_selected, NULL);
1497 }
1498 }
1499