1 #ifdef COPYRIGHT_INFORMATION
2 #include "gplv3.h"
3 #endif
4 /*
5 * Copyright (C) 2002-2012 Edscott Wilson Garcia
6 * EMail: edscott@users.sf.net
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program;
21 */
22 //////////////////////////////////////////////////////////////////////////
23 #include "tagfile.h"
24 #include "rodent_gridview.h"
25 #include "rodent_popup_callbacks.h"
26 //////////////////////////////////////////////////////////////////////////
27 #define IS_SEQUENCE_CTL 0x01
28 #define IS_SEQUENCE_CHILD 0x02
29 #define IS_SEQUENCE_NESTED 0x03
30
31 #define IS_CHOICE_CTL 0x010
32 #define IS_CHOICE_CHILD 0x020
33 #define IS_CHOICE_NESTED 0x030
34
35 #define IS_ALL_CTL 0x0100
36 #define IS_ALL_CHILD 0x0200
37 #define IS_ALL_NESTED 0x0300
38
39 #define IS_HIDDEN_ROW 0x01000
40
41 #define HIDDEN_COLOR "#990000"
42 #define EDIT_COLOR "blue"
43 #define READONLY_COLOR "gray"
44 #define REQUIRED_COLOR "red"
45
46 static GHashTable *noneditable_hash=NULL;
47
48 enum {
49 H_TAG_ITEM_COLUMN,
50 H_ATTRIBUTE_ITEM_COLUMN,
51 H_PIXBUF_COLUMN,
52 H_NS_COLUMN,
53 H_TAG_COLUMN,
54 H_ATTRIBUTE_COLUMN,
55 H_VALUE_COLUMN,
56 H_BUTTON_COLUMN,
57 H_COLOR_COLUMN,
58 H_FLAG_COLUMN,
59 H_TREE_COLUMNS
60 };
61
62 enum {
63 UNDEFINED_DATA,
64 TABLE_DATA,
65 TAG_DATA,
66 ATTRIBUTE_DATA
67 };
68
69 /////////////////////////////////////////////////////////////////////////
70 // FUNCTIONS
71 /////////////////////////////////////////////////////////////////////////
72 /*static GdkColor black={0,0,0,0};
73 static GdkColor blue={0,0x0,0x0,0x7777};
74 static GdkColor grey={0,0x6666,0x6666,0x6666};
75 static GdkColor red={0,0xdddd,0x0,0x0};*/
76
77 static GdkPixbuf *broken=NULL;
78 static GdkPixbuf *OK=NULL;
79 static GdkPixbuf *KO=NULL;
80 static GdkPixbuf *index_pix=NULL;
81 static GdkPixbuf *index_pix2=NULL;
82 static GdkPixbuf *list_add=NULL;
83 static GdkPixbuf *question=NULL;
84 static GdkPixbuf *list_remove=NULL;
85 static GdkPixbuf *bold=NULL;
86 static GdkPixbuf *redball=NULL;
87 static GdkPixbuf *greenball=NULL;
88 static GdkPixbuf *red=NULL;
89 static GdkPixbuf *green=NULL;
90 static GdkPixbuf *blue=NULL;
91 static GdkPixbuf *folder_red=NULL;
92 static GdkPixbuf *folder_green=NULL;
93 static GdkPixbuf *keyboard=NULL;
94 static GdkPixbuf *strikethrough=NULL;
95 static GdkPixbuf *include_on=NULL;
96 static GdkPixbuf *include_off=NULL;
97 static GdkPixbuf *repeat_value=NULL;
98 static GHashTable *dialog_hash = NULL;
99 static gchar *
mod_string(guint mask)100 mod_string(guint mask){
101 if (!mask) return NULL;
102 gchar *mod=g_strdup("");
103 if (mask & GDK_SHIFT_MASK) {
104 gchar *g = g_strconcat (mod,_("Shift"), "+", NULL);
105 g_free(mod);
106 mod = g;
107 }
108 if (mask & GDK_CONTROL_MASK) {
109 gchar *g = g_strconcat (mod,_("Control"), "+", NULL);
110 g_free(mod);
111 mod = g;
112 }
113 if (mask & GDK_MOD1_MASK) {
114 gchar *g = g_strconcat (mod,_("Alt"), "+", NULL);
115 g_free(mod);
116 mod = g;
117 }
118 if (strlen(mod)==0) {
119 g_free(mod);
120 mod = g_strdup_printf ("0x%x+", mask);
121 }
122 return mod;
123 }
key_string(guint keyval)124 static gchar *key_string(guint keyval){
125 gchar *key=NULL;
126 if ((keyval > 0x40 && keyval < 0x5b) ||(keyval >0x02f && keyval < 0x03a)) {
127 key = g_strdup_printf("%c", keyval);
128 }
129 else if (keyval > 0x60 && keyval < 0x7b) {
130 key = g_strdup_printf("%c", keyval);
131 }
132 else if (keyval > 0xffbd && keyval < 0xffca) { // function keys f1-f12
133 key = g_strdup_printf("F%d", keyval-0xffbd);
134 }
135 else { // other keys
136 switch (keyval){
137 case GDK_KEY_Home: key = g_strdup(_("Home")); break;
138 case GDK_KEY_Left: key = g_strdup(_("Left")); break;
139 case GDK_KEY_Up: key = g_strdup(_("Up")); break;
140 case GDK_KEY_Right: key = g_strdup(_("Right")); break;
141 case GDK_KEY_Down: key = g_strdup(_("Down")); break;
142 case GDK_KEY_Page_Up: key = g_strdup(_("Page up")); break;
143 case GDK_KEY_Page_Down: key = g_strdup(_("Page down")); break;
144 case GDK_KEY_End: key = g_strdup(_("End")); break;
145 case GDK_KEY_Begin: key = g_strdup(_("Begin")); break;
146 case GDK_KEY_Delete: key = g_strdup(_("Delete")); break;
147 case GDK_KEY_Insert: key = g_strdup(_("Insert")); break;
148 case GDK_KEY_equal: key = g_strdup(_("Equal")); break;
149 case GDK_KEY_plus: key = g_strdup(_("Plus")); break;
150 case GDK_KEY_minus: key = g_strdup(_("Minus")); break;
151 case GDK_KEY_KP_Add: key = g_strdup(_("Add")); break;
152 case GDK_KEY_KP_Subtract: key = g_strdup(_("Subtract")); break;
153 }
154 }
155 if (!key) key = g_strdup_printf("0x%x", keyval);
156 return key;
157 }
158
159
160 static void
set_editable_element(xmltree_t * xmltree_p,const gchar * element,gboolean state)161 set_editable_element(xmltree_t *xmltree_p, const gchar *element, gboolean state){
162 if (!xmltree_p || !element) return ;
163 g_hash_table_replace(xmltree_p->editable_elements, g_strdup(element), GINT_TO_POINTER(state));
164 return;
165 }
166
167 static gboolean
get_editable_element(xmltree_t * xmltree_p,const gchar * element)168 get_editable_element(xmltree_t *xmltree_p, const gchar *element){
169 if (!xmltree_p || !element) return FALSE;
170 void *r = g_hash_table_lookup(xmltree_p->editable_elements, element);
171 return GPOINTER_TO_INT(r);
172 }
173
174 static gboolean
get_editable_attribute(xmltree_t * xmltree_p,const gchar * attribute)175 get_editable_attribute(xmltree_t *xmltree_p, const gchar *attribute){
176 gboolean retval = FALSE;
177 if (!attribute) return FALSE;
178 gchar **p = xmltree_p->editable_attributes;
179 for (;p && *p; p++){
180 if (strcasecmp(*p, attribute) == 0){
181 NOOP( "editatble set for %s\n", *p);
182 retval = TRUE;
183 break;
184 }
185 }
186 NOOP( "get_editable_attribute(%s) = %d\n", attribute, retval);
187 return retval;
188 }
189
190 #if 0
191 static Tag_item_t *
192 set_attribute_color(GtkTreeModel *treemodel, GtkTreeIter *iter){
193 gchar *attribute=NULL;
194 Tag_item_t *tag;
195 Tag_item_t *parent_tag;
196 Attribute_item_t *item = NULL;
197 xmltree_t *xmltree_p = g_object_get_data(G_OBJECT(treemodel), "xmltree_p");
198 gtk_tree_model_get(treemodel, iter,
199 H_TAG_ITEM_COLUMN, &tag,
200 H_ATTRIBUTE_COLUMN, &attribute,
201 H_ATTRIBUTE_ITEM_COLUMN, &item, -1);
202 if (!item) parent_tag = get_parent_tag(tag);
203 else parent_tag=get_attribute_parent(item);
204
205 if (!attribute) {
206 gtk_tree_store_set((GtkTreeStore *) treemodel, iter, H_COLOR_COLUMN, "black", -1);
207 } else {
208 if (noneditable_hash && g_hash_table_lookup(noneditable_hash, item)){
209 gtk_tree_store_set((GtkTreeStore *) treemodel, iter, H_COLOR_COLUMN, READONLY_COLOR, -1);
210 } else if (get_editable_attribute(xmltree_p, attribute)){
211 gtk_tree_store_set((GtkTreeStore *) treemodel, iter, H_COLOR_COLUMN, EDIT_COLOR, -1);
212 } else if (get_editable_element(xmltree_p, get_tag_name(parent_tag))){
213 gtk_tree_store_set((GtkTreeStore *) treemodel, iter, H_COLOR_COLUMN, EDIT_COLOR, -1);
214 } else {
215 gtk_tree_store_set((GtkTreeStore *) treemodel, iter, H_COLOR_COLUMN, READONLY_COLOR, -1);
216 }
217 }
218
219 return tag;
220
221 }
222 #endif
223
224
225 static
226 gboolean
switch_colors(GtkTreeModel * treemodel,GtkTreePath * treepath,GtkTreeIter * iter,gpointer data)227 switch_colors( GtkTreeModel * treemodel,
228 GtkTreePath * treepath,
229 GtkTreeIter * iter,
230 gpointer data)
231 {
232 //Tag_item_t *tag = set_attribute_color(treemodel, iter);
233 return FALSE;
234 }
235
236
237 static void
set_button_serial(GtkTreeView * treeview,GdkEventButton * event)238 set_button_serial(GtkTreeView *treeview, GdkEventButton * event){
239 GtkTreePath *treepath;
240 GtkTreeViewColumn *column;
241 if(!gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
242 &treepath, &column, NULL, NULL)) {
243 return;
244 }
245 gchar *path = gtk_tree_path_to_string (treepath);
246 gchar *oldpath = g_object_get_data(G_OBJECT(treeview), "button_path");
247 g_free(oldpath);
248 g_object_set_data(G_OBJECT(treeview), "button_path", path);
249 g_object_set_data(G_OBJECT(treeview), "button_column", column);
250 gtk_tree_path_free(treepath);
251 return;
252 }
253
254 static void
unset_button_serial(GtkTreeView * treeview,GdkEventButton * event)255 unset_button_serial(GtkTreeView *treeview, GdkEventButton * event){
256 gchar *oldpath = g_object_get_data(G_OBJECT(treeview), "button_path");
257 g_free(oldpath);
258 g_object_set_data(G_OBJECT(treeview), "button_path", NULL);
259 g_object_set_data(G_OBJECT(treeview), "button_column", NULL);
260
261 }
262
263
264 static gboolean
check_button_serial(GtkTreeView * treeview,GdkEventButton * event)265 check_button_serial(GtkTreeView *treeview, GdkEventButton * event){
266 gint status=FALSE;
267 GtkTreePath *treepath;
268 GtkTreeViewColumn *column;
269 if(gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
270 &treepath, &column, NULL, NULL)) {
271 gchar *path = gtk_tree_path_to_string (treepath);
272 gchar *oldpath =
273 g_object_get_data(G_OBJECT(treeview), "button_path");
274 GtkTreeViewColumn *oldcolumn =
275 g_object_get_data(G_OBJECT(treeview), "button_column");
276 status = (oldpath && path &&
277 strcmp(path, oldpath)==0 &&
278 column == oldcolumn);
279 NOOP("path=%s oldpath=%s column=0x%x oldcolumn=0x%x status=%d\n",
280 path, oldpath,
281 GPOINTER_TO_INT(column), GPOINTER_TO_INT(oldcolumn),
282 status);
283 g_free(path);
284 gtk_tree_path_free(treepath);
285 }
286 return status;
287 }
288
289
290 static
291 gboolean
find_keybinding(GtkTreeModel * model,GtkTreePath * treepath,GtkTreeIter * iter,gpointer data)292 find_keybinding( GtkTreeModel * model,
293 GtkTreePath * treepath,
294 GtkTreeIter * iter,
295 gpointer data)
296 {
297 Attribute_item_t *Attribute_item_p;
298
299 gtk_tree_model_get (model, iter,
300 H_ATTRIBUTE_ITEM_COLUMN, &Attribute_item_p,
301 -1);
302 if (Attribute_item_p) return FALSE; // Only affect tags, not attributes.
303 Tag_item_t *Tag_item_p;
304 gtk_tree_model_get (model, iter,
305 H_TAG_ITEM_COLUMN, &Tag_item_p,
306 -1);
307 gint flag = GPOINTER_TO_INT(get_tag_item_user_data(Tag_item_p));
308
309 if (flag & 0x01){
310 // change color to red.
311 gtk_tree_store_set(GTK_TREE_STORE(model), iter,
312 H_PIXBUF_COLUMN, repeat_value,
313 H_COLOR_COLUMN, "red",
314 -1);
315 } else {
316 // change color to black.
317 GdkPixbuf *pixbuf = keyboard;
318 Attribute_item_t *att_p = get_attribute(Tag_item_p, "icon_id");
319 if (att_p) {
320 const gchar *icon_id = get_attribute_value(att_p);
321 if (icon_id && strlen(icon_id)){
322 pixbuf = rfm_get_pixbuf(icon_id, TINY_ICON_SIZE);
323 }
324 }
325 gtk_tree_store_set(GTK_TREE_STORE(model), iter,
326 H_PIXBUF_COLUMN, pixbuf,
327 H_COLOR_COLUMN, "black",
328 -1);
329 g_object_unref(pixbuf);
330
331 }
332 return FALSE;
333 }
334
335
336 static
337 gboolean
check_clean(GtkTreeModel * model,GtkTreePath * treepath,GtkTreeIter * iter,gpointer data)338 check_clean( GtkTreeModel * model,
339 GtkTreePath * treepath,
340 GtkTreeIter * iter,
341 gpointer data)
342 {
343 gchar *color;
344 gboolean *clean = data;
345 gtk_tree_model_get (model, iter,
346 H_COLOR_COLUMN, &color,
347 -1);
348 if (!color) return FALSE;
349 if (strcmp(color, "red")==0){
350 *clean = FALSE;
351 rfm_confirm(NULL, GTK_MESSAGE_ERROR, _("You may not specify duplicate patterns"),NULL, NULL);
352 return TRUE;
353 }
354 return FALSE;
355 }
356
357
358 /////////////////////////////////////////////////////////////////////////
359 // DIALOG CALLBACKS
360 /////////////////////////////////////////////////////////////////////////
361
362 static void
ak_destroy(GtkButton * button,gpointer data)363 ak_destroy (GtkButton * button, gpointer data) {
364 GtkEntry *entry = data;
365 GtkWidget *window = g_object_get_data(G_OBJECT(entry), "attribute_window");
366 gchar *key = g_object_get_data(G_OBJECT(window), "path_string");
367
368 g_hash_table_steal(dialog_hash, key);
369 g_free(key);
370 gtk_widget_destroy(window);
371
372 }
373 static gboolean
on_destroy_child(GtkWidget * window,GdkEvent * event,gpointer data)374 on_destroy_child (GtkWidget *window, GdkEvent *event, gpointer data) {
375 gchar *path_string = g_object_get_data(G_OBJECT(window), "path_string");
376 if(path_string) {
377 g_hash_table_steal (dialog_hash, path_string);
378 g_object_set_data(G_OBJECT(window), "path_string", NULL);
379 g_free(path_string);
380 }
381 return FALSE;
382 }
383
384
385 static gboolean
signal_keyboard_event(GtkWidget * entry,GdkEventKey * event,gpointer data)386 signal_keyboard_event (
387 GtkWidget *entry,
388 GdkEventKey * event,
389 gpointer data
390 ) {
391 /* asian Input methods */
392 if(event->keyval == GDK_KEY_space && (event->state & (GDK_MOD1_MASK | GDK_SHIFT_MASK))) {
393 return FALSE;
394 }
395 gchar *key=NULL;
396 gchar *key_s=key_string(event->keyval);
397 guint mod=0;
398 gchar *mod_s=NULL;
399 if (event->keyval == GDK_KEY_Tab
400 || event->keyval == GDK_KEY_Return
401 || event->keyval == GDK_KEY_KP_Enter) return FALSE;
402 if (event->state ) {
403 if (event->state & GDK_SHIFT_MASK) mod |= GDK_SHIFT_MASK;
404 if (event->state & GDK_CONTROL_MASK) mod |= GDK_CONTROL_MASK;
405 if (event->state & (GDK_MOD1_MASK|GDK_MOD5_MASK)) mod |= (GDK_MOD1_MASK|GDK_MOD5_MASK) ;
406 mod_s=mod_string(mod);
407 }
408 if (mod_s) key=g_strdup_printf("%s%s", mod_s, key_s);
409 else key=g_strdup_printf("%s", key_s);
410 gtk_entry_set_text (GTK_ENTRY(entry), key);
411 g_free(key);
412 g_free(key_s);
413 g_free(mod_s);
414 g_object_set_data(G_OBJECT(entry), "mask", GUINT_TO_POINTER(mod));
415 g_object_set_data(G_OBJECT(entry), "key", GUINT_TO_POINTER(event->keyval));
416
417
418 return TRUE;
419
420 }
421 static void
ak_apply(GtkButton * button,gpointer data)422 ak_apply (GtkButton * button, gpointer data) {
423 GtkWidget *entry = data;
424 GtkWidget *window = g_object_get_data(G_OBJECT(entry), "attribute_window");
425 GtkTreeModel *model = g_object_get_data(G_OBJECT(window), "model");
426 const gchar *path_string = g_object_get_data(G_OBJECT(window), "path_string");
427 struct xmltree_t *xmltree_p = g_object_get_data(G_OBJECT(window), "xmltree_p");
428 GtkTreeIter iter;
429 const gchar *value = NULL;
430
431 if (GTK_IS_ENTRY(entry)) value = gtk_entry_get_text(GTK_ENTRY(entry));
432 #if GTK_MAJOR_VERSION==2 && GTK_MINOR_VERSION<24
433 else if (GTK_IS_COMBO_BOX(entry)) value = gtk_combo_box_get_active_text(GTK_COMBO_BOX(entry));
434 #else
435 else if (GTK_IS_COMBO_BOX_TEXT(entry)) value = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(entry));
436 #endif
437 if (!value) value ="gtk_entry_get_text returns NULL";
438
439 const gchar *variable_type = g_object_get_data(G_OBJECT(entry), "variable_type");
440 NOOP( "variable type = %s\n", variable_type);
441 if (variable_type){
442 if (strstr(variable_type, "double")){
443 char *r;
444 errno=0;
445 double d = strtod(value, &r);
446 if (errno==ERANGE || (!d && value==r)){
447 gchar *c = g_strdup_printf("<b>%s</b> cannot be converted to a valid double", value);
448 rfm_confirm(NULL, GTK_MESSAGE_ERROR, c, NULL, NULL);
449 g_free(c);
450 return;
451 }
452 }
453 }
454
455 // find attribute with value repeated.
456 GtkTreeStore *store;
457 GtkTreeModelFilter *filter_model = g_object_get_data(G_OBJECT(window), "filter_model");
458 if (filter_model) store = GTK_TREE_STORE(gtk_tree_model_filter_get_model(filter_model));
459 else store = GTK_TREE_STORE(model);
460 NOOP( "pathstring=%s\n", path_string);
461 GtkTreePath *treepath = gtk_tree_path_new_from_string (path_string);
462 if (filter_model){
463 GtkTreePath *tp = gtk_tree_model_filter_convert_path_to_child_path(filter_model, treepath);
464 if (!tp){
465 fprintf(stderr, "cannot convert filter path to child path\n");
466 return;
467 }
468 gtk_tree_path_free(treepath);
469 treepath=tp;
470 }
471
472 if (gtk_tree_model_get_iter (GTK_TREE_MODEL(store), &iter, treepath)){
473
474 // Get associated attribute_item_p and parent tag_item_p
475 Tag_item_t *Tag_item_p;
476 Attribute_item_t *Attribute_item_p;
477 gchar *attribute;
478 gtk_tree_model_get (GTK_TREE_MODEL(store), &iter,
479 H_TAG_ITEM_COLUMN, &Tag_item_p,
480 H_ATTRIBUTE_COLUMN, &attribute,
481 H_ATTRIBUTE_ITEM_COLUMN, &Attribute_item_p,
482 -1);
483 set_attribute_value(Attribute_item_p, value);
484
485 /// XXX XSD stuff ....
486 // update the viewable treeview and model
487 gtk_tree_store_set (store, &iter,
488 H_VALUE_COLUMN, value,
489 H_PIXBUF_COLUMN, get_attribute_pixbuf(Attribute_item_p),
490 -1);
491 set_attribute_colorXSD(GTK_TREE_MODEL(store), &iter);
492 update_iconsXSD(GTK_TREE_MODEL(store), iter);
493
494 //////////////////////
495
496 if (get_editable_attribute(xmltree_p, attribute)) {
497 NOOP( "Gotcha: update parent too...\n");
498 GtkTreeIter parent;
499 if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(store), &parent, &iter)){
500 gtk_tree_store_set (store, &parent,
501 H_VALUE_COLUMN, value,
502 -1);
503 }
504 }
505
506 // if not key selection, we are done.
507 ;
508 if (!g_object_get_data(G_OBJECT(window), "XMLTREE_key_type")){
509 gchar *key = g_object_get_data(G_OBJECT(window), "path_string");
510 g_hash_table_steal(dialog_hash, key);
511 g_free(key);
512 gtk_widget_destroy(window);
513 return;
514 }
515
516 // XXX from here down are specifics to keybindings dialog...
517 // Must update "mask" and "key" attributes as well.
518 Attribute_item_t *a_p;
519 a_p = get_attribute(Tag_item_p, "key");
520 if (a_p){
521 guint key = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(entry), "key"));
522 gchar *key_s = g_strdup_printf("%d", key);
523 set_attribute_value(a_p, key_s);
524 g_free(key_s);
525 }
526 a_p = get_attribute(Tag_item_p, "mask");
527 if (a_p){
528 guint mask = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(entry), "mask"));
529 gchar *mask_s = g_strdup_printf("%d", mask);
530 set_attribute_value(a_p, mask_s);
531 g_free(mask_s);
532 }
533 }
534 gtk_tree_path_free(treepath);
535
536 // XXX: the repeat stuff is specific to keybindings dialog...
537 // Duplicate test
538 Tag_t *Tag_p = g_object_get_data(G_OBJECT(model), "Tag_p");
539 GSList *list = get_full_attribute_list(Tag_p, NULL, "Keybinding");
540 GSList *tmp = list;
541 for (;tmp && tmp->data; tmp = tmp->next){
542 Attribute_item_t *Attribute_item_p = tmp->data;
543 Tag_item_t *parent = get_attribute_parent(Attribute_item_p);
544 set_tag_item_user_data(parent, GINT_TO_POINTER(0x0));
545 }
546 for (tmp = list;tmp && tmp->data; tmp = tmp->next){
547 Attribute_item_t *Attribute_item_p = tmp->data;
548 Tag_item_t *parent = get_attribute_parent(Attribute_item_p);
549 const gchar *value = get_attribute_value(Attribute_item_p);
550 GSList *tmp2 = tmp->next;
551 //NOOP(stderr, "duptest: %s\n", value); continue;
552 gboolean dupped = FALSE;
553 for (;tmp2 && tmp2->data; tmp2 = tmp2->next){
554 const gchar *value2 = get_attribute_value((Attribute_item_t *)tmp2->data);
555 Tag_item_t *parent2 = get_attribute_parent((Attribute_item_t *)(tmp2->data));
556 if (!parent || !parent2) g_error("terribly wrong\n");
557 if (value && value2 && strcmp(value, value2) == 0){
558 dupped = TRUE;
559 set_tag_item_user_data(parent2, GINT_TO_POINTER(0x01));
560 // NOOP(stderr, "redlisted: %s, %s\n", get_tag_name(parent), get_tag_name(parent2));
561 }
562 }
563 if (dupped) {
564 set_tag_item_user_data(parent, GINT_TO_POINTER(0x01));
565 }
566 }
567 g_slist_free(list);
568 gtk_tree_model_foreach(GTK_TREE_MODEL(store), find_keybinding, NULL);
569
570
571 gchar *key = g_object_get_data(G_OBJECT(window), "path_string");
572
573 g_hash_table_steal(dialog_hash, key);
574 g_free(key);
575
576 gtk_widget_destroy(window);
577
578
579 }
580
581 static void
ak_erase(GtkButton * button,gpointer data)582 ak_erase (GtkButton * button, gpointer data) {
583 GtkEntry *entry = data;
584 gtk_entry_set_text(entry, "");
585 }
586
587 /////////////////////////////////////////////////////////////////////////
588 // DIALOG CREATION FUNCTIONALITY
589 /////////////////////////////////////////////////////////////////////////
590
591 static void *
tag_box(const gchar * head,const gchar * tag,const gchar * value,gint flag,Tag_item_t * parent_tag)592 tag_box(const gchar *head, const gchar *tag, const gchar *value, gint flag, Tag_item_t *parent_tag){
593 GtkWidget *vbox = rfm_vbox_new (FALSE, 0);
594
595 GtkWidget *hbox = rfm_hbox_new (FALSE, 0);
596 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 3);
597 GtkWidget *label = gtk_label_new("");
598 gchar *text = g_strdup_printf("<b>%s</b> ", head);
599 gtk_label_set_markup(GTK_LABEL(label), text);
600 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 3);
601
602 hbox = rfm_hbox_new (FALSE, 0);
603 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 3);
604 text = g_strdup_printf("<i>%s:</i> ", strcasecmp(tag,"text")?tag:get_tag_name(parent_tag));
605 label = gtk_label_new("");
606 gtk_label_set_markup(GTK_LABEL(label), text);
607 g_free(text);
608 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 3);
609
610 GtkEntryBuffer *entry_buffer =
611 gtk_entry_buffer_new (value, -1);
612
613 //if (value) g_strstrip(value);
614 GtkWidget *entry = NULL;
615
616 gchar *att_name = g_strdup_printf("%s:type", tag);
617 Attribute_item_t *type_item = get_attribute(parent_tag, att_name);
618 g_free(att_name);
619 const gchar *variable_type = NULL;
620 const gchar *variable_subtype = NULL;
621 if (type_item){
622 variable_type = get_attribute_value(type_item);
623 Attribute_item_t *subtype_item = get_attribute(parent_tag, "list:itemType");
624 if (subtype_item) variable_subtype = get_attribute_value(subtype_item);
625 if (variable_type && strstr(variable_type, "integer")){
626 gint min = 1;
627 gint max = 99999999;
628 gint step = 1;
629 entry = gtk_spin_button_new_with_range((double)min, (double)max, (double)step);
630 }
631 }
632
633 // do we have a pattern restriction?
634
635 att_name = g_strdup_printf("%s:pattern", tag);
636 Attribute_item_t *pattern_item = get_attribute(parent_tag, att_name);
637 g_free(att_name);
638 if (pattern_item){
639 const gchar *pattern = get_attribute_value(pattern_item);
640 gchar **pattern_v = g_strsplit(pattern, "|", -1);
641 gchar **p = pattern_v;
642 #if GTK_MAJOR_VERSION==2 && GTK_MINOR_VERSION<24
643 // use a text combo
644 entry = gtk_combo_box_new_text();
645 if (value && strlen(value)) gtk_combo_box_prepend_text(GTK_COMBO_BOX(entry), value);
646 for (;p && *p; p++){
647 g_strstrip(*p);
648 if (strcmp(value, *p)==0) continue;
649 gtk_combo_box_append_text(GTK_COMBO_BOX(entry), *p);
650 }
651 #else
652 // use a text combo
653 entry = gtk_combo_box_text_new();
654 if (value && strlen(value)) gtk_combo_box_text_prepend_text(GTK_COMBO_BOX_TEXT(entry), value);
655 for (;p && *p; p++){
656 g_strstrip(*p);
657 if (value && strcmp(value, *p)==0) continue;
658 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(entry), *p);
659 }
660 #endif
661 g_strfreev(pattern_v);
662 gtk_combo_box_set_active(GTK_COMBO_BOX(entry), 0);
663 } else if (!entry){
664 entry = gtk_entry_new_with_buffer(entry_buffer);
665 }
666
667
668 //gchar *pattern;
669 gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 3);
670
671 // single key input
672 if (flag==1) {
673 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK (signal_keyboard_event), NULL);
674 }
675 //gtk_container_add (GTK_CONTAINER (vbox), hbox);
676 if (variable_type){
677 g_object_set_data(G_OBJECT(entry), "variable_type",(void *) variable_type);
678 g_object_set_data(G_OBJECT(entry), "variable_subtype",(void *) variable_subtype);
679 hbox = rfm_hbox_new (FALSE, 0);
680 label = gtk_label_new("");
681 gchar *g = g_strdup_printf("<i>%s%s%s</i>", strchr(variable_type, ':')?
682 strchr(variable_type, ':')+1: variable_type,
683 (variable_subtype==NULL)?"":":",
684 (variable_subtype==NULL)?"":
685 strchr(variable_subtype, ':')?
686 strchr(variable_subtype, ':')+1: variable_subtype);
687 gtk_label_set_markup(GTK_LABEL(label), g);
688 g_free(g);
689 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 3);
690 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 3);
691 }
692 hbox = rfm_hbox_new (FALSE, 0);
693 GtkWidget *button;
694 button = rfm_mk_little_button ("xffm/stock_ok",
695 (gpointer)ak_apply, entry, _("Apply"));
696 gtk_widget_set_can_focus (button, TRUE);
697 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 3);
698
699 if (pattern_item == NULL){
700 button = rfm_mk_little_button ("xffm/stock_clear",
701 (gpointer)ak_erase, entry, _("Clear"));
702 gtk_widget_set_can_focus (button, TRUE);
703 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 3);
704 }
705
706 button = rfm_mk_little_button ("xffm/stock_cancel",
707 (gpointer)ak_destroy, entry, _("Cancel"));
708 gtk_widget_set_can_focus (button, TRUE);
709 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 3);
710
711 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 3);
712 g_object_set_data(G_OBJECT(vbox), "entry", entry);
713
714 return vbox;
715 }
716
717 #if 0
718 static void *
719 string_box(const gchar *head, const gchar *tag, const gchar *value){
720 GtkWidget *vbox = rfm_vbox_new (FALSE, 0);
721
722 GtkWidget *hbox = rfm_hbox_new (FALSE, 0);
723 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 3);
724 GtkWidget *label = gtk_label_new("");
725 gchar *text = g_strdup_printf("<b>%s</b> ", head);
726 gtk_label_set_markup(GTK_LABEL(label), text);
727 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 3);
728
729 hbox = rfm_hbox_new (FALSE, 0);
730 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 3);
731 text = g_strdup_printf("<i>%s:</i> ", tag);
732 label = gtk_label_new("");
733 gtk_label_set_markup(GTK_LABEL(label), text);
734 g_free(text);
735 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 3);
736
737 GtkEntryBuffer *entry_buffer =
738 gtk_entry_buffer_new (value, -1);
739 GtkWidget *entry =
740 gtk_entry_new_with_buffer(entry_buffer);
741 gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 3);
742
743 //g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK (signal_keyboard_event), NULL);
744 //gtk_container_add (GTK_CONTAINER (vbox), hbox);
745
746 hbox = rfm_hbox_new (FALSE, 0);
747 GtkWidget *button;
748 button = rfm_mk_little_button ("xffm/stock_ok",
749 (gpointer)ak_apply, entry, _("Apply"));
750 gtk_widget_set_can_focus (button, TRUE);
751 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 3);
752
753 button = rfm_mk_little_button ("xffm/stock_edit-clear",
754 (gpointer)ak_erase, entry, _("Clear"));
755 gtk_widget_set_can_focus (button, TRUE);
756 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 3);
757
758 button = rfm_mk_little_button ("xffm/emblem_cancel",
759 (gpointer)ak_destroy, entry, _("Cancel"));
760 gtk_widget_set_can_focus (button, TRUE);
761 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 3);
762
763 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 3);
764 g_object_set_data(G_OBJECT(vbox), "entry", entry);
765
766 return vbox;
767 }
768 #endif
769
770 static void *
new_dialog(GtkWidget * vbox,const gchar * title)771 new_dialog (GtkWidget *vbox, const gchar *title){
772 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
773 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
774 gtk_window_set_title (GTK_WINDOW (window), title);
775 gtk_container_add (GTK_CONTAINER (window), vbox);
776 g_object_set_data(G_OBJECT(window), "vbox", vbox);
777 GtkWidget *entry = g_object_get_data(G_OBJECT(vbox), "entry");
778 g_object_set_data(G_OBJECT(entry), "attribute_window", window);
779 return (void *)window;
780 }
781
782 /////////////////////////////////////////////////////////////////////////
783 // WINDOW CALLBACKS
784 /////////////////////////////////////////////////////////////////////////
785 static void
on_destroy_k(GtkButton * button,gpointer user_data)786 on_destroy_k (GtkButton * button, gpointer user_data) {
787 gtk_main_quit ();
788 }
789
790
791 static void
button_cell_pressed(GtkTreeView * treeview,GtkTreePath * treepath,const gchar * column_title)792 button_cell_pressed(GtkTreeView *treeview, GtkTreePath *treepath, const gchar *column_title){
793 NOOP( "activate_f --> \"%s\"\n", column_title);
794 //copy content to one row above.
795 // Content:
796 GtkTreeIter sibling;
797
798 // This is the filter model
799 GtkTreeModelFilter *filter_model = g_object_get_data(G_OBJECT(treeview), "filter_model");
800 // Currently only set up for xsd treeview of associated xml.
801 if (!filter_model) return;
802 // This is the actual treestore
803 GtkTreeModel *treemodel = gtk_tree_model_filter_get_model(filter_model);
804
805 GtkTreePath *storepath = gtk_tree_model_filter_convert_path_to_child_path(filter_model, treepath);
806 if (!gtk_tree_model_get_iter(treemodel, &sibling, storepath)) {
807 fprintf(stderr, "*** button_cell_pressed(): Cannot get iter from treepath.\n");
808 return ;
809 }
810 gtk_tree_path_free(storepath);
811
812 static gboolean lock=FALSE;
813 if (lock) return;
814 lock = TRUE;
815 Tag_item_t *src_tag;
816 gint flag;
817 gtk_tree_model_get(treemodel, &sibling,
818 H_TAG_ITEM_COLUMN, &src_tag,
819 H_FLAG_COLUMN, &flag,
820 -1);
821
822 choice_callback(src_tag, treeview, treemodel, &sibling, flag);
823
824 lock = FALSE;
825
826 return;
827 }
828
829 static gboolean
activate_f(GtkTreeView * treeview,GtkTreePath * treepath,const gchar * column_title,GdkEventButton * event)830 activate_f(GtkTreeView *treeview, GtkTreePath *treepath, const gchar *column_title, GdkEventButton * event){
831 gint Xsize=45;
832 gint Ysize=45;
833 gchar *path = gtk_tree_path_to_string (treepath);
834 xmltree_t *xmltree_p = g_object_get_data(G_OBJECT(treeview), "xmltree_p");
835 if (column_title && strcmp(column_title, "*")==0) {
836 button_cell_pressed(treeview, treepath, column_title);
837 g_free(path);
838 return TRUE;
839 }
840 if (column_title && strcmp(column_title, _("Value"))==0) {
841 if (!dialog_hash){
842 dialog_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
843 }
844 TRACE( "hash lookup for window: %s\n", path);
845 GtkWidget *window = g_hash_table_lookup(dialog_hash, path);
846 if (!window) {
847 gchar *key=g_strdup(path);
848 gint tag_type = UNDEFINED_DATA;
849 // Retrieve value in _("XML tag") to see if we have a table.
850 // 1. Get associated treemodel
851 GtkTreeModel *model = gtk_tree_view_get_model(treeview);
852 // 2. Get the iter which corresponds to the treepath
853 GtkTreeIter iter;
854 gtk_tree_model_get_iter (model, &iter, treepath);
855 // Then we retrieve the values in the columns we will need.
856 gchar *tag;
857 gchar *attribute;
858 gchar *value;
859 Tag_item_t *parent_tag;
860 Attribute_item_t *attribute_item;
861 gint flag;
862 gtk_tree_model_get (model, &iter,
863 H_TAG_COLUMN, &tag,
864 H_ATTRIBUTE_COLUMN, &attribute,
865 H_TAG_ITEM_COLUMN, &parent_tag,
866 H_ATTRIBUTE_ITEM_COLUMN, &attribute_item,
867 H_VALUE_COLUMN, &value,
868 H_FLAG_COLUMN, &flag,
869 -1);
870 if (noneditable_hash && g_hash_table_lookup(noneditable_hash, attribute_item)) goto done;
871 if (flag & IS_ALL_CTL) goto done;
872 if (flag & IS_SEQUENCE_CTL) goto done;
873 // FIXME: also, get all parent tags, and if sequence ctl, return
874 GtkTreeIter c_iter = iter;
875 GtkTreeIter p_iter;
876 while (gtk_tree_model_iter_parent(model, &p_iter, &c_iter)){
877 gtk_tree_model_get (model, &p_iter,
878 H_FLAG_COLUMN, &flag,
879 -1);
880 if (flag & IS_ALL_CTL) goto done;
881 if (flag & IS_SEQUENCE_CTL) goto done;
882 c_iter= p_iter;
883 }
884
885 NOOP("tag=\"%s\", attribute=\"%s\"\n", tag, attribute);
886 if (tag && !attribute){
887 if (strcmp(tag, "TABLE")==0){
888 tag_type = TABLE_DATA;
889 } else {
890 tag_type = TAG_DATA;
891 }
892 }
893 else if (!tag && attribute){
894 tag_type = ATTRIBUTE_DATA;
895 }
896 switch (tag_type){
897 case TABLE_DATA:
898 NOOP("table data: %d!\n", tag_type);
899 break;
900 case ATTRIBUTE_DATA:;
901 const gchar *element_name = get_tag_name(parent_tag);
902
903 fprintf(stderr, "attribute data: %d!\n", tag_type);
904 if (attribute_item &&
905 !attribute_get_hidden(attribute_item) &&
906 get_editable_element(xmltree_p, element_name)){
907 const gchar *text = get_attribute_value(attribute_item);
908 if (!text) text = _("Modify");
909 gchar *attribute_title = g_strdup_printf("%s", _("<Modify value>"));
910 GtkWidget *box = tag_box(text, attribute, value, 2, parent_tag);
911 if (box) {
912 window = new_dialog(box, attribute_title);
913 g_object_set_data(G_OBJECT(window), "filter_model", g_object_get_data(G_OBJECT(treeview), "filter_model"));
914 g_object_set_data(G_OBJECT(window), "model", gtk_tree_view_get_model(treeview));
915 g_object_set_data(G_OBJECT(window), "xmltree_p", xmltree_p);
916 }
917 g_free(attribute_title);
918 } else if (!get_editable_attribute(xmltree_p, attribute)){
919 g_free(path);
920 return FALSE;
921 } else {
922 gint type = GPOINTER_TO_INT(g_hash_table_lookup(xmltree_p->attribute_hash, attribute));
923 Attribute_item_t *att_text = get_attribute(parent_tag, "text");
924 const gchar *text = get_attribute_value(att_text);
925 if (!text) text = _("Modify");
926 gchar *attribute_title = NULL;
927 GtkWidget *box = NULL;
928 if (type == XMLTREE_key_type){
929 attribute_title = g_strdup_printf("%s", _("<choose a key>"));
930 box = tag_box(text, attribute, value, 1, parent_tag);
931 } else if (type == XMLTREE_string_type){
932 attribute_title = g_strdup_printf("%s", _("<Modify value>"));
933 box = tag_box(text, attribute, value, 2, parent_tag);
934 }
935 if (box) {
936 window = new_dialog(box, attribute_title);
937 if (type == XMLTREE_key_type){
938 g_object_set_data(G_OBJECT(window), "XMLTREE_key_type", GINT_TO_POINTER(1));
939 }
940 g_object_set_data(G_OBJECT(window), "filter_model", g_object_get_data(G_OBJECT(treeview), "filter_model"));
941 g_object_set_data(G_OBJECT(window), "model", gtk_tree_view_get_model(treeview));
942 g_object_set_data(G_OBJECT(window), "xmltree_p", xmltree_p);
943 }
944 g_free(attribute_title);
945 }
946
947
948
949
950 break;
951 case TAG_DATA:
952 // click on text will fire up modification of key attribute. OK
953 fprintf(stderr,"tag data: %d!\n", tag_type);
954 gint action = xmltree_p->text_activates_top_attribute;
955 fprintf(stderr, "action=%d\n", action);
956 if (action == -1) {
957 // FIXME: here we open dialog with textview to modify text
958 // if text is modifyable... (action == -1)
959 } else if (action==1) {
960 if (gtk_tree_model_iter_has_child(model, &iter)){
961 GtkTreePath *ipath=NULL;
962 GtkTreeIter child;
963 gtk_tree_model_iter_children (model, &child, &iter);
964 do {
965 gchar * attribute;
966 gtk_tree_model_get (model, &child,
967 H_ATTRIBUTE_COLUMN, &attribute,
968 -1);
969 NOOP(stderr, "got attribute \"%s\"\n", attribute);
970 if (get_editable_attribute(xmltree_p, attribute)){
971 NOOP(stderr, "gotcha \"%s\"\n", attribute);
972 ipath = gtk_tree_model_get_path(model, &child);
973 GdkEventButton newevent;
974 newevent.x = event->x;
975 newevent.y = event->y;
976 activate_f(treeview, ipath, _("Value"), &newevent);
977 gtk_tree_path_free(ipath);
978 break;
979 }
980 } while (gtk_tree_model_iter_next(model, &child));
981
982 }
983 }
984 break;
985
986 default:
987 g_free(path);
988 return FALSE;
989 }
990 if (key) {
991 gchar *path_string = g_strdup(key);
992 g_object_set_data(G_OBJECT(window), "path_string", path_string);
993 }
994
995 g_hash_table_replace(dialog_hash, key, window);
996 TRACE( "inserting %s -- 0x%x\n", key, GPOINTER_TO_INT(window));
997 g_signal_connect(G_OBJECT(window), "delete-event",
998 G_CALLBACK (on_destroy_child), NULL);
999 g_signal_connect(G_OBJECT(window), "destroy-event",
1000 G_CALLBACK (on_destroy_child), NULL);
1001 // freed with g_hash_table_destroy ... g_free(key);
1002
1003 NOOP("size--> %d, %d\n", Xsize, Ysize);
1004 gtk_window_set_default_size (GTK_WINDOW (window), Xsize, Ysize);
1005 gtk_widget_show_all(window);
1006 }
1007 // Move window...
1008 if (event){
1009 gint root_x;
1010 gint root_y;
1011 gint x=event->x;
1012 gint y=event->y;
1013 GtkWidget *parent_window = g_object_get_data(G_OBJECT(treeview), "parent_window");
1014 gtk_window_get_position (GTK_WINDOW(parent_window), &root_x, &root_y);
1015 NOOP("moving %s to %d, %d\n", path, x, y);
1016 gtk_window_move (GTK_WINDOW(window), root_x+x, root_y+y);
1017 }
1018 // raise as well...
1019 gdk_window_raise (gtk_widget_get_window(window));
1020 }
1021 done:
1022 g_free(path);
1023 return TRUE;
1024 }
1025
1026 static gboolean
on_button_press(GtkWidget * widget,GdkEventButton * event,gpointer data)1027 on_button_press (GtkWidget * widget, GdkEventButton * event, gpointer data) {
1028 set_button_serial (GTK_TREE_VIEW(widget), event);
1029 return FALSE;
1030 }
1031
1032 static gboolean
on_button_release(GtkWidget * widget,GdkEventButton * event,gpointer data)1033 on_button_release (GtkWidget * widget, GdkEventButton * event, gpointer data)
1034 {
1035 if (!check_button_serial(GTK_TREE_VIEW(widget), event)) return FALSE;
1036 unset_button_serial (GTK_TREE_VIEW(widget), event);
1037
1038
1039 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
1040 GtkTreePath *treepath=NULL;
1041 GtkTreeViewColumn *column;
1042 gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
1043 &treepath, &column, NULL, NULL);
1044
1045 const gchar *column_title="none";
1046 if (column){
1047 column_title = gtk_tree_view_column_get_title (column);
1048 }
1049
1050 NOOP ("treepath=\"%s\" column=\"%s\"\n", path, column_title);
1051 gboolean retval = activate_f(treeview, treepath, column_title, event);
1052 if (strcmp(column_title, _("Value"))) retval = FALSE;
1053
1054 gtk_tree_path_free(treepath);
1055 return retval;
1056 }
1057
1058 // To enter edit mode via keyboard:
1059 static
treeview_key(GtkWidget * w,GdkEventKey * event,gpointer data)1060 gboolean treeview_key(GtkWidget *w, GdkEventKey *event,gpointer data){
1061 //NOOP(stderr, "0x%x\n",event->keyval);
1062 if (event->keyval != GDK_KEY_Return
1063 && event->keyval != GDK_KEY_KP_Enter
1064 && event->keyval != GDK_KEY_ISO_Enter
1065 && event->keyval != GDK_KEY_3270_Enter){
1066 return FALSE;
1067 }
1068 GtkTreeView *treeview=(GtkTreeView *)w;
1069 xmltree_t *xmltree_p = g_object_get_data(G_OBJECT(treeview), "xmltree_p");
1070 GtkTreeModel *model = gtk_tree_view_get_model(treeview);
1071 GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
1072 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
1073 GtkTreePath *ipath=NULL;
1074 GtkTreeIter iter;
1075
1076
1077 if(gtk_tree_selection_get_selected(selection, &model, &iter)){
1078 gchar *tag;
1079 gtk_tree_model_get(model, &iter, H_TAG_COLUMN, &tag, -1);
1080 if (tag && strcasecmp(tag, "keys")==0) {
1081 ipath = gtk_tree_model_get_path(model, &iter);
1082 if (gtk_tree_view_row_expanded (treeview,ipath)){
1083 gtk_tree_view_collapse_row(treeview, ipath);
1084 } else {
1085 gtk_tree_view_expand_row(treeview, ipath, FALSE);
1086 }
1087 if (ipath) gtk_tree_path_free(ipath);
1088 return FALSE;
1089 }
1090 }
1091 GtkTreeIter *att_iter;
1092 GtkTreeIter child;
1093 if (gtk_tree_model_iter_has_child(model, &iter)){
1094 gtk_tree_model_iter_children (model, &child, &iter);
1095 att_iter = &child;
1096 } else {
1097 att_iter = &iter;
1098 }
1099 gchar * attribute;
1100 gtk_tree_model_get (model, att_iter,
1101 H_ATTRIBUTE_COLUMN, &attribute,
1102 -1);
1103 if (!attribute) goto done;
1104 // FIXME: any editable attribute.
1105 if (get_editable_attribute(xmltree_p, attribute)){
1106 //if (strcasecmp(attribute, "Keybinding")==0) {
1107 ipath = gtk_tree_model_get_path(model, att_iter);
1108 GdkEventButton newevent;
1109 gint x;
1110 gint y;
1111 gint wx;
1112 gint wy;
1113 GtkWindow *window = g_object_get_data(G_OBJECT(treeview), "parent_window");
1114 gtk_window_get_position (window, &wx, &wy);
1115 #if GTK_MAJOR_VERSION==3
1116 rfm_global_t *rfm_global_p = rfm_global();
1117 gdk_device_get_position (rfm_global_p->pointer, NULL, &(x), &(y));
1118 #else
1119 gdk_display_get_pointer (gdk_display_get_default(), NULL, &(x), &(y), NULL);
1120 #endif
1121 x -= wx;
1122 y -= wy;
1123 newevent.x = x;
1124 newevent.y = y;
1125 activate_f(treeview, ipath, _("Value"), &newevent);
1126 }
1127 done:
1128 if (ipath) gtk_tree_path_free(ipath);
1129 return FALSE;
1130 }
1131
1132 static void
xml_edit_destroy(GtkButton * button,gpointer data)1133 xml_edit_destroy (GtkButton * button, gpointer data) {
1134 GtkWidget *window = data;
1135 Tag_t *Tag_p = g_object_get_data(G_OBJECT(window), "Tag_p");
1136 tag_free (Tag_p);
1137 gtk_widget_destroy(window);
1138 gtk_main_quit();
1139
1140 }
1141 static void
xml_edit_save(GtkButton * button,gpointer data)1142 xml_edit_save (GtkButton * button, gpointer data) {
1143 GtkWidget *window = data;
1144 gboolean clean = TRUE;
1145 GtkTreeModel *model = g_object_get_data(G_OBJECT(window), "model");
1146 gtk_tree_model_foreach(model, check_clean, &clean);
1147 if (!clean){
1148 return;
1149 }
1150 // save xml.
1151 Tag_t *Tag_p = g_object_get_data(G_OBJECT(window), "Tag_p");
1152 xmltree_t *xmltree_p = g_object_get_data(G_OBJECT(window), "xmltree_p");
1153 // FIXME: enter as parameter OK
1154 //gchar *keybindings_file = g_build_filename(KEYBINDINGS_FILE, NULL);
1155 gchar *file = g_build_filename(xmltree_p->xml_path, NULL);
1156 tag_write_file(Tag_p, file, FALSE);
1157 rfm_confirm(NULL, GTK_MESSAGE_INFO, file, NULL, NULL);
1158 g_free(file);
1159 gtk_widget_destroy(window);
1160
1161 }
1162
1163 /////////////////////////////////////////////////////////////////////////
1164 // TREEVIEW CREATION FUNCTIONALITY
1165 /////////////////////////////////////////////////////////////////////////
1166
1167 static void *
build_treeview(GtkTreeModel * model)1168 build_treeview(GtkTreeModel *model){
1169 GtkWidget *treeview = gtk_tree_view_new_with_model (model);
1170 GtkTreeViewColumn *column;
1171 GtkCellRenderer *cell;
1172
1173 // This is the nerdy stuff:
1174 // adding the columns with the appropriate cell renderer...
1175 //
1176 // button column
1177 column = gtk_tree_view_column_new ();
1178 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1179 gtk_tree_view_column_set_resizable (column, FALSE);
1180 gtk_tree_view_column_set_reorderable (column, FALSE);
1181 gtk_tree_view_column_set_spacing (column, 2);
1182
1183 cell = gtk_cell_renderer_pixbuf_new ();
1184 gtk_tree_view_column_pack_start (column, cell, FALSE);
1185 gtk_tree_view_column_set_attributes (column, cell,
1186 "pixbuf", H_BUTTON_COLUMN,
1187 NULL);
1188 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1189 gtk_tree_view_column_set_title (column, "*");
1190
1191 // Start with the pixbuf column...
1192 column = gtk_tree_view_column_new ();
1193 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1194 gtk_tree_view_column_set_resizable (column, FALSE);
1195 gtk_tree_view_column_set_reorderable (column, FALSE);
1196 gtk_tree_view_column_set_spacing (column, 2);
1197
1198 cell = gtk_cell_renderer_pixbuf_new ();
1199 gtk_tree_view_column_pack_start (column, cell, FALSE);
1200 gtk_tree_view_column_set_attributes (column, cell,
1201 "pixbuf", H_PIXBUF_COLUMN,
1202 "pixbuf_expander_closed", H_PIXBUF_COLUMN,
1203 "pixbuf_expander_open", H_PIXBUF_COLUMN,
1204 NULL);
1205 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1206 gtk_tree_view_set_expander_column (GTK_TREE_VIEW(treeview), column);
1207
1208
1209 // Start with the tag column...
1210 column = gtk_tree_view_column_new ();
1211 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1212 gtk_tree_view_column_set_resizable (column, FALSE);
1213 gtk_tree_view_column_set_reorderable (column, FALSE);
1214 gtk_tree_view_column_set_spacing (column, 2);
1215 cell = gtk_cell_renderer_text_new ();
1216 g_object_set (G_OBJECT (cell), "editable", FALSE, NULL);
1217 gtk_tree_view_column_set_clickable (column, TRUE);
1218
1219 gtk_tree_view_column_pack_start (column, cell, FALSE);
1220 gtk_tree_view_column_set_attributes (column, cell, "text", H_TAG_COLUMN, "foreground", H_COLOR_COLUMN,
1221 NULL);
1222 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1223 gtk_tree_view_column_set_title (column, _("XML tag"));
1224
1225 // Continue with the namespace (prefix) column...
1226 column = gtk_tree_view_column_new ();
1227 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1228 gtk_tree_view_column_set_resizable (column, FALSE);
1229 gtk_tree_view_column_set_reorderable (column, FALSE);
1230 gtk_tree_view_column_set_spacing (column, 2);
1231 cell = gtk_cell_renderer_text_new ();
1232 g_object_set (G_OBJECT (cell), "editable", FALSE, NULL);
1233 gtk_tree_view_column_set_clickable (column, TRUE);
1234
1235 gtk_tree_view_column_pack_start (column, cell, FALSE);
1236 gtk_tree_view_column_set_attributes (column, cell, "text", H_NS_COLUMN, "foreground", H_COLOR_COLUMN,
1237 NULL);
1238 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1239 gtk_tree_view_column_set_title (column, _("prefix"));
1240
1241
1242 // Next is the attributes column...
1243 column = gtk_tree_view_column_new ();
1244 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1245 gtk_tree_view_column_set_resizable (column, FALSE);
1246 gtk_tree_view_column_set_reorderable (column, FALSE);
1247 gtk_tree_view_column_set_spacing (column, 2);
1248 cell = gtk_cell_renderer_text_new ();
1249 g_object_set (G_OBJECT (cell), "editable", FALSE, NULL);
1250 gtk_tree_view_column_set_clickable (column, TRUE);
1251
1252 gtk_tree_view_column_pack_start (column, cell, FALSE);
1253 gtk_tree_view_column_set_attributes (column, cell, "text", H_ATTRIBUTE_COLUMN, "foreground", H_COLOR_COLUMN,
1254 NULL);
1255 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1256 gtk_tree_view_column_set_title (column, _("Attribute"));
1257
1258
1259 // Finally (for now) is the value (string) column...
1260 column = gtk_tree_view_column_new ();
1261 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1262 gtk_tree_view_column_set_resizable (column, FALSE);
1263 gtk_tree_view_column_set_reorderable (column, FALSE);
1264 gtk_tree_view_column_set_spacing (column, 2);
1265 cell = gtk_cell_renderer_text_new ();
1266 g_object_set (G_OBJECT (cell), "editable", FALSE, NULL);
1267 gtk_tree_view_column_set_clickable (column, TRUE);
1268
1269 gtk_tree_view_column_pack_start (column, cell, FALSE);
1270 gtk_tree_view_column_set_attributes (column, cell, "text", H_VALUE_COLUMN, "foreground", H_COLOR_COLUMN,
1271 NULL);
1272 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1273 gtk_tree_view_column_set_title (column, _("Value"));
1274 // Signal connections
1275 // "button-press" and "button-release" are combined to create a
1276 // "clicked" signal for the widget.
1277 g_signal_connect(G_OBJECT(treeview), "button-press-event",
1278 G_CALLBACK (on_button_press), NULL);
1279 g_signal_connect(G_OBJECT(treeview), "button-release-event",
1280 G_CALLBACK (on_button_release), NULL);
1281 return treeview;
1282 }
1283
1284 static void *
build_treeview_box(GtkTreeView * treeview)1285 build_treeview_box(GtkTreeView *treeview){
1286 GtkWidget *vbox = rfm_vbox_new (TRUE, 0);
1287 GtkWidget *scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
1288 gtk_container_add (GTK_CONTAINER (vbox), scrolledwindow);
1289 gtk_container_add (GTK_CONTAINER (scrolledwindow), GTK_WIDGET(treeview));
1290 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), TRUE);
1291 return vbox;
1292 }
1293
1294
1295 static void
recurse_tree(Tag_t * Tag_p,Tag_item_t * item,GtkTreeModel * tree_model,gint level,GtkTreeIter * parent_p)1296 recurse_tree(Tag_t *Tag_p, Tag_item_t *item, GtkTreeModel *tree_model, gint level, GtkTreeIter *parent_p){
1297 GtkTreeStore *model = GTK_TREE_STORE(tree_model);
1298 xmltree_t *xmltree_p = g_object_get_data(G_OBJECT(tree_model), "xmltree_p");
1299
1300 if (!GDK_IS_PIXBUF(OK) || !GDK_IS_PIXBUF(KO)){
1301 broken = rfm_get_pixbuf("xffm/emblem_broken", TINY_ICON_SIZE);
1302 OK = rfm_get_pixbuf("xffm/stock_yes", TINY_ICON_SIZE);
1303 KO = rfm_get_pixbuf("xffm/stock_no", TINY_ICON_SIZE);
1304 keyboard = rfm_get_pixbuf("xffm/emblem_keyboard", TINY_ICON_SIZE);
1305 folder_red = rfm_get_pixbuf("xffm/stock_directory/compositeC/emblem_redball", TINY_ICON_SIZE);
1306 folder_green = rfm_get_pixbuf("xffm/stock_directory/compositeC/emblem_greenball", TINY_ICON_SIZE);
1307 redball = rfm_get_pixbuf("xffm/emblem_redball", 16);
1308 greenball = rfm_get_pixbuf("xffm/emblem_greenball", 16);
1309 green = rfm_get_pixbuf("xffm/emblem_edit/compositeNE/emblem_greenball", TINY_ICON_SIZE);
1310 red = rfm_get_pixbuf("xffm/emblem_edit/compositeNE/emblem_redball", TINY_ICON_SIZE);
1311 blue = rfm_get_pixbuf("xffm/emblem_edit", TINY_ICON_SIZE);
1312 bold = rfm_get_pixbuf("xffm/stock_bold", TINY_ICON_SIZE);
1313 list_remove = rfm_get_pixbuf("xffm/stock_list-remove", 16);
1314 list_add = rfm_get_pixbuf("xffm/stock_list-add", 16);
1315 question = rfm_get_pixbuf("xffm/stock_dialog-question", 16);
1316 index_pix = rfm_get_pixbuf("xffm/stock_index", 16);
1317 index_pix2 = rfm_get_pixbuf("xffm/emblem_file", 16);
1318 strikethrough = rfm_get_pixbuf("xffm/stock_strikethrough", TINY_ICON_SIZE);
1319 include_on = rfm_get_pixbuf("xffm/stock_go-bottom", TINY_ICON_SIZE);
1320 include_off = rfm_get_pixbuf("xffm/stock_go-top", TINY_ICON_SIZE);
1321 repeat_value = rfm_get_pixbuf("xffm/stock_stop", TINY_ICON_SIZE);
1322 // references are in hash table
1323 g_object_unref(broken);
1324 g_object_unref(OK);
1325 g_object_unref(KO);
1326 g_object_unref(keyboard);
1327 g_object_unref(folder_red);
1328 g_object_unref(folder_green);
1329 g_object_unref(bold);
1330 g_object_unref(redball);
1331 g_object_unref(greenball);
1332 g_object_unref(red);
1333 g_object_unref(green);
1334 g_object_unref(blue);
1335 g_object_unref(strikethrough);
1336 g_object_unref(include_on);
1337 g_object_unref(include_off);
1338 g_object_unref(repeat_value);
1339 }
1340
1341 GSList *list;
1342 GtkTreeIter child;
1343 GtkTreeIter grandchild;
1344 NOOP("item=0x%x\n", GPOINTER_TO_INT(item));
1345
1346
1347 GSList *the_list = get_tag_item_list(Tag_p, item, NULL); // all tags
1348 for (list=the_list;list && list->data; list=list->next){
1349 Tag_item_t * item = list->data;
1350 const gchar *name = get_tag_name(item);
1351 const gchar *string = tag_item_get_string(item);
1352 if (!name)continue;
1353 if (strcasecmp(name, "schema")==0){
1354 NOOP("schema_tag\n");
1355 }
1356 // Add name to model to create a new treeiter.
1357 // strike through icon for tags with no attributes (default)
1358 gtk_tree_store_append (model, &child, parent_p);
1359 GdkPixbuf *pixbuf = strikethrough;
1360 gtk_tree_store_set (model, &child,
1361 H_PIXBUF_COLUMN, pixbuf,
1362 H_TAG_COLUMN, (string)?string:name,
1363 H_TAG_ITEM_COLUMN, item,
1364 H_ATTRIBUTE_ITEM_COLUMN, NULL, // tags are not attributes.
1365 H_VALUE_COLUMN, NULL,
1366 -1);
1367 // Does the node have properties? (or attributes)
1368 GSList *attribute_list = get_attribute_item_list(item);
1369 GSList *tmp = attribute_list;
1370 for(;tmp && tmp->data; tmp=tmp->next){
1371 if (strcasecmp(name, "schema")==0){
1372 NOOP("schema_tag attribute...\n");
1373 }
1374 Attribute_item_t *at_item = tmp->data;
1375 const gchar *value = get_attribute_value(at_item);
1376 if (value) {
1377 Attribute_item_t * at_item = tmp->data;
1378 const gchar *at_name=get_attribute_name(at_item);
1379 if (!at_name){
1380 DBG("recurse_tree(): at_name=NULL\n");
1381 continue;
1382 }
1383 const gchar *name_field = g_hash_table_lookup(xmltree_p->echo_hash, name);
1384 if (!name_field) name_field = "text";
1385 if (strcasecmp(at_name, "Keybinding")==0) pixbuf = OK;
1386 else pixbuf = NULL;
1387 // Put the text field into the parent tag's value column
1388 if (strcasecmp(at_name, name_field)==0){
1389 gtk_tree_store_set (model, &child,
1390 H_VALUE_COLUMN, get_attribute_value(at_item),
1391 -1);
1392 }
1393 //else
1394 {
1395 if (attribute_get_hidden(at_item)) gtk_tree_store_append (model, &grandchild, &child);
1396 else if (noneditable_hash && g_hash_table_lookup(noneditable_hash, at_item))
1397 gtk_tree_store_append (model, &grandchild, &child);
1398 else gtk_tree_store_prepend (model, &grandchild, &child);
1399 gtk_tree_store_set (model, &grandchild,
1400 H_NS_COLUMN, get_attribute_prefix(at_item),
1401 H_ATTRIBUTE_COLUMN, get_attribute_name(at_item),
1402 H_PIXBUF_COLUMN, pixbuf,
1403 H_VALUE_COLUMN, get_attribute_value(at_item),
1404 H_TAG_ITEM_COLUMN, item, // This will correspond to the parent tag
1405 H_ATTRIBUTE_ITEM_COLUMN, at_item,
1406 -1);
1407 }
1408
1409 } else {
1410 gtk_tree_store_set (model, &grandchild,
1411 H_ATTRIBUTE_COLUMN, get_attribute_name(at_item),
1412 H_PIXBUF_COLUMN, KO,
1413 H_TAG_ITEM_COLUMN, item, // This will correspond to the parent tag
1414 H_ATTRIBUTE_ITEM_COLUMN, at_item,
1415 -1);
1416 }
1417 }
1418 if (attribute_list) {
1419 // Change tag icon to keyboard
1420 g_slist_free(attribute_list);
1421 pixbuf = keyboard;
1422 if (keyboard) g_object_ref(keyboard);
1423 Attribute_item_t *att = get_attribute(item, "icon_id");
1424 if (att){
1425 const gchar *icon_id = get_attribute_value(att);
1426 if (icon_id){
1427 if (strlen(icon_id)){
1428 if (pixbuf) g_object_unref(pixbuf);
1429 pixbuf = rfm_get_pixbuf(icon_id, TINY_ICON_SIZE);
1430 }
1431 }
1432 }
1433 gtk_tree_store_set (model, &child,
1434 H_PIXBUF_COLUMN, pixbuf,
1435 -1);
1436 if (pixbuf) g_object_unref(pixbuf);
1437 }
1438 // recurse:
1439 // Does the node have children?
1440 if (tag_item_has_children(item)){
1441 pixbuf = keyboard;
1442 gtk_tree_store_set (model, &child,
1443 H_PIXBUF_COLUMN, pixbuf,
1444 -1);
1445 recurse_tree(Tag_p, item, tree_model, level+1, &child);
1446 }
1447 }
1448 g_slist_free(the_list);
1449 return;
1450 }
1451
1452 static GtkTreeModel *
populate_tree_model_from_tag(Tag_t * Tag_p,GtkTreeModel * model,GError ** error)1453 populate_tree_model_from_tag (Tag_t *Tag_p, GtkTreeModel *model, GError **error){
1454 if (!Tag_p){
1455 g_error("build_treemodel(): Tag_p cannot be NULL!");
1456 }
1457
1458 recurse_tree(Tag_p, NULL, model, 0, NULL);
1459
1460 return model;
1461 }
1462
1463