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