53
53
#include "dialogs.h"
56
65
/* custom commands code*/
70
GtkTreeViewColumn *edit_column;
72
GtkTreeSelection *selection;
73
GtkWidget *button_add;
74
GtkWidget *button_remove;
76
GtkWidget *button_down;
63
79
static gboolean cc_error_occurred = FALSE;
64
80
static gboolean cc_reading_finished = FALSE;
65
81
static GString *cc_buffer;
67
static void cc_add_command(struct cc_dialog *cc, gint idx)
69
GtkWidget *label, *entry, *hbox;
72
hbox = gtk_hbox_new(FALSE, 5);
73
g_snprintf(str, 5, "%d:", cc->count);
74
label = gtk_label_new(str);
76
entry = gtk_entry_new();
78
gtk_entry_set_text(GTK_ENTRY(entry), ui_prefs.custom_commands[idx]);
79
ui_entry_add_clear_icon(GTK_ENTRY(entry));
80
gtk_entry_set_max_length(GTK_ENTRY(entry), 255);
81
gtk_entry_set_width_chars(GTK_ENTRY(entry), 30);
82
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
83
gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
84
gtk_widget_show_all(hbox);
85
gtk_container_add(GTK_CONTAINER(cc->box), hbox);
84
static gboolean cc_exists_command(const gchar *command)
86
gchar *path = g_find_program_in_path(command);
94
/* update STATUS and TOOLTIP columns according to cmd */
95
static void cc_dialog_update_row_status(GtkListStore *store, GtkTreeIter *iter, const gchar *cmd)
98
const gchar *stock_id = GTK_STOCK_NO;
99
gchar *tooltip = NULL;
104
stock_id = GTK_STOCK_YES;
105
else if (g_shell_parse_argv(cmd, &argc, &argv, &err))
107
if (argc > 0 && cc_exists_command(argv[0]))
108
stock_id = GTK_STOCK_YES;
110
tooltip = g_strdup_printf(_("Invalid command: %s"), _("Command not found"));
115
tooltip = g_strdup_printf(_("Invalid command: %s"), err->message);
119
gtk_list_store_set(store, iter, CC_COLUMN_STATUS, stock_id, CC_COLUMN_TOOLTIP, tooltip, -1);
124
/* adds a new row for custom command @p idx, or an new empty one if < 0 */
125
static void cc_dialog_add_command(struct cc_dialog *cc, gint idx, gboolean start_editing)
129
guint id = cc->count;
131
cmd = (idx >= 0) ? ui_prefs.custom_commands[idx] : NULL;
90
static void cc_on_custom_commands_dlg_add_clicked(GtkToolButton *toolbutton, struct cc_dialog *cc)
92
cc_add_command(cc, -1);
134
gtk_list_store_append(cc->store, &iter);
135
gtk_list_store_set(cc->store, &iter, CC_COLUMN_ID, id, CC_COLUMN_CMD, cmd, -1);
136
cc_dialog_update_row_status(cc->store, &iter, cmd);
142
gtk_widget_grab_focus(cc->view);
143
path = gtk_tree_model_get_path(GTK_TREE_MODEL(cc->store), &iter);
144
gtk_tree_view_set_cursor(GTK_TREE_VIEW(cc->view), path, cc->edit_column, TRUE);
145
gtk_tree_path_free(path);
150
static void cc_on_dialog_add_clicked(GtkButton *button, struct cc_dialog *cc)
152
cc_dialog_add_command(cc, -1, TRUE);
156
static void cc_on_dialog_remove_clicked(GtkButton *button, struct cc_dialog *cc)
160
if (gtk_tree_selection_get_selected(cc->selection, NULL, &iter))
161
gtk_list_store_remove(cc->store, &iter);
165
static void cc_on_dialog_move_up_clicked(GtkButton *button, struct cc_dialog *cc)
169
if (gtk_tree_selection_get_selected(cc->selection, NULL, &iter))
174
path = gtk_tree_model_get_path(GTK_TREE_MODEL(cc->store), &iter);
175
if (gtk_tree_path_prev(path) &&
176
gtk_tree_model_get_iter(GTK_TREE_MODEL(cc->store), &prev, path))
178
gtk_list_store_move_before(cc->store, &iter, &prev);
180
gtk_tree_path_free(path);
185
static void cc_on_dialog_move_down_clicked(GtkButton *button, struct cc_dialog *cc)
189
if (gtk_tree_selection_get_selected(cc->selection, NULL, &iter))
191
GtkTreeIter next = iter;
193
if (gtk_tree_model_iter_next(GTK_TREE_MODEL(cc->store), &next))
194
gtk_list_store_move_after(cc->store, &iter, &next);
406
static void cc_dialog_on_command_edited(GtkCellRendererText *renderer, gchar *path, gchar *text,
407
struct cc_dialog *cc)
411
gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(cc->store), &iter, path);
412
gtk_list_store_set(cc->store, &iter, CC_COLUMN_CMD, text, -1);
413
cc_dialog_update_row_status(cc->store, &iter, text);
417
/* re-compute IDs to reflect the current store state */
418
static void cc_dialog_update_ids(struct cc_dialog *cc)
423
if (! gtk_tree_model_get_iter_first(GTK_TREE_MODEL(cc->store), &iter))
428
gtk_list_store_set(cc->store, &iter, CC_COLUMN_ID, cc->count, -1);
431
while (gtk_tree_model_iter_next(GTK_TREE_MODEL(cc->store), &iter));
435
/* update sensitiveness of the buttons according to the selection */
436
static void cc_dialog_update_sensitive(struct cc_dialog *cc)
439
gboolean has_selection = FALSE;
440
gboolean first_selected = FALSE;
441
gboolean last_selected = FALSE;
443
if ((has_selection = gtk_tree_selection_get_selected(cc->selection, NULL, &iter)))
448
path = gtk_tree_model_get_path(GTK_TREE_MODEL(cc->store), &iter);
449
copy = gtk_tree_path_copy(path);
450
first_selected = ! gtk_tree_path_prev(copy);
451
gtk_tree_path_free(copy);
452
gtk_tree_path_next(path);
453
last_selected = ! gtk_tree_model_get_iter(GTK_TREE_MODEL(cc->store), &iter, path);
454
gtk_tree_path_free(path);
457
gtk_widget_set_sensitive(cc->button_remove, has_selection);
458
gtk_widget_set_sensitive(cc->button_up, has_selection && ! first_selected);
459
gtk_widget_set_sensitive(cc->button_down, has_selection && ! last_selected);
463
static void cc_dialog_on_tree_selection_changed(GtkTreeSelection *selection, struct cc_dialog *cc)
465
cc_dialog_update_sensitive(cc);
469
static void cc_dialog_on_row_inserted(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
470
struct cc_dialog *cc)
472
cc_dialog_update_ids(cc);
473
cc_dialog_update_sensitive(cc);
477
static void cc_dialog_on_row_deleted(GtkTreeModel *model, GtkTreePath *path, struct cc_dialog *cc)
479
cc_dialog_update_ids(cc);
480
cc_dialog_update_sensitive(cc);
484
static void cc_dialog_on_rows_reordered(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
485
gpointer new_order, struct cc_dialog *cc)
487
cc_dialog_update_ids(cc);
488
cc_dialog_update_sensitive(cc);
303
492
static void cc_show_dialog_custom_commands(void)
305
GtkWidget *dialog, *label, *vbox, *button;
494
GtkWidget *dialog, *label, *vbox, *scroll, *buttonbox;
495
GtkCellRenderer *renderer;
496
GtkTreeViewColumn *column;
307
498
struct cc_dialog cc;
309
500
dialog = gtk_dialog_new_with_buttons(_("Set Custom Commands"), GTK_WINDOW(main_widgets.window),
310
501
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
311
502
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
503
gtk_window_set_default_size(GTK_WINDOW(dialog), 300, 300); /* give a reasonable minimal default size */
312
504
vbox = ui_dialog_vbox_new(GTK_DIALOG(dialog));
313
505
gtk_box_set_spacing(GTK_BOX(vbox), 6);
314
506
gtk_widget_set_name(dialog, "GeanyDialog");
316
508
label = gtk_label_new(_("You can send the current selection to any of these commands and the output of the command replaces the current selection."));
317
509
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
318
510
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
319
gtk_container_add(GTK_CONTAINER(vbox), label);
511
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
322
cc.box = gtk_vbox_new(FALSE, 0);
323
gtk_container_add(GTK_CONTAINER(vbox), cc.box);
325
if (ui_prefs.custom_commands == NULL || g_strv_length(ui_prefs.custom_commands) == 0)
327
cc_add_command(&cc, -1);
514
cc.store = gtk_list_store_new(CC_COLUMN_COUNT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING,
516
cc.view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(cc.store));
517
gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(cc.view), CC_COLUMN_TOOLTIP);
518
gtk_tree_view_set_reorderable(GTK_TREE_VIEW(cc.view), TRUE);
519
cc.selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cc.view));
521
renderer = gtk_cell_renderer_text_new();
522
column = gtk_tree_view_column_new_with_attributes(_("ID"), renderer, "text", CC_COLUMN_ID, NULL);
523
gtk_tree_view_append_column(GTK_TREE_VIEW(cc.view), column);
524
/* command column, holding status and command display */
525
column = gtk_tree_view_column_new();
526
gtk_tree_view_column_set_title(column, _("Command"));
527
renderer = gtk_cell_renderer_pixbuf_new();
528
gtk_tree_view_column_pack_start(column, renderer, FALSE);
529
gtk_tree_view_column_set_attributes(column, renderer, "stock-id", CC_COLUMN_STATUS, NULL);
530
renderer = gtk_cell_renderer_text_new();
531
g_object_set(renderer, "editable", TRUE, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
532
g_signal_connect(renderer, "edited", G_CALLBACK(cc_dialog_on_command_edited), &cc);
533
gtk_tree_view_column_pack_start(column, renderer, TRUE);
534
gtk_tree_view_column_set_attributes(column, renderer, "text", CC_COLUMN_CMD, NULL);
535
cc.edit_column = column;
536
gtk_tree_view_append_column(GTK_TREE_VIEW(cc.view), column);
538
scroll = gtk_scrolled_window_new(NULL, NULL);
539
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC,
540
GTK_POLICY_AUTOMATIC);
541
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_IN);
542
gtk_container_add(GTK_CONTAINER(scroll), cc.view);
543
gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0);
545
if (ui_prefs.custom_commands != NULL)
331
548
guint len = g_strv_length(ui_prefs.custom_commands);
332
550
for (i = 0; i < len; i++)
334
if (ui_prefs.custom_commands[i][0] == '\0')
552
if (! NZV(ui_prefs.custom_commands[i]))
335
553
continue; /* skip empty fields */
337
cc_add_command(&cc, i);
555
cc_dialog_add_command(&cc, i, FALSE);
558
/* focus the first row if any */
559
if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(cc.store), &iter))
561
GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(cc.store), &iter);
563
gtk_tree_view_set_cursor(GTK_TREE_VIEW(cc.view), path, cc.edit_column, FALSE);
564
gtk_tree_path_free(path);
341
button = gtk_button_new_from_stock("gtk-add");
342
g_signal_connect(button, "clicked", G_CALLBACK(cc_on_custom_commands_dlg_add_clicked), &cc);
343
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
568
buttonbox = gtk_hbutton_box_new();
569
gtk_box_set_spacing(GTK_BOX(buttonbox), 6);
570
gtk_box_pack_start(GTK_BOX(vbox), buttonbox, FALSE, FALSE, 0);
571
cc.button_add = gtk_button_new_from_stock(GTK_STOCK_ADD);
572
g_signal_connect(cc.button_add, "clicked", G_CALLBACK(cc_on_dialog_add_clicked), &cc);
573
gtk_container_add(GTK_CONTAINER(buttonbox), cc.button_add);
574
cc.button_remove = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
575
g_signal_connect(cc.button_remove, "clicked", G_CALLBACK(cc_on_dialog_remove_clicked), &cc);
576
gtk_container_add(GTK_CONTAINER(buttonbox), cc.button_remove);
577
cc.button_up = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
578
g_signal_connect(cc.button_up, "clicked", G_CALLBACK(cc_on_dialog_move_up_clicked), &cc);
579
gtk_container_add(GTK_CONTAINER(buttonbox), cc.button_up);
580
cc.button_down = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
581
g_signal_connect(cc.button_down, "clicked", G_CALLBACK(cc_on_dialog_move_down_clicked), &cc);
582
gtk_container_add(GTK_CONTAINER(buttonbox), cc.button_down);
584
cc_dialog_update_sensitive(&cc);
586
/* only connect the selection signal when all other cc_dialog fields are set */
587
g_signal_connect(cc.selection, "changed", G_CALLBACK(cc_dialog_on_tree_selection_changed), &cc);
588
g_signal_connect(cc.store, "row-inserted", G_CALLBACK(cc_dialog_on_row_inserted), &cc);
589
g_signal_connect(cc.store, "row-deleted", G_CALLBACK(cc_dialog_on_row_deleted), &cc);
590
g_signal_connect(cc.store, "rows-reordered", G_CALLBACK(cc_dialog_on_rows_reordered), &cc);
345
592
gtk_widget_show_all(vbox);
347
594
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
349
/* get all hboxes which contain a label and an entry element */
350
GList *children = gtk_container_get_children(GTK_CONTAINER(cc.box));
352
596
GSList *result_list = NULL;
355
598
gchar **result = NULL;
358
foreach_list(node, children)
601
if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(cc.store), &iter))
360
/* get the contents of each hbox */
361
list = gtk_container_get_children(GTK_CONTAINER(node->data));
363
/* first element of the list is the label, so skip it and get the entry element */
364
text = gtk_entry_get_text(GTK_ENTRY(list->next->data));
366
/* if the content of the entry is non-empty, add it to the result array */
369
result_list = g_slist_append(result_list, g_strdup(text));
607
gtk_tree_model_get(GTK_TREE_MODEL(cc.store), &iter, CC_COLUMN_CMD, &cmd, -1);
610
result_list = g_slist_prepend(result_list, cmd);
616
while (gtk_tree_model_iter_next(GTK_TREE_MODEL(cc.store), &iter));
374
/* create a new null-terminated array but only if there any commands defined */
618
result_list = g_slist_reverse(result_list);
619
/* create a new null-terminated array but only if there is any commands defined */
377
625
result = g_new(gchar*, len + 1);
378
while (result_list != NULL)
626
foreach_list(node, result_list)
380
result[j] = (gchar*) result_list->data;
382
result_list = result_list->next;
628
result[j] = (gchar*) node->data;
385
result[len] = NULL; /* null-terminate the array */
631
result[j] = NULL; /* null-terminate the array */
387
633
/* set the new array */
388
634
g_strfreev(ui_prefs.custom_commands);