Commit 9767f7f9f81acfee3cd1f5a9dcade478512b1fb1

Authored by Perry Werneck
1 parent b08a928d
Exists in master and in 1 other branch develop

Checking for duplicate accelerators.

src/dialogs/settings/accelerator.c
@@ -30,6 +30,10 @@ @@ -30,6 +30,10 @@
30 /** 30 /**
31 * @brief Implements the accelerator settings widget. 31 * @brief Implements the accelerator settings widget.
32 * 32 *
  33 + * References:
  34 + *
  35 + * <https://github.com/Apress/foundations-of-gtk-dev/blob/master/chapter_8/accelerators.c>
  36 + *
33 */ 37 */
34 38
35 #include <internals.h> 39 #include <internals.h>
@@ -38,6 +42,7 @@ @@ -38,6 +42,7 @@
38 #include <lib3270/log.h> 42 #include <lib3270/log.h>
39 #include <v3270/actions.h> 43 #include <v3270/actions.h>
40 #include <terminal.h> 44 #include <terminal.h>
  45 + #include <gdk/gdkkeysyms-compat.h>
41 46
42 /*--[ Widget Definition ]----------------------------------------------------------------------------*/ 47 /*--[ Widget Definition ]----------------------------------------------------------------------------*/
43 48
@@ -69,6 +74,9 @@ @@ -69,6 +74,9 @@
69 static void load(GtkWidget *w, GtkWidget *terminal); 74 static void load(GtkWidget *w, GtkWidget *terminal);
70 static void apply(GtkWidget *w, GtkWidget *terminal); 75 static void apply(GtkWidget *w, GtkWidget *terminal);
71 76
  77 + static void accel_edited(GtkCellRendererAccel*, gchar*, guint, GdkModifierType, guint, V3270AcceleratorSettings*);
  78 + static void alternative_edited(GtkCellRendererAccel*, gchar*, guint, GdkModifierType, guint, V3270AcceleratorSettings*);
  79 +
72 /*--[ Implement ]------------------------------------------------------------------------------------*/ 80 /*--[ Implement ]------------------------------------------------------------------------------------*/
73 81
74 static void V3270AcceleratorSettings_class_init(V3270AcceleratorSettingsClass *klass) 82 static void V3270AcceleratorSettings_class_init(V3270AcceleratorSettingsClass *klass)
@@ -95,13 +103,23 @@ @@ -95,13 +103,23 @@
95 // Create Accelerator list 103 // Create Accelerator list
96 GtkCellRenderer * text_renderer = gtk_cell_renderer_text_new(); 104 GtkCellRenderer * text_renderer = gtk_cell_renderer_text_new();
97 105
98 - GtkCellRenderer * accel_renderer = gtk_cell_renderer_accel_new(); 106 + GtkCellRenderer * accel_renderer[] = { gtk_cell_renderer_accel_new(), gtk_cell_renderer_accel_new() };
  107 +
  108 + g_object_set(
  109 + accel_renderer[0],
  110 + "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
  111 + "editable", TRUE,
  112 + NULL);
  113 +
99 g_object_set( 114 g_object_set(
100 - accel_renderer, 115 + accel_renderer[1],
101 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER, 116 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
102 "editable", TRUE, 117 "editable", TRUE,
103 NULL); 118 NULL);
104 119
  120 + g_signal_connect (G_OBJECT (accel_renderer[0]), "accel_edited", G_CALLBACK (accel_edited), widget);
  121 + g_signal_connect (G_OBJECT (accel_renderer[1]), "accel_edited", G_CALLBACK (alternative_edited), widget);
  122 +
