1 #include "core/keymapio.h"
2 #include "core/kbd-custom.h"
3 #include "core/view.h"
4 #include "ui/mousing.h"
5 
6 static gchar*
find_command_dir(gint idx,gchar * filename)7 find_command_dir(gint idx, gchar* filename)
8 {
9   command_row* row = NULL;
10   keymap_get_command_row(Denemo.map, &row, idx);
11 
12   if(!row->menupath)
13     g_debug("Command %s has no menupath", filename);
14 
15   GList* dirs = NULL;
16   dirs = g_list_append(dirs, g_build_filename (PACKAGE_SOURCE_DIR, COMMANDS_DIR, "menus", row->menupath, NULL));
17   dirs = g_list_append(dirs, g_build_filename (get_user_data_dir (TRUE), COMMANDS_DIR, "menus", row->menupath, NULL));
18   dirs = g_list_append(dirs, g_build_filename (get_user_data_dir (TRUE), "download", COMMANDS_DIR, "menus", row->menupath, NULL));
19   dirs = g_list_append(dirs, g_build_filename (get_system_data_dir (), COMMANDS_DIR, "menus", row->menupath, NULL));
20 
21   return find_dir_for_file (filename, dirs);
22 }
23 
24 static int
get_command_type(xmlChar * type)25 get_command_type(xmlChar* type)
26 {
27   return 0 == xmlStrcmp (type, COMMAND_TYPE_SCHEME) ? COMMAND_SCHEME : COMMAND_BUILTIN;
28 }
29 
30 static void
parseScripts(xmlDocPtr doc,xmlNodePtr cur,gchar * fallback)31 parseScripts (xmlDocPtr doc, xmlNodePtr cur, gchar * fallback)
32 {
33   command_row* command = NULL;
34   xmlChar *type = NULL;
35   xmlNodePtr head = cur;
36   type = xmlGetProp(cur, COMMANDXML_TAG_TYPE);
37     for (cur = cur->xmlChildrenNode; cur; cur = cur->next)
38     {
39       if (0 == xmlStrcmp (cur->name, COMMANDXML_TAG_ACTION))
40         {
41           if (cur->xmlChildrenNode == NULL)
42             {
43               g_warning ("Empty action node found in keymap file");
44             }
45           else
46             {
47               // We allow multiple locations for a given action, all are added to the gtk_ui when this command is processed after the tooltip node.
48               // This is very bad xml, as the action should have all the others as children, and not depend on the order.FIXME
49               gchar* name = (gchar*) xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
50               command = get_or_create_command(name);
51               command->fallback = fallback;
52               command->locations = NULL;
53 
54               if(type && 0 == xmlStrcmp (type, COMMAND_TYPE_SCHEME))
55                 command->script_type = get_command_type(type);
56             }
57         }
58     }
59   cur = head;
60   for (cur = cur->xmlChildrenNode; cur; cur = cur->next)
61     {
62     if (0 == xmlStrcmp (cur->name, COMMANDXML_TAG_HIDDEN))
63         {
64           command->hidden = TRUE;
65         }
66       else if (0 == xmlStrcmp (cur->name, COMMANDXML_TAG_MENUPATH))
67         {
68           command->locations = g_list_append (command->locations, xmlNodeListGetString (doc, cur->xmlChildrenNode, 1));
69         }
70       else if (0 == xmlStrcmp (cur->name, COMMANDXML_TAG_LABEL))
71         {
72           command->label = _((gchar*) xmlNodeListGetString (doc, cur->xmlChildrenNode, 1));
73         }
74       else if (0 == xmlStrcmp (cur->name, COMMANDXML_TAG_AFTER))
75         {
76           command->after = (gchar*) xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
77         }
78       else if (0 == xmlStrcmp (cur->name, COMMANDXML_TAG_TOOLTIP))
79         {
80           command->tooltip = _((gchar*) xmlNodeListGetString (doc, cur->xmlChildrenNode, 1));
81         }
82     }
83   create_command(command);
84   xmlFree(type);
85 }
86 
87 static void
parseBindings(xmlDocPtr doc,xmlNodePtr cur,keymap * the_keymap)88 parseBindings (xmlDocPtr doc, xmlNodePtr cur, keymap * the_keymap)
89 {
90 
91   xmlChar *name = NULL;                //keyval variables
92   gint command_number = -1;
93   guint keyval = 0;
94   GdkModifierType state = 0;
95   name = 0;                     //defend against corrupt files.
96   for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next)
97     {
98       if (0 == xmlStrcmp (cur->name, BINDINGXML_TAG_ACTION))
99         {
100           if (cur->xmlChildrenNode == NULL)
101             {
102               g_warning ("Empty children node found in keymap file");
103             }
104           else
105             {
106               name = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
107               show_action_of_name ((gchar*) name);
108             }
109         }
110       else if (0 == xmlStrcmp (cur->name, COMMANDXML_TAG_HIDDEN))
111         {
112           if (name)
113             hide_action_of_name ((gchar*) name);
114 
115         }
116       else if (0 == xmlStrcmp (cur->name, BINDINGXML_TAG_BIND))
117         {
118           if (name)
119             command_number = lookup_command_from_name (the_keymap, (gchar *) name);
120           //g_debug("Found bind node for action %s %d\n", name, command_number);
121           if (cur->xmlChildrenNode == NULL)
122             {
123               g_warning ("Empty <bind><\\bind> found in commandset file");
124             }
125           else
126             {
127               xmlChar *tmp = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
128               if (name && tmp)
129                 {
130                   gchar *gtk_binding = translate_binding_dnm_to_gtk ((gchar *) tmp);
131                   //g_debug("gtk_binding is %s\n", gtk_binding);
132                   if (gtk_binding)
133                     {
134                       keyval = 0;
135                       if (Denemo.prefs.strictshortcuts)
136                         dnm_accelerator_parse (gtk_binding, &keyval, &state);
137                       //g_debug ("binding %s, keyval %d, state %d, Command Number %d", gtk_binding, keyval, state, command_number);
138                       {
139                         gchar *comma;
140                         comma = strtok (gtk_binding, ",");
141                         if (comma)      //two key binding, remove any single keybinding
142                           {
143                             if (-1 != lookup_command_for_keybinding_name (the_keymap, comma))
144                               remove_keybinding_from_name (the_keymap, comma);
145                             *(comma + strlen (comma)) = ',';
146                           }
147                       }
148                       if (command_number != -1)
149                         {
150                           if (keyval)
151                             add_keybinding_to_idx (the_keymap, keyval, state, command_number, POS_LAST);
152                           else
153                             add_named_binding_to_idx (the_keymap, (gchar*) tmp, command_number, POS_LAST);
154                         }
155                       g_free (gtk_binding);
156                     }
157                   else
158                     {
159                       g_warning ("No gtk equivalent for shortcut %s", tmp);
160                     }
161                   xmlFree (tmp);
162                 }
163             }
164         }
165     }
166 }
167 
168 static void
parseCursorBinding(xmlDocPtr doc,xmlNodePtr cur)169 parseCursorBinding (xmlDocPtr doc, xmlNodePtr cur)
170 {
171   gint state, cursor_num;
172   xmlChar *tmp;
173   for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next)
174     {
175       if (0 == xmlStrcmp (cur->name, BINDINGXML_TAG_STATE))
176         {
177           tmp = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
178           if (tmp)
179             {
180               sscanf ((char*) tmp, "%x", &state);       // = atoi(tmp);
181               xmlFree (tmp);
182             }
183 
184         }
185       else if (0 == xmlStrcmp (cur->name, BINDINGXML_TAG_CURSOR))
186         {
187           tmp = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
188           if (tmp)
189             {
190               cursor_num = atoi ((char*) tmp);
191               xmlFree (tmp);
192             }
193           assign_cursor (state, cursor_num);
194           //g_debug("type is %s\n",g_type_name(G_TYPE_FROM_INSTANCE(Denemo.window->window)));
195           // set_cursor_for(state);
196         }
197     }
198 }
199 
200 static void
parseCursors(xmlDocPtr doc,xmlNodePtr cur)201 parseCursors (xmlDocPtr doc, xmlNodePtr cur)
202 {
203   for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next)
204     {
205       if (0 == xmlStrcmp (cur->name, BINDINGXML_TAG_CURSORBINDING))
206         {
207           parseCursorBinding (doc, cur);
208         }
209     }
210 }
211 
212 static void
parseCommands(xmlDocPtr doc,xmlNodePtr cur,keymap * the_keymap,gchar * menupath)213 parseCommands (xmlDocPtr doc, xmlNodePtr cur, keymap * the_keymap, gchar * menupath)
214 {
215   xmlNodePtr ncur;
216 
217   //Parse commands first
218   for (ncur = cur->xmlChildrenNode; ncur; ncur = ncur->next)
219     {
220       if ((0 == xmlStrcmp (ncur->name, COMMANDXML_TAG_ROW)))
221         {
222           parseScripts (doc, ncur, menupath);
223         }
224     }
225 
226   //Then parse bindings
227   if(!Denemo.non_interactive){
228     for (ncur = cur->xmlChildrenNode; ncur; ncur = ncur->next)
229       {
230         if ((0 == xmlStrcmp (ncur->name, COMMANDXML_TAG_ROW)))
231           {
232             parseBindings (doc, ncur, the_keymap);
233           }
234         else if (0 == xmlStrcmp (ncur->name, COMMANDXML_TAG_CURSORS))
235           {
236             parseCursors (doc, ncur);
237           }
238       }
239   }
240 }
241 
242 static void
parseKeymap(xmlDocPtr doc,xmlNodePtr cur,keymap * the_keymap,gchar * menupath)243 parseKeymap (xmlDocPtr doc, xmlNodePtr cur, keymap * the_keymap, gchar * menupath)
244 {
245   for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next)
246     {
247       if (0 == xmlStrcmp (cur->name, COMMANDXML_TAG_MAP))
248         {
249           parseCommands (doc, cur, the_keymap, menupath);
250         }
251     }
252 }
253 
254 /*
255  * load a command from filename.
256  * if not scripted and merging with other commands, tell the user where the new command is.
257  * If an action exists but has an empty script load the scheme script,
258  if action is a new action leave script as empty string for loading on demand.
259  * Create a widget for the action in a menupath found in filename or failing that deduced from
260  * the path to filename itself (starting from actions/menus).
261  * returns 0 on success
262  * negative on failure
263  */
264 gint
load_xml_keymap(gchar * filename)265 load_xml_keymap (gchar * filename)
266 {
267   gint ret = -1;
268   xmlDocPtr doc;
269   xmlNodePtr rootElem;
270   xmlKeepBlanksDefault (0);
271 
272   if (filename == NULL)
273     return ret;
274 
275   if (!g_file_test (filename, G_FILE_TEST_EXISTS))
276     return ret;
277 
278   if (g_file_test (filename, G_FILE_TEST_IS_DIR))
279     {
280       warningdialog (_("There is no support for loading whole folders of commands yet, sorry"));
281       return ret;
282     }
283   doc = xmlParseFile (filename);
284   gchar *menupath = extract_menupath (filename);
285   if (doc == NULL)
286     {
287       g_debug ("Could not read XML file %s", filename);
288       return ret;
289     }
290 
291   rootElem = xmlDocGetRootElement (doc);
292   if (rootElem == NULL)
293     {
294       g_warning ("Empty Document");
295       xmlFreeDoc (doc);
296       return ret;
297     }
298 
299   if (xmlStrcmp (rootElem->name, COMMANDXML_TAG_ROOT))
300     {
301       g_warning ("Document has wrong type");
302       xmlFreeDoc (doc);
303       return ret;
304     }
305   rootElem = rootElem->xmlChildrenNode;
306 
307 
308   while (rootElem != NULL)
309     {
310       parseKeymap (doc, rootElem, Denemo.map, menupath);
311 
312       if (Denemo.last_merged_command)
313         g_free (Denemo.last_merged_command);
314       Denemo.last_merged_command = g_strdup (filename);
315       if (menupath)
316         execute_init_scripts (menupath);
317 
318       if(!Denemo.non_interactive)
319         update_all_labels (Denemo.map);
320       ret = 0;
321 
322       rootElem = rootElem->next;
323     }
324 
325   xmlFreeDoc (doc);
326   {static gboolean init=FALSE;
327   if (!init)
328     {
329     alphabeticalize_commands (Denemo.map);
330     init = TRUE;
331     }
332   }
333   {
334     //if this is a new-style .commands file, we need to load the keybindings separately
335     gchar *name = g_strdup (filename);
336     gchar *ext = remove_extension (name);
337     if (ext && !strcmp (ext, "commands") && !Denemo.non_interactive)
338       {
339         gchar *newname = g_strdup_printf ("%s%s", name, ".shortcuts");
340         load_xml_keybindings (newname);
341         g_free (newname);
342       }
343     g_free (name);
344   }
345   return ret;
346 }
347 
348 gint
load_xml_keybindings(gchar * filename)349 load_xml_keybindings (gchar * filename)
350 {
351   gint ret = -1;
352   xmlDocPtr doc;
353   //xmlNsPtr ns;
354   xmlNodePtr rootElem;
355   if (filename == NULL)
356     return ret;
357   if (!g_file_test (filename, G_FILE_TEST_EXISTS))
358     return ret;
359   doc = xmlParseFile (filename);
360   if (doc == NULL)
361     {
362       g_debug ("Could not read XML file %s", filename);
363       return ret;
364     }
365   rootElem = xmlDocGetRootElement (doc);
366   if (rootElem == NULL)
367     {
368       g_warning ("Empty Document");
369       xmlFreeDoc (doc);
370       return ret;
371     }
372   //g_debug ("RootElem %s\n", rootElem->name);
373   if (xmlStrcmp (rootElem->name, COMMANDXML_TAG_ROOT))
374     {
375       g_warning ("Document has wrong type");
376       xmlFreeDoc (doc);
377       return ret;
378     }
379   rootElem = rootElem->xmlChildrenNode;
380 
381   while (rootElem != NULL)
382     {
383       if ((0 == xmlStrcmp (rootElem->name, COMMANDXML_TAG_MERGE)))
384         {
385           xmlNodePtr cur;
386           for (cur = rootElem->xmlChildrenNode; cur != NULL; cur = cur->next)
387             {
388               if (0 == xmlStrcmp (cur->name, COMMANDXML_TAG_MAP))
389                 {
390                   xmlNodePtr ncur;
391                   for (ncur = cur->xmlChildrenNode; ncur != NULL; ncur = ncur->next)
392                     {
393                       parseBindings (doc, ncur, Denemo.map);
394                     }
395                   ret = 0;
396                 }
397             }
398           update_all_labels (Denemo.map);
399         }
400       rootElem = rootElem->next;
401     }
402   xmlFreeDoc (doc);
403   return ret;
404 }
405 
406 static void
write_xml_keybinding_info(gchar * kb_name,xmlNodePtr node)407 write_xml_keybinding_info (gchar * kb_name, xmlNodePtr node)
408 {
409   gchar *dnm_binding = translate_binding_gtk_to_dnm (kb_name);
410   g_debug ("binding is : (dnm) %s, (gtk) %s \n", dnm_binding, kb_name);
411   if (!(Denemo.prefs.return_key_is_special && !strcmp (dnm_binding, N_("Return"))))
412     xmlNewTextChild (node, NULL, (xmlChar *) "bind", (xmlChar *) dnm_binding);
413   g_free (dnm_binding);
414 }
415 
416 static void
output_pointer_shortcut(gint * state,GdkCursor * cursor,xmlNodePtr parent)417 output_pointer_shortcut (gint * state, GdkCursor * cursor, xmlNodePtr parent)
418 {
419   gchar *statestr = g_strdup_printf ("%x", *state);
420 #if GTK_MAJOR_VERSION==3
421   gint cursor_num = gdk_cursor_get_cursor_type (cursor);
422 #else
423   gint cursor_num = cursor->type;
424 #endif
425   gchar *numstr = g_strdup_printf ("%d", cursor_num);
426   xmlNodePtr child = xmlNewTextChild (parent, NULL, (xmlChar *) "cursor-binding", NULL);
427   xmlNewChild (child, NULL, (xmlChar*) "state", (xmlChar*) statestr);
428   xmlNewChild (child, NULL, (xmlChar*) "cursor", (xmlChar*) numstr);
429   g_free (statestr);
430   g_free (numstr);
431 }
432 
433 gint
save_xml_keymap(gchar * filename)434 save_xml_keymap (gchar * filename)      //_!!! create a DEV version here, saving C-code to create the actions at runtime with translatable tooltips.
435 {
436   keymap *the_keymap = Denemo.map;
437   gint i, ret = -1;
438   xmlDocPtr doc;
439   xmlNodePtr parent, child;
440   gchar* cfilename = NULL;
441   const gchar *basename = NULL;
442   gchar* dir = NULL;
443   doc = xmlNewDoc ((xmlChar *) "1.0");
444   command_row* row;
445   doc->xmlRootNode = parent = xmlNewDocNode (doc, NULL, COMMANDXML_TAG_ROOT, NULL);
446 
447   child = xmlNewChild (parent, NULL, COMMANDXML_TAG_MERGE, NULL);
448 
449   xmlNewTextChild (child, NULL, COMMANDXML_TAG_TITLE, (xmlChar *) "A Denemo Command Set");
450   xmlNewTextChild (child, NULL, COMMANDXML_TAG_AUTHOR, (xmlChar *) "AT, JRR, RTS");
451 
452   parent = xmlNewChild (child, NULL, COMMANDXML_TAG_MAP, NULL);
453 
454   child = xmlNewChild (parent, NULL, COMMANDXML_TAG_CURSORS, NULL);
455 
456   g_hash_table_foreach (Denemo.map->cursors, (GHFunc) output_pointer_shortcut, child);
457 
458 
459   for (i = 0; i < keymap_size (the_keymap); i++)
460     {
461       keymap_get_command_row (the_keymap, &row, i);
462 
463       gpointer action = (gpointer) lookup_action_from_idx (the_keymap, i);
464       gchar *name = (gchar *) lookup_name_from_idx (the_keymap, i);
465 
466       basename = gtk_action_get_name (action);
467 
468       if(!is_action_name_builtin(name))
469       {
470         // Check if the command metada file exists
471         cfilename = g_strconcat (basename, XML_EXT, NULL);
472         dir = find_command_dir(i, cfilename);
473         g_free(cfilename);
474         if(!dir)
475         {
476           g_warning("Unable to find metadata file for script %s", name);
477           continue;
478         }
479 
480         // Check if the command data file exists
481         cfilename = g_strconcat (basename, SCM_EXT, NULL);
482         dir = find_command_dir(i, cfilename);
483         g_free(cfilename);
484         if(!dir)
485         {
486           g_warning("Unable to find data file for script %s", name);
487           continue;
488         }
489       }
490 
491       child = xmlNewChild (parent, NULL, COMMANDXML_TAG_ROW, NULL);
492 
493       xmlNewTextChild (child, NULL, COMMANDXML_TAG_ACTION, (xmlChar *) name);
494 
495       if(!is_action_name_builtin(name))
496           xmlNewProp(child, COMMANDXML_TAG_TYPE, COMMAND_TYPE_SCHEME);
497       else
498           xmlNewProp(child, COMMANDXML_TAG_TYPE, COMMAND_TYPE_BUILTIN);
499 
500       if (row->after)
501         xmlNewTextChild (child, NULL, COMMANDXML_TAG_AFTER, (xmlChar *) row->after);
502       if (row->deleted)              //store as hidden in commands file
503         xmlNewTextChild (child, NULL, COMMANDXML_TAG_HIDDEN, (xmlChar *) "true");
504 
505       if (row->menupath)
506         xmlNewTextChild (child, NULL, COMMANDXML_TAG_MENUPATH, (xmlChar *) row->menupath);
507 
508       gchar *label = (gchar *) lookup_label_from_idx (the_keymap, i);
509       if (label)
510         xmlNewTextChild (child, NULL, COMMANDXML_TAG_LABEL, (xmlChar *) label);
511 
512 
513       gchar *tooltip = (gchar *) lookup_tooltip_from_idx (the_keymap, i);
514       if (tooltip)
515         xmlNewTextChild (child, NULL, COMMANDXML_TAG_TOOLTIP, (xmlChar *) tooltip);
516     }
517 
518   xmlSaveFormatFileEnc (filename, doc, XML_ENCODING, 1);
519 
520   xmlFreeDoc (doc);
521   return ret;
522 }
523 
524 gint
save_xml_keybindings(gchar * filename)525 save_xml_keybindings (gchar * filename)
526 {
527   keymap *the_keymap = Denemo.map;
528   gint i, ret = -1;
529   xmlDocPtr doc;
530   //xmlNsPtr ns;
531   xmlNodePtr parent, child;
532   command_row *row;
533 
534   doc = xmlNewDoc ((xmlChar *) "1.0");
535   doc->xmlRootNode = parent = xmlNewDocNode (doc, NULL, COMMANDXML_TAG_ROOT, NULL);
536   child = xmlNewChild (parent, NULL, COMMANDXML_TAG_MERGE, NULL);
537 
538   xmlNewTextChild (child, NULL, COMMANDXML_TAG_TITLE, (xmlChar *) "A Denemo Command Set");
539   xmlNewTextChild (child, NULL, COMMANDXML_TAG_AUTHOR, (xmlChar *) "AT, JRR, RTS");
540 
541   parent = xmlNewChild (child, NULL, COMMANDXML_TAG_MAP, NULL);
542 
543   child = xmlNewChild (parent, NULL, COMMANDXML_TAG_CURSORS, NULL);
544 
545   g_hash_table_foreach (Denemo.map->cursors, (GHFunc) output_pointer_shortcut, child);
546 
547 
548   for (i = 0; i < keymap_size (the_keymap); i++)
549     {
550       keymap_get_command_row (the_keymap, &row, i);
551 
552       gpointer action = (gpointer) lookup_action_from_idx (the_keymap, i);
553       if (row->deleted && !is_action_id_builtin(i))
554         continue;
555       if (row->hidden || command_has_binding (i))
556         {
557           child = xmlNewChild (parent, NULL, COMMANDXML_TAG_ROW, NULL);
558 
559           gchar *name = (gchar *) lookup_name_from_idx (the_keymap, i);
560           //g_debug ("%s %s binding(s) \n", name, command_has_binding (i) ? "has" : "does not have");
561           xmlNewTextChild (child, NULL, COMMANDXML_TAG_ACTION, (xmlChar *) name);
562           if (row->hidden)
563             xmlNewTextChild (child, NULL, COMMANDXML_TAG_HIDDEN, (xmlChar *) "true");
564 
565           g_list_foreach(row->bindings, (GFunc) write_xml_keybinding_info, child);
566         }
567     }
568 
569   xmlSaveFormatFileEnc (filename, doc, XML_ENCODING, 1);
570 
571   xmlFreeDoc (doc);
572   return ret;
573 }
574 
575 /*
576 static void
577 show_type (GtkWidget * widget, gchar * message)
578 {
579   g_message ("%s%s", message, widget ? g_type_name (G_TYPE_FROM_INSTANCE (widget)) : "NULL widget");
580 }
581 */
582 /* not used */
583 /*
584 static gint
585 create_dir_for_menu (gchar * str)
586 {
587   gchar *thismenu = g_build_filename (get_user_data_dir (TRUE), COMMANDS_DIR, "menus", str, NULL);
588   if (!g_file_test (thismenu, G_FILE_TEST_IS_DIR))
589     {
590       return g_mkdir_with_parents (thismenu, 0770);
591     }
592   return 0;
593 }
594 */
595 
596 /* parse an entry in denemoui.xml recursively
597    set menupath as attribute of widgets
598  */
599 static gint
parseMenu(xmlNodePtr rootElem,gchar * path,DenemoProject * gui)600 parseMenu (xmlNodePtr rootElem, gchar * path, DenemoProject * gui)
601 {
602   for (rootElem = rootElem->xmlChildrenNode; rootElem; rootElem = rootElem->next)
603     {
604       if (0 == xmlStrcmp (rootElem->name, MENUXML_TAG_MENUBAR) ||
605           0 == xmlStrcmp (rootElem->name, MENUXML_TAG_MENU) ||
606           0 == xmlStrcmp (rootElem->name, MENUXML_TAG_TOOLBAR))
607         /* ignoring popup menus */
608         {
609           gchar *name = (gchar *) xmlGetProp (rootElem, MENUXML_PROP_NAME);
610           if (name == NULL)
611             name = (gchar *) xmlGetProp (rootElem, MENUXML_PROP_ACTION);
612 
613           if (name)
614             {
615               gchar *str = g_strdup_printf ("%s%s%s", path, "/", name);
616               GtkWidget *widget = gtk_ui_manager_get_widget (Denemo.ui_manager, str);
617               if (widget)
618                 {
619                   g_object_set_data (G_OBJECT (widget), "menupath", str);
620                   // we do this in menu_click when needed create_dir_for_menu(str);//FIXME we only need do this once for a given denemoui.xml
621                   //show_type(widget, "The type is ");
622                   //g_debug("set %p %s\n",widget, str);
623                   parseMenu (rootElem, str, gui);
624                 }
625               else
626                 g_warning ("no object for %s", str);
627             }
628 
629         }
630       if (0 == xmlStrcmp (rootElem->name, MENUXML_TAG_MENUITEM))
631         {
632           gchar *name = (gchar *) xmlGetProp (rootElem, MENUXML_PROP_ACTION);
633           if (name)
634             {
635               gchar *str = g_strdup_printf ("%s%s%s", path, "/", name);
636               GtkWidget *widget = gtk_ui_manager_get_widget (Denemo.ui_manager, str);
637               g_free (str);
638               //show_type(widget, "The type is ");
639               //g_debug("set %p %s\n",widget, path);
640               if (widget)
641                 {
642                   g_object_set_data (G_OBJECT (widget), "menupath", g_strdup (path));
643                 }
644             }
645           g_free (name);
646         }
647     }
648   return 0;
649 }
650 
651 /*
652  * attaches the menu hierarchy path to each menuitem widget in the passed file (denemoui.xml)
653  * returns 0 on success
654  * negative on failure
655  */
656 gint
parse_paths(gchar * filename,DenemoProject * gui)657 parse_paths (gchar * filename, DenemoProject * gui)
658 {
659   gint ret = -1;
660   xmlDocPtr doc;
661   xmlNodePtr rootElem;
662   if (filename == NULL)
663     return ret;
664   doc = xmlParseFile (filename);
665 
666   if (doc == NULL)
667     {
668       g_warning ("Could not read XML file %s", filename);
669       return ret;
670     }
671 
672   rootElem = xmlDocGetRootElement (doc);
673   if (rootElem == NULL)
674     {
675       g_warning ("Empty Document");
676       xmlFreeDoc (doc);
677       return ret;
678     }
679 
680   if (xmlStrcmp (rootElem->name, (const xmlChar *) "ui"))
681     {
682       g_warning ("Document has wrong type");
683       xmlFreeDoc (doc);
684       return ret;
685     }
686 
687   parseMenu (rootElem, "", gui);
688   ret = 0;
689   xmlFreeDoc (doc);
690   return ret;
691 }
692 
693 gint
save_command_metadata(gchar * filename,gchar * myname,gchar * mylabel,gchar * mytooltip,gchar * after)694 save_command_metadata (gchar * filename, gchar * myname, gchar * mylabel, gchar * mytooltip, gchar * after)
695 {
696   xmlDocPtr doc;
697   xmlNodePtr parent, child;
698 
699   doc = xmlNewDoc ((xmlChar *) "1.0");
700   doc->xmlRootNode = parent = xmlNewDocNode (doc, NULL, COMMANDXML_TAG_ROOT, NULL);
701   child = xmlNewChild (parent, NULL, COMMANDXML_TAG_MERGE, NULL);
702 
703   xmlNewTextChild (child, NULL, COMMANDXML_TAG_TITLE, (xmlChar *) "A Denemo Keymap");
704   xmlNewTextChild (child, NULL, COMMANDXML_TAG_AUTHOR, (xmlChar *) "AT, JRR, RTS");
705 
706   parent = xmlNewChild (child, NULL, COMMANDXML_TAG_MAP, NULL);
707 
708   child = xmlNewChild (parent, NULL, COMMANDXML_TAG_ROW, NULL);
709   xmlNewProp(child, COMMANDXML_TAG_TYPE, COMMAND_TYPE_SCHEME);
710 
711   xmlNewTextChild (child, NULL, COMMANDXML_TAG_ACTION, (xmlChar *) myname);
712 
713   if (after)
714     xmlNewTextChild (child, NULL, COMMANDXML_TAG_AFTER, (xmlChar *) after);
715 
716 
717   xmlNewTextChild (child, NULL, COMMANDXML_TAG_LABEL, (xmlChar *) mylabel);
718 
719   xmlNewTextChild (child, NULL, COMMANDXML_TAG_TOOLTIP, (xmlChar *) mytooltip);
720 
721   xmlSaveFormatFileEnc (filename, doc, XML_ENCODING, 1);
722   xmlFreeDoc (doc);
723   return 0;
724 }
725 
726 gint
save_command_data(gchar * filename,gchar * myscheme)727 save_command_data (gchar * filename, gchar * myscheme)
728 {
729   g_file_set_contents (filename, myscheme, -1, NULL);
730   return 0;
731 }
732 
733 gchar *
load_command_data(gint idx)734 load_command_data (gint idx)
735 {
736   gchar *basename = (gchar*) lookup_name_from_idx (Denemo.map, idx);
737   gchar *filename = g_strconcat (basename, SCM_EXT, NULL);
738   gchar* path = NULL;
739   gchar* scheme = NULL;
740   GError* error = NULL;
741 
742   // Locate the script
743   gchar* dir = find_command_dir(idx, filename);
744   if(!dir)
745   {
746     gchar* msg = g_strdup_printf(_("Unable to locate the script %s"), filename);
747     warningdialog (msg);
748     g_free(msg);
749     g_free(filename);
750     return NULL;
751   }
752 
753   // Load the script
754   path = g_build_filename(dir, filename, NULL);
755   g_free(filename);
756   if(!g_file_get_contents (path, &scheme, NULL, &error))
757   {
758     gchar* msg = g_strdup_printf(_("Unable to load the script %s"), path);
759     warningdialog (msg);
760     g_free(msg);
761     g_free(path);
762     return NULL;
763   }
764   g_free(path);
765 
766   // Load the init script if there is one
767   path = g_build_filename (dir, INIT_SCM, NULL);
768   if (g_file_test (path, G_FILE_TEST_EXISTS))
769     //scm_c_primitive_load(path);Use scm_c_primitive_load together with scm_internal_catch and scm_handle_by_message_no_exit instead.
770     eval_file_with_catch (path);
771   g_free (path);
772 
773   g_free (dir);
774 
775   return scheme;
776 }
777 
778 #ifdef DEVELOPER
779 //code to take denemoui.xml and Default.commands from the cwd and output a new version of Default.commands with builtin commands' menupaths inserted
780 GString *contents = NULL;
781 
782 
insert_path(gchar * name,gchar * path)783 static void insert_path (gchar *name, gchar *path)
784 {
785  if(!contents)
786     {
787      GError* error = NULL;
788      gchar *temp;
789      g_file_get_contents ("Default.commands", &temp, NULL, &error);
790      if(error) exit (-1);
791      contents = g_string_new (temp);
792      //g_print ("contents %s\n", contents->str);
793     }
794  name = g_strconcat ("<action>", name, "</action>", NULL);
795  gchar *found = g_strrstr (contents->str, name);
796  if(found)
797     {
798      path = g_strconcat ("<menupath>", path, "</menupath>\n", NULL);
799      contents = g_string_insert (contents, found - contents->str, path);
800     }
801 }
802 
803 static void
parseMenuItems(xmlDocPtr doc,xmlNodePtr cur,gchar * folder)804 parseMenuItems (xmlDocPtr doc, xmlNodePtr cur, gchar *folder)
805 {
806   for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next)
807     {
808       if (0 == xmlStrcmp (cur->name, "menuitem"))
809         {
810           gchar *name = xmlGetProp (cur, "action");
811           insert_path (name, folder);
812         }
813      else if (0 == xmlStrcmp (cur->name, "menu"))
814         {
815          gchar *menufolder = g_strconcat (folder, "/", xmlGetProp (cur, "action"), NULL);
816          parseMenuItems (doc, cur, menufolder);
817         }
818     }
819 }
820 
821 gint
attach_menupaths(void)822 attach_menupaths (void)
823 {
824     gchar * filename = "denemoui.xml";
825     gchar * commands = "Default.commands";
826   gint ret = -1;
827   xmlDocPtr doc;
828   //xmlNsPtr ns;
829   xmlNodePtr rootElem;
830   if (filename == NULL)
831     return ret;
832   if (!g_file_test (filename, G_FILE_TEST_EXISTS))
833     return ret;
834   doc = xmlParseFile (filename);
835   if (doc == NULL)
836     {
837       g_debug ("Could not read XML file %s", filename);
838       return ret;
839     }
840   rootElem = xmlDocGetRootElement (doc);
841   if (rootElem == NULL)
842     {
843       g_warning ("Empty Document");
844       xmlFreeDoc (doc);
845       return ret;
846     }
847   //g_debug ("RootElem %s\n", rootElem->name);
848   if (xmlStrcmp (rootElem->name, "ui"))
849     {
850       g_warning ("Document has wrong type");
851       xmlFreeDoc (doc);
852       return ret;
853     }
854 
855   xmlNodePtr cur;
856  for (cur = rootElem->xmlChildrenNode; cur != NULL; cur = cur->next)
857     {
858       if ((0 == xmlStrcmp (cur->name, "menubar")))
859         {
860           gchar *folder = xmlGetProp (cur, "name");
861           parseMenuItems (doc, cur, folder);
862         }
863     }
864     g_print ("\n%s", contents->str);
865   xmlFreeDoc (doc);
866   return ret;
867 }
868 #endif
869