1 /*
2  * palettestorage.c
3  *
4  * Copyright 2013 Richard Shann <rshann@virgin.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  */
21 #include "ui/palettes.h"
22 #include "core/view.h"
23 #include "core/utils.h"
24 #include <libxml/parser.h>
25 #include <libxml/tree.h>
26 #include <libxml/xmlmemory.h>
27 
save_button(xmlNodePtr button,GtkWidget * widget)28 static void save_button (xmlNodePtr button, GtkWidget *widget)
29 {
30     //newXMLIntProp (xmlNodePtr parent, const xmlChar * name, gint content)
31     const gchar *label = g_object_get_data (G_OBJECT(widget), "icon");
32     if(label == NULL)
33         label = gtk_button_get_label(GTK_BUTTON(widget));
34     xmlSetProp (button, (xmlChar *) "label", (xmlChar *) label );
35     xmlSetProp (button, (xmlChar *) "_tooltip", (xmlChar *) gtk_widget_get_tooltip_text(widget));
36     xmlSetProp (button, (xmlChar *) "script", (xmlChar *) g_object_get_data (G_OBJECT(widget), "script"));
37 }
38 /**
39  *
40 Set a prop of the parent, holding the passed name and integer.
41  */
42 static void
newXMLIntProp(xmlNodePtr parent,const xmlChar * name,gint content)43 newXMLIntProp (xmlNodePtr parent, const xmlChar * name, gint content)
44 {
45   gchar *integer = g_strdup_printf ("%d", content);
46   xmlSetProp (parent, name, (xmlChar *) integer);
47   g_free (integer);
48 }
49 
50 
51 static void
save_palette(xmlNodePtr parent,DenemoPalette * pal)52 save_palette (xmlNodePtr parent, DenemoPalette *pal)
53 {
54     xmlSetProp (parent, (xmlChar *) "_name", (xmlChar *) pal->name);
55 
56     newXMLIntProp (parent, "row-wise", pal->rows);
57     newXMLIntProp (parent, "limit", pal->limit);
58     newXMLIntProp (parent, "dock", pal->docked);
59 
60     newXMLIntProp (parent, "hidden", pal->docked?!gtk_widget_get_visible(pal->box): !gtk_widget_get_visible(pal->window));
61     GList *g;
62     for(g=pal->buttons;g;g=g->next)
63     {
64         xmlNodePtr child = xmlNewChild (parent, NULL, (xmlChar *) "button", NULL);
65         save_button (child, g->data);
66     }
67 
68 }
69 
70 
71 
72 gint
writePalettes(void)73 writePalettes (void)
74 {
75   gint ret = -1;
76   xmlDocPtr doc;
77   xmlNodePtr parent, child;
78   gchar *localpal = NULL;
79 
80   localpal = g_build_filename (get_user_data_dir (TRUE), "actions", "palettes.xml", NULL);
81 
82   doc = xmlNewDoc ((xmlChar *) "1.0");
83   doc->xmlRootNode = parent = xmlNewDocNode (doc, NULL, (xmlChar *) "Denemo", NULL);
84     GList *g;
85     for( g = Denemo.palettes; g; g = g->next)
86         {
87         child = xmlNewChild (parent, NULL, (xmlChar *) "palette", NULL);
88         save_palette (child, g->data);
89         }
90     if (xmlSaveFormatFile (localpal, doc, 1) < 0)
91     {
92       g_warning ("Could not save file %s", localpal);
93       ret = -1;
94     } else
95     ret = 0;
96     xmlFreeDoc (doc);
97     return ret;
98 }
99 
100 
101 
102 /**
103  * install palettes from file
104 
105  */
106 
getXMLIntProp(xmlNodePtr child,gchar * name)107 static gint getXMLIntProp (xmlNodePtr child, gchar *name)
108  {
109   gint val = -1;
110   gchar *thename = (gchar *) xmlGetProp (child, (xmlChar *) name);
111   if (thename)
112     val = atoi (thename);
113     xmlFree (thename);
114     return val;
115 }
116 
117 
118 #define FOREACH_CHILD_ELEM(childElem, parentElem) \
119 for ((childElem) = (parentElem)->xmlChildrenNode; \
120      (childElem) != NULL; \
121      (childElem) = (childElem)->next)
122 
123 #define ELEM_NAME_EQ(childElem, childElemName) \
124 (strcmp ((gchar *)(childElem)->name, (childElemName)) == 0)
125 
installButtons(xmlNodePtr palette,DenemoPalette * pal)126  static void installButtons (xmlNodePtr palette, DenemoPalette *pal)
127  {
128     xmlNodePtr childElem;
129 
130   FOREACH_CHILD_ELEM (childElem, palette)
131   if (ELEM_NAME_EQ (childElem, "button"))
132   {
133     gchar *label = (gchar *) xmlGetProp (childElem, (xmlChar *) "label");
134     gchar *tooltip = (gchar *) xmlGetProp (childElem, (xmlChar *) "_tooltip");
135     gchar *script = (gchar *) xmlGetProp (childElem, (xmlChar *) "script");
136     if(label && tooltip && script)
137         palette_add_button (pal, label, tooltip, script);
138     else
139         g_warning ("Bad value for button in palettes.xml %s %s %s", label, tooltip, script);
140   }
141 
142 
143  }
144 
install_palette(xmlNodePtr palette,gboolean hide)145 static void install_palette (xmlNodePtr palette, gboolean hide)
146 {
147     gchar *name = (gchar *) xmlGetProp (palette, (xmlChar *) "_name");
148     gboolean hidden =  getXMLIntProp (palette, (xmlChar *) "hidden");
149     gboolean row_wise =  getXMLIntProp (palette, (xmlChar *) "row-wise");
150     gboolean dock =  getXMLIntProp (palette, (xmlChar *) "dock");
151     gint limit =  getXMLIntProp (palette, (xmlChar *) "limit");
152     DenemoPalette *pal = create_palette (name, dock, row_wise);
153     set_palate_shape (name, row_wise, limit);//does gtk_widget_show in repack
154     installButtons (palette, pal);
155     if (hide) hidden = TRUE;
156     if(hidden)
157         gtk_widget_hide(pal->docked?pal->box:pal->window);
158     else
159         gtk_widget_show(pal->docked?pal->box:pal->window);
160 
161     if (pal->buttons==NULL)
162             {
163                 delete_palette (pal);
164             }
165 }
merge_palette(xmlNodePtr palette,const gchar * sought)166 static gint merge_palette (xmlNodePtr palette, const gchar *sought)
167 {
168     gchar *name = (gchar *) xmlGetProp (palette, (xmlChar *) "_name");
169     gboolean hidden =  getXMLIntProp (palette, (xmlChar *) "hidden");
170     gboolean row_wise =  getXMLIntProp (palette, (xmlChar *) "row-wise");
171     gboolean dock =  getXMLIntProp (palette, (xmlChar *) "dock");
172     gint limit =  getXMLIntProp (palette, (xmlChar *) "limit");
173     if(!strcmp(name, sought))
174     {
175         DenemoPalette *pal = create_palette (name, dock, row_wise);
176         set_palate_shape (name, row_wise, limit);//does gtk_widget_show in repack
177         installButtons (palette, pal);
178         gtk_widget_show(pal->docked?pal->box:pal->window);
179         if (pal->buttons==NULL)
180             {
181                 delete_palette (pal);
182                 return -1;
183             }
184         return 0;
185     }
186     return -1;
187 }
188 
189 
installPalettesFile(gchar * filename,gboolean hide)190 gint installPalettesFile (gchar *filename, gboolean hide)
191 {
192    xmlDocPtr doc = NULL;
193   xmlNodePtr rootElem;
194      doc = xmlParseFile (filename);
195   if (doc == NULL)
196     {
197       g_warning ("Could not read XML file %s", filename);
198       return -1;
199     }
200 
201   rootElem = xmlDocGetRootElement (doc);
202   if (rootElem == NULL)
203     {
204       g_warning ("Empty Document");
205       xmlFreeDoc (doc);
206       return -1;
207     }
208 
209  //g_debug ("RootElem: %s\n", rootElem->name);
210   if (0 != xmlStrcmp (rootElem->name, (xmlChar*) "Denemo"))
211     {
212       g_warning ("Document has wrong type");
213       xmlFreeDoc (doc);
214       return -1;
215     }
216 
217   rootElem = rootElem->xmlChildrenNode;
218   while (rootElem != NULL)
219     {
220      //g_debug ("RootElem %s\n", rootElem->name);
221       if (0 == xmlStrcmp (rootElem->name, (const xmlChar *) "palette"))
222         {
223           install_palette (rootElem, hide);
224         }
225       rootElem = rootElem->next;
226     }
227 
228   xmlFreeDoc (doc);
229   return 0;
230 
231 }
232 
233 gint
installPalettes(void)234 installPalettes (void)
235 {
236 gint ret;
237   gchar *filename = NULL;
238 
239   GList* dirs = NULL;
240  // if(Denemo.old_user_data_dir)
241  //   dirs = g_list_append(dirs, g_build_filename (Denemo.old_user_data_dir, COMMANDS_DIR, NULL));
242 //  else
243     dirs = g_list_append(dirs, g_build_filename (get_user_data_dir (TRUE), COMMANDS_DIR, NULL));
244   dirs = g_list_append(dirs, g_build_filename (PACKAGE_SOURCE_DIR, COMMANDS_DIR, NULL));
245   dirs = g_list_append(dirs, g_build_filename (get_system_data_dir (), COMMANDS_DIR, NULL));
246 
247   filename = find_path_for_file("palettes.xml", dirs);
248   if (filename == NULL)
249     {
250       g_warning ("Could not find palette file.");
251       return -1;
252     }
253 
254 
255   if(Denemo.old_user_data_dir)
256   {
257     ret = installPalettesFile (filename, TRUE);//install but hide the new standard palettes
258     installPalettesFile (g_build_filename (Denemo.old_user_data_dir, COMMANDS_DIR, "palettes.xml", NULL) , FALSE);//merge users previous custom palettes, showing them
259    } else
260    {
261      ret = installPalettesFile (filename, FALSE);//install and show palettes
262     }
263   return ret;
264 }
265 
266 
267 gint
mergePalette(const gchar * name)268 mergePalette (const gchar *name)
269 {
270     gint ret = -1;
271      xmlDocPtr doc = NULL;
272   xmlNodePtr rootElem;
273 
274   gchar *filename = NULL;
275 
276   if (filename == NULL)
277     filename = g_build_filename (get_system_data_dir (), "actions", "palettes.xml", NULL);
278 
279   doc = xmlParseFile (filename);
280   if (doc == NULL)
281     {
282       g_warning ("Could not read XML file %s", filename);
283       return -1;
284     }
285 
286   rootElem = xmlDocGetRootElement (doc);
287   if (rootElem == NULL)
288     {
289       g_warning ("Empty Document");
290       xmlFreeDoc (doc);
291       return -1;
292     }
293 
294  //g_debug ("RootElem: %s\n", rootElem->name);
295   if (0 != xmlStrcmp (rootElem->name, (xmlChar*) "Denemo"))
296     {
297       g_warning ("Document has wrong type");
298       xmlFreeDoc (doc);
299       return -1;
300     }
301 
302   rootElem = rootElem->xmlChildrenNode;
303   while (rootElem != NULL)
304         {
305       if (0 == xmlStrcmp (rootElem->name, (const xmlChar *) "palette"))
306         {
307           if( 0 == merge_palette (rootElem, name))
308             {
309                 ret = 0;
310                 break;
311 
312             }
313         }
314       rootElem = rootElem->next;
315     }
316 
317   xmlFreeDoc (doc);
318 
319 
320     return ret;
321 }
322 
323