Commit 3450a75e authored by Paolo Bacchilega's avatar Paolo Bacchilega

scripts: save the accelerators as window shortcuts

This allows to handle accelerator collisions and change the
script shortcuts from the preferences dialog as well.
parent 110f10a0
......@@ -29,10 +29,10 @@
#include "gth-script-file.h"
#include "gth-script-task.h"
#include "list-tools.h"
#include "shortcuts.h"
#define BROWSER_DATA_KEY "list-tools-browser-data"
#define SCRIPTS_GROUP "scripts"
static const GActionEntry actions[] = {
......@@ -76,23 +76,18 @@ update_scripts (BrowserData *data)
GthScript *script = scan->data;
GthShortcut *shortcut;
shortcut = gth_script_get_shortcut (script);
shortcut = gth_script_create_shortcut (script);
gth_window_add_removable_shortcut (GTH_WINDOW (data->browser),
SCRIPTS_GROUP,
shortcut);
if (gth_script_is_visible (script)) {
char *detailed_action;
detailed_action = g_strdup_printf ("win.exec-script('%s')", gth_script_get_id (script));
gth_menu_manager_append_entry (menu_manager,
data->menu_merge_id,
gth_script_get_display_name (script),
detailed_action,
shortcut->label,
shortcut->detailed_action,
"",
NULL);
g_free (detailed_action);
}
gth_shortcut_free (shortcut);
......
......@@ -27,6 +27,7 @@
#include "gth-script.h"
#include "gth-script-editor-dialog.h"
#include "gth-script-file.h"
#include "shortcuts.h"
#define GET_WIDGET(name) _gtk_builder_get_widget (data->builder, (name))
......@@ -131,13 +132,15 @@ row_inserted_cb (GtkTreeModel *tree_model,
static char *
get_script_shortcut (GthScript *script)
get_shortcut_label (DialogData *data,
GthScript *script)
{
guint keyval;
GdkModifierType modifiers;
GthShortcut *shortcut;
gth_script_get_accelerator (script, &keyval, &modifiers);
return gtk_accelerator_get_label (keyval, modifiers);
shortcut = gth_window_get_shortcut (GTH_WINDOW (data->browser),
gth_script_get_detailed_action (script));
return (shortcut != NULL) ? shortcut->label : "";
}
......@@ -151,20 +154,15 @@ set_script_list (DialogData *data,
for (scan = script_list; scan; scan = scan->next) {
GthScript *script = scan->data;
char *shortcut;
GtkTreeIter iter;
shortcut = get_script_shortcut (script);
gtk_list_store_append (data->list_store, &iter);
gtk_list_store_set (data->list_store, &iter,
COLUMN_SCRIPT, script,
COLUMN_NAME, gth_script_get_display_name (script),
COLUMN_SHORTCUT, shortcut,
COLUMN_SHORTCUT, get_shortcut_label (data, script),
COLUMN_VISIBLE, gth_script_is_visible (script),
-1);
g_free (shortcut);
}
g_signal_handlers_unblock_by_func (data->list_store, row_inserted_cb, data);
......@@ -295,7 +293,31 @@ add_columns (GtkTreeView *treeview,
static gboolean
get_script_iter (DialogData *data,
get_iter_for_shortcut (DialogData *data,
GthShortcut *shortcut,
GtkTreeIter *iter)
{
GtkTreeModel *model = GTK_TREE_MODEL (data->list_store);
gboolean found = FALSE;
if (! gtk_tree_model_get_iter_first (model, iter))
return FALSE;
do {
GthScript *script;
gtk_tree_model_get (model, iter, COLUMN_SCRIPT, &script, -1);
found = g_strcmp0 (shortcut->detailed_action, gth_script_get_detailed_action (script)) == 0;
g_object_unref (script);
}
while (! found && gtk_tree_model_iter_next (model, iter));
return found;
}
static gboolean
get_iter_script (DialogData *data,
GthScript *script,
GtkTreeIter *iter)
{
......@@ -329,16 +351,12 @@ script_editor_dialog__response_cb (GtkDialog *dialog,
DialogData *data = user_data;
GthScript *script;
GError *error = NULL;
GPtrArray *shortcuts_v;
GthScriptFile *script_file;
gboolean new_script;
GthShortcut *shortcut;
GtkTreeIter iter;
gboolean change_list = TRUE;
if (response == GTK_RESPONSE_HELP) {
/* FIXME: show help dialog */
return;
}
gboolean change_list;
if (response != GTK_RESPONSE_OK) {
gtk_widget_destroy (GTK_WIDGET (dialog));
......@@ -352,42 +370,71 @@ script_editor_dialog__response_cb (GtkDialog *dialog,
return;
}
/* update the script file */
/* update the shortcuts */
shortcuts_v = g_ptr_array_copy (gth_window_get_shortcuts (GTH_WINDOW (data->browser)),
(GCopyFunc) gth_shortcut_dup,
NULL);
/* If another shortcut has the same accelerator, reset the accelerator
* for that shortcut. */
shortcut = gth_shortcut_array_find_by_accel (shortcuts_v,
GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER,
gth_script_get_accelerator (script));
if (shortcut != NULL) {
if (g_strcmp0 (shortcut->detailed_action, gth_script_get_detailed_action (script)) != 0) {
if (get_iter_for_shortcut (data, shortcut, &iter))
gtk_list_store_set (data->list_store, &iter,
COLUMN_SHORTCUT, "",
-1);
gth_shortcut_set_key (shortcut, 0, 0);
}
}
/* update the script shortcut */
shortcut = gth_shortcut_array_find_by_action (shortcuts_v, gth_script_get_detailed_action (script));
if (shortcut != NULL)
g_ptr_array_remove (shortcuts_v, shortcut);
shortcut = gth_script_create_shortcut (script);
g_ptr_array_add (shortcuts_v, shortcut);
/* save the script */
script_file = gth_script_file_get ();
new_script = ! gth_script_file_has_script (script_file, script);
g_signal_handlers_block_by_func (script_file, scripts_changed_cb, data);
gth_script_file_add (script_file, script);
gth_script_file_save (script_file, NULL); /* FIXME: handle errors */
gth_script_file_save (script_file, NULL);
g_signal_handlers_unblock_by_func (script_file, scripts_changed_cb, data);
gth_main_shortcuts_changed (shortcuts_v);
/* update the script list */
if (new_script) {
g_signal_handlers_block_by_func (data->list_store, row_inserted_cb, data);
gtk_list_store_append (data->list_store, &iter);
g_signal_handlers_unblock_by_func (data->list_store, row_inserted_cb, data);
change_list = TRUE;
}
else
change_list = get_script_iter (data, script, &iter);
change_list = get_iter_script (data, script, &iter);
if (change_list) {
char *shortcut;
shortcut = get_script_shortcut (script);
if (change_list)
gtk_list_store_set (data->list_store, &iter,
COLUMN_SCRIPT, script,
COLUMN_NAME, gth_script_get_display_name (script),
COLUMN_SHORTCUT, shortcut,
COLUMN_SHORTCUT, shortcut->label,
COLUMN_VISIBLE, gth_script_is_visible (script),
-1);
g_free (shortcut);
}
gtk_widget_destroy (GTK_WIDGET (dialog));
g_ptr_array_unref (shortcuts_v);
g_object_unref (script);
}
......@@ -398,7 +445,7 @@ new_script_cb (GtkButton *button,
{
GtkWidget *dialog;
dialog = gth_script_editor_dialog_new (_("New Command"), GTK_WINDOW (data->dialog));
dialog = gth_script_editor_dialog_new (_("New Command"), GTH_WINDOW (data->browser), GTK_WINDOW (data->dialog));
g_signal_connect (dialog, "response",
G_CALLBACK (script_editor_dialog__response_cb),
data);
......@@ -425,7 +472,7 @@ edit_script_cb (GtkButton *button,
if (script == NULL)
return;
dialog = gth_script_editor_dialog_new (_("Edit Command"), GTK_WINDOW (data->dialog));
dialog = gth_script_editor_dialog_new (_("Edit Command"), GTH_WINDOW (data->browser), GTK_WINDOW (data->dialog));
gth_script_editor_dialog_set_script (GTH_SCRIPT_EDITOR_DIALOG (dialog), script);
g_signal_connect (dialog,
"response",
......@@ -448,6 +495,8 @@ delete_script_cb (GtkButton *button,
GtkTreeModel *model = GTK_TREE_MODEL (data->list_store);
GtkTreeIter iter;
GthScript *script;
GPtrArray *shortcuts_v;
GthShortcut *shortcut;
GthScriptFile *script_file;
d = _gtk_message_dialog_new (GTK_WINDOW (data->dialog),
......@@ -471,6 +520,16 @@ delete_script_cb (GtkButton *button,
if (script == NULL)
return;
/* update the shortcuts */
shortcuts_v = g_ptr_array_copy (gth_window_get_shortcuts (GTH_WINDOW (data->browser)),
(GCopyFunc) gth_shortcut_dup,
NULL);
shortcut = gth_shortcut_array_find_by_action (shortcuts_v, gth_script_get_detailed_action (script));
if (shortcut != NULL)
g_ptr_array_remove (shortcuts_v, shortcut);
/* update the script file */
script_file = gth_script_file_get ();
......@@ -479,6 +538,8 @@ delete_script_cb (GtkButton *button,
gth_script_file_save (script_file, NULL);
g_signal_handlers_unblock_by_func (script_file, scripts_changed_cb, data);
gth_main_shortcuts_changed (shortcuts_v);
/* update the script list */
g_signal_handlers_block_by_func (data->list_store, row_deleted_cb, data);
......
......@@ -37,14 +37,16 @@ enum {
};
struct _GthScriptEditorDialogPrivate {
GtkBuilder *builder;
GtkWidget *accel_button;
char *script_id;
gboolean script_visible;
gboolean wait_command;
gboolean shell_script;
gboolean for_each_file;
gboolean help_visible;
GthWindow *shortcut_window;
GtkBuilder *builder;
GtkWidget *accel_button;
char *script_id;
gboolean script_visible;
gboolean wait_command;
gboolean shell_script;
gboolean for_each_file;
gboolean help_visible;
GthShortcut *shortcut;
};
......@@ -90,6 +92,8 @@ gth_script_editor_dialog_init (GthScriptEditorDialog *dialog)
dialog->priv->shell_script = FALSE;
dialog->priv->for_each_file = FALSE;
dialog->priv->help_visible = FALSE;
dialog->priv->shortcut = NULL;
dialog->priv->shortcut_window = NULL;
}
......@@ -117,6 +121,26 @@ command_entry_icon_press_cb (GtkEntry *entry,
}
static gboolean
accel_button_change_value_cb (GthAccelButton *button,
guint keycode,
GdkModifierType modifiers,
gpointer user_data)
{
GthScriptEditorDialog *self = user_data;
gboolean change;
change = gth_window_can_change_shortcut (self->priv->shortcut_window,
self->priv->shortcut != NULL ? self->priv->shortcut->detailed_action : NULL,
GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER,
keycode,
modifiers,
GTK_WINDOW (self));
return change ? GDK_EVENT_PROPAGATE : GDK_EVENT_STOP;
}
static void
gth_script_editor_dialog_construct (GthScriptEditorDialog *self,
const char *title,
......@@ -138,6 +162,11 @@ gth_script_editor_dialog_construct (GthScriptEditorDialog *self,
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), _gtk_builder_get_widget (self->priv->builder, "script_editor"), TRUE, TRUE, 0);
self->priv->accel_button = gth_accel_button_new ();
g_signal_connect (self->priv->accel_button,
"change-value",
G_CALLBACK (accel_button_change_value_cb),
self);
gtk_widget_show (self->priv->accel_button);
gtk_box_pack_start (GTK_BOX (GET_WIDGET ("accel_box")), self->priv->accel_button, FALSE, FALSE, 0);
......@@ -154,6 +183,7 @@ gth_script_editor_dialog_construct (GthScriptEditorDialog *self,
GtkWidget *
gth_script_editor_dialog_new (const char *title,
GthWindow *shortcut_window,
GtkWindow *parent)
{
GthScriptEditorDialog *self;
......@@ -161,6 +191,7 @@ gth_script_editor_dialog_new (const char *title,
self = g_object_new (GTH_TYPE_SCRIPT_EDITOR_DIALOG,
"use-header-bar", _gtk_settings_get_dialogs_use_header (),
NULL);
self->priv->shortcut_window = shortcut_window;
gth_script_editor_dialog_construct (self, title, parent);
return (GtkWidget *) self;
......@@ -186,14 +217,11 @@ gth_script_editor_dialog_set_script (GthScriptEditorDialog *self,
g_free (self->priv->script_id);
self->priv->script_id = NULL;
self->priv->script_visible = TRUE;
self->priv->shortcut = NULL;
_gth_script_editor_dialog_set_new_script (self);
if (script != NULL) {
guint keyval;
GdkModifierType modifiers;
self->priv->script_id = g_strdup (gth_script_get_id (script));
self->priv->script_visible = gth_script_is_visible (script);
......@@ -203,8 +231,12 @@ gth_script_editor_dialog_set_script (GthScriptEditorDialog *self,
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("for_each_file_checkbutton")), gth_script_for_each_file (script));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("wait_command_checkbutton")), gth_script_wait_command (script));
gth_script_get_accelerator (script, &keyval, &modifiers);
gth_accel_button_set_accelerator (GTH_ACCEL_BUTTON (self->priv->accel_button), keyval, modifiers);
self->priv->shortcut = gth_window_get_shortcut (self->priv->shortcut_window, gth_script_get_detailed_action (script));
if (self->priv->shortcut != NULL) {
gth_accel_button_set_accelerator (GTH_ACCEL_BUTTON (self->priv->accel_button),
self->priv->shortcut->keyval,
self->priv->shortcut->modifiers);
}
}
update_sensitivity (self);
......
......@@ -49,6 +49,7 @@ struct _GthScriptEditorDialogClass {
GType gth_script_editor_dialog_get_type (void);
GtkWidget * gth_script_editor_dialog_new (const char *title,
GthWindow *shortcut_window,
GtkWindow *parent);
void gth_script_editor_dialog_set_script (GthScriptEditorDialog *self,
GthScript *script);
......
......@@ -43,12 +43,6 @@ enum {
};
typedef struct {
guint keyval;
GdkModifierType modifiers;
char *name;
} _Accel;
struct _GthScriptPrivate {
char *id;
char *display_name;
......@@ -57,7 +51,8 @@ struct _GthScriptPrivate {
gboolean shell_script;
gboolean for_each_file;
gboolean wait_command;
_Accel accelerator;
char *accelerator;
char *detailed_action;
};
......@@ -89,7 +84,6 @@ gth_script_real_create_element (DomDomizable *base,
"shell-script", (self->priv->shell_script ? "true" : "false"),
"for-each-file", (self->priv->for_each_file ? "true" : "false"),
"wait-command", (self->priv->wait_command ? "true" : "false"),
"accelerator", self->priv->accelerator.name,
NULL);
if (! self->priv->visible)
dom_element_set_attribute (element, "display", "none");
......@@ -115,7 +109,7 @@ gth_script_real_load_from_element (DomDomizable *base,
"shell-script", (g_strcmp0 (dom_element_get_attribute (element, "shell-script"), "true") == 0),
"for-each-file", (g_strcmp0 (dom_element_get_attribute (element, "for-each-file"), "true") == 0),
"wait-command", (g_strcmp0 (dom_element_get_attribute (element, "wait-command"), "true") == 0),
"accelerator", dom_element_get_attribute (element, "accelerator"),
"accelerator", "",
NULL);
}
......@@ -135,7 +129,7 @@ gth_script_real_duplicate (GthDuplicable *duplicable)
"shell-script", script->priv->shell_script,
"for-each-file", script->priv->for_each_file,
"wait-command", script->priv->wait_command,
"accelerator", script->priv->accelerator.name,
"accelerator", script->priv->accelerator,
NULL);
return (GObject *) new_script;
......@@ -151,12 +145,28 @@ gth_script_finalize (GObject *base)
g_free (self->priv->id);
g_free (self->priv->display_name);
g_free (self->priv->command);
g_free (self->priv->accelerator.name);
g_free (self->priv->accelerator);
g_free (self->priv->detailed_action);
G_OBJECT_CLASS (gth_script_parent_class)->finalize (base);
}
static char *
detailed_action_from_id (char *id)
{
GVariant *param;
char *detailed_action;
param = g_variant_new_string (id);
detailed_action = g_action_print_detailed_name ("exec-script", param);
g_variant_unref (param);
return detailed_action;
}
static void
gth_script_set_property (GObject *object,
guint property_id,
......@@ -173,6 +183,8 @@ gth_script_set_property (GObject *object,
self->priv->id = g_value_dup_string (value);
if (self->priv->id == NULL)
self->priv->id = g_strdup ("");
g_free (self->priv->detailed_action);
self->priv->detailed_action = detailed_action_from_id (self->priv->id);
break;
case PROP_DISPLAY_NAME:
g_free (self->priv->display_name);
......@@ -199,10 +211,8 @@ gth_script_set_property (GObject *object,
self->priv->wait_command = g_value_get_boolean (value);
break;
case PROP_ACCELERATOR:
self->priv->accelerator.name = g_value_dup_string (value);
gtk_accelerator_parse (self->priv->accelerator.name,
&self->priv->accelerator.keyval,
&self->priv->accelerator.modifiers);
g_free (self->priv->accelerator);
self->priv->accelerator = g_value_dup_string (value);
break;
default:
break;
......@@ -243,7 +253,7 @@ gth_script_get_property (GObject *object,
g_value_set_boolean (value, self->priv->wait_command);
break;
case PROP_ACCELERATOR:
g_value_set_string (value, self->priv->accelerator.name);
g_value_set_string (value, self->priv->accelerator);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
......@@ -345,9 +355,12 @@ gth_script_init (GthScript *self)
self->priv->id = NULL;
self->priv->display_name = NULL;
self->priv->command = NULL;
self->priv->accelerator.name = NULL;
self->priv->accelerator.keyval = 0;
self->priv->accelerator.modifiers = 0;
self->priv->visible = FALSE;
self->priv->shell_script = FALSE;
self->priv->for_each_file = FALSE;
self->priv->wait_command = FALSE;
self->priv->accelerator = NULL;
self->priv->detailed_action = NULL;
}
......@@ -386,6 +399,13 @@ gth_script_get_command (GthScript *script)
}
const char *
gth_script_get_detailed_action (GthScript *self)
{
return self->priv->detailed_action;
}
gboolean
gth_script_is_visible (GthScript *script)
{
......@@ -1026,30 +1046,25 @@ gth_script_get_command_line (GthScript *script,
}
void
gth_script_get_accelerator (GthScript *self,
guint *keyval,
GdkModifierType *modifiers)
const char *
gth_script_get_accelerator (GthScript *self)
{
g_return_if_fail (GTH_IS_SCRIPT (self));
if (keyval) *keyval = self->priv->accelerator.keyval;
if (modifiers) *modifiers = self->priv->accelerator.modifiers;
g_return_val_if_fail (GTH_IS_SCRIPT (self), NULL);
return self->priv->accelerator;
}
GthShortcut *
gth_script_get_shortcut (GthScript *self)
gth_script_create_shortcut (GthScript *self)
{
GthShortcut *shortcut;
shortcut = gth_shortcut_new ();
shortcut->action_name = g_strdup ("exec-script");
shortcut->action_parameter = g_variant_ref_sink (g_variant_new_string (gth_script_get_id (self)));
shortcut = gth_shortcut_new ("exec-script", g_variant_new_string (gth_script_get_id (self)));
shortcut->description = g_strdup (self->priv->display_name);
shortcut->context = GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER;
shortcut->category = GTH_SHORTCUT_CATEGORY_LIST_TOOLS;
gth_shortcut_set_key (shortcut, self->priv->accelerator.keyval, self->priv->accelerator.modifiers);
shortcut->default_accelerator = g_strdup (shortcut->accelerator);
gth_shortcut_set_accelerator (shortcut, self->priv->accelerator);
shortcut->default_accelerator = g_strdup ("");
return shortcut;
}
......@@ -55,6 +55,7 @@ GthScript * gth_script_new (void);
const char * gth_script_get_id (GthScript *script);
const char * gth_script_get_display_name (GthScript *script);
const char * gth_script_get_command (GthScript *script);
const char * gth_script_get_detailed_action (GthScript *script);
gboolean gth_script_is_visible (GthScript *script);
gboolean gth_script_is_shell_script (GthScript *script);
gboolean gth_script_for_each_file (GthScript *script);
......@@ -65,10 +66,8 @@ char * gth_script_get_command_line (GthScript *script,
GList *file_list /* GthFileData */,
gboolean can_skip,
GError **error);
void gth_script_get_accelerator (GthScript *script,
guint *keyval,
GdkModifierType *modifiers);
GthShortcut * gth_script_get_shortcut (GthScript *script);
const char * gth_script_get_accelerator (GthScript *script);
GthShortcut * gth_script_create_shortcut (GthScript *script);
G_END_DECLS
......
......@@ -23,5 +23,6 @@
#define LIST_TOOLS_SHORTCUTS_H
#define GTH_SHORTCUT_CATEGORY_LIST_TOOLS "list-tools"
#define SCRIPTS_GROUP "scripts"
#endif /* LIST_TOOLS_SHORTCUTS_H */
......@@ -129,7 +129,7 @@ find_row_by_shortcut (BrowserData *browser_data,
for (i = 0; i < browser_data->rows->len; i++) {
RowData *row_data = g_ptr_array_index (browser_data->rows, i);
if (g_strcmp0 (row_data->shortcut->action_name, shortcut->action_name) == 0)
if (g_strcmp0 (row_data->shortcut->detailed_action, shortcut->detailed_action) == 0)