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