105 widget->store = GTK_LIST_STORE(gtk_list_store_new(COLUMNS, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT, G_TYPE_INT, G_TYPE_UINT)); 123 widget->store = GTK_LIST_STORE(gtk_list_store_new(COLUMNS, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT, G_TYPE_INT, G_TYPE_UINT));
106 124
107 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(widget->store),1,GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID); 125 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(widget->store),1,GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
@@ -124,7 +142,7 @@ @@ -124,7 +142,7 @@
124 GTK_TREE_VIEW(view), 142 GTK_TREE_VIEW(view),
125 -1, 143 -1,
126 _("Accelerator"), 144 _("Accelerator"),
127 - accel_renderer, 145 + accel_renderer[0],
128 "accel-mods", MAIN_MASK, 146 "accel-mods", MAIN_MASK,
129 "accel-key", MAIN_VALUE, 147 "accel-key", MAIN_VALUE,
130 NULL 148 NULL
@@ -134,7 +152,7 @@ @@ -134,7 +152,7 @@
134 GTK_TREE_VIEW(view), 152 GTK_TREE_VIEW(view),
135 -1, 153 -1,
136 _("Alternative"), 154 _("Alternative"),
137 - accel_renderer, 155 + accel_renderer[1],
138 "accel-mods", ALTERNATIVE_MASK, 156 "accel-mods", ALTERNATIVE_MASK,
139 "accel-key", ALTERNATIVE_VALUE, 157 "accel-key", ALTERNATIVE_VALUE,
140 NULL 158 NULL
@@ -155,7 +173,8 @@ @@ -155,7 +173,8 @@
155 gtk_grid_attach(GTK_GRID(widget),box,0,0,4,4); 173 gtk_grid_attach(GTK_GRID(widget),box,0,0,4,4);
156 } 174 }
157 175
158 - } 176 +}
  177 +
159 178
160 LIB3270_EXPORT GtkWidget * v3270_accelerator_settings_new() 179 LIB3270_EXPORT GtkWidget * v3270_accelerator_settings_new()
161 { 180 {
@@ -167,6 +186,163 @@ LIB3270_EXPORT GtkWidget * v3270_accelerator_settings_new() @@ -167,6 +186,163 @@ LIB3270_EXPORT GtkWidget * v3270_accelerator_settings_new()
167 return GTK_WIDGET(settings); 186 return GTK_WIDGET(settings);
168 } 187 }
169 188
  189 +struct AccelEditInfo
  190 +{
  191 + GtkWidget * widget;
  192 + gint response;
  193 + V3270Accelerator * origin;
  194 + V3270Accelerator * accel;
  195 + GtkTreePath *path;
  196 + guint accel_key;
  197 + GdkModifierType mask;
  198 + int id_key;
  199 + int id_mask;
  200 +};
  201 +
  202 +static gboolean check_accel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, struct AccelEditInfo * info)
  203 +{
  204 + static const gint columns[] = { MAIN_MASK, MAIN_VALUE, ALTERNATIVE_MASK, ALTERNATIVE_VALUE };
  205 + size_t ix;
  206 + GValue value;
  207 +
  208 + debug("%s",__FUNCTION__);
  209 +
  210 + for(ix = 0; ix < 2; ix++)
  211 + {
  212 + guint key;
  213 + GdkModifierType mask;
  214 +
  215 + memset(&value,0,sizeof(value));
  216 + gtk_tree_model_get_value(model, iter, columns[(ix * 2)], &value);
  217 + mask = (GdkModifierType) g_value_get_int(&value);
  218 + g_value_unset(&value);
  219 +
  220 + memset(&value,0,sizeof(value));
  221 + gtk_tree_model_get_value(model, iter, columns[(ix * 2)+1], &value);
  222 + key = g_value_get_uint(&value);
  223 + g_value_unset(&value);
  224 +
  225 + if(key == info->accel_key && mask == info->mask) {
  226 +
  227 + debug("************ Index %d cmp=%d",(unsigned int) ix, gtk_tree_path_compare(path, info->path));
  228 + GtkWidget * dialog;
  229 +
  230 + if(gtk_tree_path_compare(path, info->path))
  231 + {
  232 + // Another entry, rejects.
  233 + memset(&value,0,sizeof(value));
  234 + gtk_tree_model_get_value(model, iter, ACTION, &value);
  235 + info->accel = (V3270Accelerator *) g_value_get_pointer(&value);
  236 + g_value_unset(&value);
  237 +
  238 + debug("Key is already set on accel %s",v3270_accelerator_get_name(info->accel));
  239 +
  240 + // Ask for what the user wants to do.
  241 + dialog = gtk_message_dialog_new_with_markup(
  242 + GTK_WINDOW(gtk_widget_get_toplevel(info->widget)),
  243 + GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
  244 + GTK_MESSAGE_QUESTION,
  245 + GTK_BUTTONS_YES_NO,
  246 + _( "The selected accelerator is in use by action <b>%s</b> (<b>%s</b>)" ),
  247 + v3270_accelerator_get_description(info->accel),
  248 + v3270_accelerator_get_name(info->accel)
  249 + );
  250 +
  251 + gtk_message_dialog_format_secondary_markup(
  252 + GTK_MESSAGE_DIALOG(dialog),
  253 + _( "Assign it to action (<b>%s</b>)?"),
  254 + v3270_accelerator_get_name(info->origin)
  255 + );
  256 +
  257 + }
  258 + else
  259 + {
  260 + // It's on the same entry.
  261 + dialog = gtk_message_dialog_new_with_markup(
  262 + GTK_WINDOW(gtk_widget_get_toplevel(info->widget)),
  263 + GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
  264 + GTK_MESSAGE_QUESTION,
  265 + GTK_BUTTONS_CANCEL,
  266 + _( "The selected accelerator is in use by the same action" )
  267 + );
  268 +
  269 + }
  270 +
  271 + gtk_window_set_title(GTK_WINDOW(dialog),_("Accelerator is in use"));
  272 + gtk_widget_show_all(dialog);
  273 +
  274 + info->response = gtk_dialog_run(GTK_DIALOG(dialog));
  275 + if(info->response == GTK_RESPONSE_YES)
  276 + {
  277 + debug("%s: Removing accelerator from the other action",__FUNCTION__);
  278 +
  279 + }
  280 +
  281 + gtk_widget_destroy(dialog);
  282 +
  283 + return TRUE;
  284 +
  285 + }
  286 +
  287 + }
  288 +
  289 + return FALSE;
  290 +
  291 +}
  292 +
  293 +static void change_accel(V3270AcceleratorSettings *widget, gchar *path, guint accel_key, GdkModifierType mask, int id_key, int id_mask)
  294 +{
  295 + struct AccelEditInfo info = {
  296 + .response = GTK_RESPONSE_YES,
  297 + .widget = GTK_WIDGET(widget),
  298 + .accel = NULL,
  299 + .accel_key = accel_key,
  300 + .mask = mask,
  301 + .id_key = id_key,
  302 + .id_mask = id_mask,
  303 + .path = gtk_tree_path_new_from_string(path)
  304 + };
  305 +
  306 + GtkTreeIter iter;
  307 + if(gtk_tree_model_get_iter(GTK_TREE_MODEL(widget->store),&iter,info.path))
  308 + {
  309 + GValue value;
  310 + memset(&value,0,sizeof(value));
  311 + gtk_tree_model_get_value(GTK_TREE_MODEL(widget->store), &iter, ACTION, &value);
  312 + info.origin = (V3270Accelerator *) g_value_get_pointer(&value);
  313 + g_value_unset(&value);
  314 +
  315 + if(!info.origin)
  316 + {
  317 + g_warning("Can't identify the origin accelerator, aborting action");
  318 + return;
  319 + }
  320 +
  321 + }
  322 +
  323 + gtk_tree_model_foreach(GTK_TREE_MODEL(widget->store), (GtkTreeModelForeachFunc) check_accel, &info);
  324 +
  325 + gtk_tree_path_free(info.path);
  326 +
  327 + if(info.response == GTK_RESPONSE_YES)
  328 + {
  329 + debug("%s: Aplicar alteração",__FUNCTION__);
  330 +
  331 + }
  332 +
  333 +}
  334 +
  335 +static void accel_edited(GtkCellRendererAccel *renderer, gchar *path, guint accel_key, GdkModifierType mask, guint hardware_keycode, V3270AcceleratorSettings *widget)
  336 +{
  337 + debug("%s(%s)",__FUNCTION__,path);
  338 + change_accel(widget, path, accel_key, mask, MAIN_MASK, MAIN_VALUE);
  339 +}
  340 +
  341 +static void alternative_edited(GtkCellRendererAccel *renderer, gchar *path, guint accel_key, GdkModifierType mask, guint hardware_keycode, V3270AcceleratorSettings *widget)
  342 +{
  343 + debug("%s(%s)",__FUNCTION__,path);
  344 + change_accel(widget, path, accel_key, mask, ALTERNATIVE_MASK, ALTERNATIVE_VALUE);
  345 +}
170 346
171 void load(GtkWidget *widget, GtkWidget *terminal) 347 void load(GtkWidget *widget, GtkWidget *terminal)
172 { 348 {
@@ -195,8 +371,17 @@ void load(GtkWidget *widget, GtkWidget *terminal) @@ -195,8 +371,17 @@ void load(GtkWidget *widget, GtkWidget *terminal)
195 371
196 if(ix < G_N_ELEMENTS(keymaps)) 372 if(ix < G_N_ELEMENTS(keymaps))
197 { 373 {
198 - keymaps[ix].key = accel->key;  
199 - keymaps[ix].mods = accel->mods; 374 + if(accel->type == V3270_ACCELERATOR_TYPE_PFKEY)
  375 + {
  376 + keymaps[ix].key = GDK_F1 + (((V3270PFKeyAccelerator *)accel)->keycode - 1);
  377 + keymaps[ix].mods = 0;
  378 + }
  379 + else
  380 + {
  381 + keymaps[ix].key = accel->key;
  382 + keymaps[ix].mods = accel->mods;
  383 + }
  384 +
200 ix++; 385 ix++;
201 } 386 }
202 387
@@ -206,6 +391,7 @@ void load(GtkWidget *widget, GtkWidget *terminal) @@ -206,6 +391,7 @@ void load(GtkWidget *widget, GtkWidget *terminal)
206 // Add entry 391 // Add entry
207 GtkTreeIter iter; 392 GtkTreeIter iter;
208 gtk_list_store_append(store, &iter); 393 gtk_list_store_append(store, &iter);
  394 +
209 gtk_list_store_set( 395 gtk_list_store_set(
210 store, 396 store,
211 &iter, 397 &iter,
@@ -218,6 +404,7 @@ void load(GtkWidget *widget, GtkWidget *terminal) @@ -218,6 +404,7 @@ void load(GtkWidget *widget, GtkWidget *terminal)
218 -1 404 -1
219 ); 405 );
220 406
  407 +
221 } 408 }
222 409
223 } 410 }
@@ -226,3 +413,4 @@ void apply(GtkWidget *widget, GtkWidget *terminal) @@ -226,3 +413,4 @@ void apply(GtkWidget *widget, GtkWidget *terminal)
226 { 413 {
227 debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__); 414 debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__);
228 } 415 }
  416 +
src/terminal/keyboard/accelerator.c
@@ -114,6 +114,11 @@ @@ -114,6 +114,11 @@
114 114
115 break; 115 break;
116 116
  117 + case V3270_ACCELERATOR_TYPE_PFKEY:
  118 + if( ((V3270PFKeyAccelerator *)accel)->name )
  119 + return ((V3270PFKeyAccelerator *)accel)->name;
  120 + break;
  121 +
117 } 122 }
118 123
119 return v3270_accelerator_get_name(accel); 124 return v3270_accelerator_get_name(accel);