1 /* Bluefish HTML Editor
2  * snippets_wizard.c - plugin for snippets sidebar
3  *
4  * Copyright (C) 2006,2009-2011 Olivier Sessink
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, see <http://www.gnu.org/licenses/>.
18  */
19 /*#define DEBUG*/
20 
21 #include <string.h>
22 
23 #include "snippets.h"
24 #include "snippets_load.h"
25 #include "snippets_leaf_insert.h"
26 #include "snippets_leaf_snr.h"
27 #include "../gtk_easy.h"
28 #include "../dialog_utils.h"
29 
30 typedef enum {
31 	page_type, /* 0 */
32 	page_name,
33 	page_branch,
34 	page_insert,
35 	page_snr,
36 	page_finished
37 } Tpagenum;
38 
39 typedef struct {
40 	Tsnippetswin *snw;
41 	GtkWidget *dialog;
42 	gint choice;
43 	gchar *name;
44 	gchar *description;
45 	gpointer pagestruct;
46 	Tpagenum pagenum;
47 	xmlNodePtr node;
48 } Tsnipwiz;
49 
get_parentbranch(Tsnippetswin * snw,GtkTreePath ** parentp,xmlNodePtr * parentn)50 static void get_parentbranch(Tsnippetswin *snw, GtkTreePath **parentp, xmlNodePtr *parentn) {
51 	if (snw->lastclickedpath) {
52 		*parentp = gtk_tree_path_copy(snw->lastclickedpath);
53 	} else {
54 		*parentp = NULL;
55 	}
56 	if (snw->lastclickednode) {
57 		if (xmlStrEqual(snw->lastclickednode->name, (const xmlChar *)"leaf")) {
58 			*parentn = snw->lastclickednode->parent;
59 			if (*parentp) {
60 				if (!gtk_tree_path_up(*parentp)) {
61 					gtk_tree_path_free(*parentp);
62 					*parentp = NULL;
63 				}
64 			}
65 		} else {
66 			*parentn = snw->lastclickednode;
67 		}
68 	} else { /* parent must be the root element <snippets> */
69 		*parentn = xmlDocGetRootElement(snippets_v.doc);
70 	}
71 }
72 
add_item_to_tree(GtkTreePath * parentp,gint pixmaptype,const gchar * name,gpointer ptr)73 static void add_item_to_tree(GtkTreePath *parentp, gint pixmaptype, const gchar *name, gpointer ptr) {
74 	GtkTreeIter citer;
75 	if (parentp) {
76 		GtkTreeIter piter;
77 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(snippets_v.store),&piter,parentp)) {
78 			gtk_tree_store_append(GTK_TREE_STORE(snippets_v.store), &citer, &piter);
79 			snippets_fill_tree_item_from_node(&citer, ptr);
80 		} else {
81 			g_print("hmm weird error!?!\n");
82 		}
83 	} else {
84 		gtk_tree_store_append(GTK_TREE_STORE(snippets_v.store), &citer, NULL);
85 		snippets_fill_tree_item_from_node(&citer, ptr);
86 	}
87 }
88 
update_name_in_tree(Tsnippetswin * snw,const gchar * name)89 static void update_name_in_tree(Tsnippetswin *snw, const gchar *name) {
90 	if (snw->lastclickedpath) {
91 		GtkTreeIter citer;
92 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(snippets_v.store),&citer,snw->lastclickedpath)) {
93 			gtk_tree_store_set(snippets_v.store, &citer, TITLE_COLUMN, name,-1);
94 		}
95 	}
96 }
97 
98 typedef struct {
99 	GtkWidget *table;
100 	GtkWidget *entries[6];
101 	GtkWidget *matchtype;
102 	GtkWidget *scope;
103 	GtkWidget *casesens;
104 	GtkWidget *escapechars;
105 	GtkWidget *searchpat;
106 	GtkWidget *replace;
107 } TpageSnr;
108 
snippets_build_pageSnr(Tsnipwiz * snwiz,GtkWidget * dialog_action)109 static gpointer snippets_build_pageSnr(Tsnipwiz *snwiz, GtkWidget *dialog_action) {
110 	const gchar *scope[] = {
111 		N_("Entire document"),
112 		N_("Forward from cursor position"),
113 		N_("Selection"),
114 		N_("All open files"),
115 	};
116 
117 	const gchar *matchPattern[] = {
118 		N_("Normal"),
119 		N_("PERL")
120 	};
121 	GtkWidget *label;
122 	gint i;
123 	TpageSnr *p = g_new(TpageSnr,1);
124 
125 	p->table = gtk_table_new(8, 4, FALSE);
126 	gtk_table_set_row_spacings(GTK_TABLE (p->table), 6);
127 	gtk_table_set_col_spacings(GTK_TABLE (p->table), 12);
128 	gtk_box_pack_start(GTK_BOX(dialog_action), p->table, TRUE, TRUE, 0);
129 
130 	label = gtk_label_new(_("Specify a search and a replace pattern. You may use %0, %1, ...%5 placeholders to ask for values when you activate this item. Give these placeholders an appropriate name on the right. (Please use %% if you need literal % in your string!)"));
131 	/*gtk_label_set_use_markup(GTK_LABEL(label),TRUE);*/
132 #if GTK_CHECK_VERSION(3,2,0)
133 	gtk_label_set_width_chars(GTK_LABEL(label),50);
134 #endif
135 	gtk_label_set_line_wrap(GTK_LABEL(label),TRUE);
136 	gtk_table_attach(GTK_TABLE(p->table),label, 0,4,0,1
137 					,GTK_FILL,GTK_FILL,0,0);
138 
139 	p->searchpat = gtk_entry_new();
140 	dialog_mnemonic_label_in_table(_("_Search for: "), p->searchpat, p->table, 0, 1, 1, 2);
141 	gtk_table_attach(GTK_TABLE(p->table),p->searchpat, 1,4,1,2,GTK_FILL|GTK_EXPAND,GTK_FILL,0,0);
142 
143 	p->replace = gtk_entry_new();
144 	dialog_mnemonic_label_in_table(_("Replace _with: "), p->replace, p->table, 0, 1, 2, 3);
145 	gtk_table_attach(GTK_TABLE(p->table),p->replace, 1,4,2,3,GTK_FILL|GTK_EXPAND,GTK_FILL,0,0);
146 
147 	p->scope = gtk_combo_box_text_new();
148 	for (i = 0; i < G_N_ELEMENTS(scope); i++) {
149 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(p->scope), _(scope[i]));
150 	}
151 	dialog_mnemonic_label_in_table(_("Sco_pe: "), p->scope, p->table, 0, 1, 3, 4);
152 	gtk_table_attach(GTK_TABLE(p->table),p->scope, 1,2,3,4,GTK_FILL|GTK_EXPAND,GTK_SHRINK,0,0);
153 
154 	p->matchtype = gtk_combo_box_text_new();
155 	for (i = 0; i < G_N_ELEMENTS(matchPattern); i++) {
156 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(p->matchtype), _(matchPattern[i]));
157 	}
158 	dialog_mnemonic_label_in_table(_("Match Patter_n: "), p->matchtype, p->table, 0, 1, 4, 5);
159 	gtk_table_attach(GTK_TABLE(p->table), p->matchtype, 1, 2, 4, 5, GTK_EXPAND|GTK_FILL,GTK_SHRINK, 0, 0);
160 
161 	p->casesens = gtk_check_button_new_with_mnemonic(_("Case sensitive _matching"));
162 	gtk_widget_set_tooltip_text(p->casesens,_("Only match if case (upper/lower) is identical."));
163 	gtk_table_attach(GTK_TABLE(p->table), p->casesens, 0, 2, 5, 6, GTK_EXPAND|GTK_FILL,GTK_SHRINK, 0, 0);
164 
165 	p->escapechars = gtk_check_button_new_with_mnemonic(_("_Use escape chars"));
166 	gtk_widget_set_tooltip_text(p->escapechars,_("Unescape backslash escaped characters such as \\n, \\t etc."));
167 	gtk_table_attach(GTK_TABLE(p->table), p->escapechars, 0, 2, 6, 7, GTK_EXPAND|GTK_FILL,GTK_SHRINK, 0, 0);
168 
169 	for (i = 0; i <  6; i++) {
170 		gchar *tmpstr;
171 		tmpstr = g_strdup_printf("%%%d ", i);
172 		label = gtk_label_new(tmpstr);
173 		gtk_misc_set_alignment(GTK_MISC(label),1,0.5);
174 		gtk_table_attach(GTK_TABLE(p->table),label, 2,3,i+3,i+4
175 					,GTK_FILL,GTK_FILL,0,0);
176 		g_free(tmpstr);
177 		p->entries[i] = gtk_entry_new();
178 		gtk_table_attach(GTK_TABLE(p->table),p->entries[i], 3,4,i+3,i+4
179 					,GTK_FILL,GTK_FILL,0,0);
180 	}
181 
182 	if (snwiz->node) {
183 		xmlNodePtr cur;
184 		xmlChar *tmpstr;
185 		xmlChar *region,*matchtype,*casesens,*escapechars;
186 		gint i=0;
187 		for (cur = snwiz->node->xmlChildrenNode;cur != NULL;cur = cur->next) {
188 			if (i < 6 && xmlStrEqual(cur->name, (const xmlChar *)"param")) {
189 				xmlChar *name;
190 				name = xmlGetProp(cur, (const xmlChar *)"name");
191 				gtk_entry_set_text(GTK_ENTRY(p->entries[i]), (gchar *)name);
192 				g_free(name);
193 				i++;
194 			} else if (xmlStrEqual(cur->name, (const xmlChar *)"searchpat")) {
195 				tmpstr = xmlNodeListGetString(snippets_v.doc, cur->xmlChildrenNode, 1);
196 				DEBUG_MSG("searchpattern: %s\n",tmpstr);
197 				gtk_entry_set_text(GTK_ENTRY(p->searchpat),(gchar *)tmpstr);
198 				g_free(tmpstr);
199 			} else if (xmlStrEqual(cur->name, (const xmlChar *)"replacepat")) {
200 				tmpstr = xmlNodeListGetString(snippets_v.doc, cur->xmlChildrenNode, 1);
201 				DEBUG_MSG("replacepattern: %s\n",tmpstr);
202 				gtk_entry_set_text(GTK_ENTRY(p->replace),(gchar *)tmpstr);
203 				g_free(tmpstr);
204 			}
205 		}
206 		region = xmlGetProp(snwiz->node, (const xmlChar *)"region");
207 		matchtype = xmlGetProp(snwiz->node, (const xmlChar *)"matchtype");
208 		casesens = xmlGetProp(snwiz->node, (const xmlChar *)"casesens");
209 		escapechars = xmlGetProp(snwiz->node, (const xmlChar *)"escapechars");
210 		gtk_combo_box_set_active(GTK_COMBO_BOX(p->scope),snippets_snr_region_from_char(region));
211 		gtk_combo_box_set_active(GTK_COMBO_BOX(p->matchtype),snippets_snr_matchtype_from_char(matchtype));
212 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->casesens), (casesens && casesens[0] == '1'));
213 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->escapechars), (escapechars && escapechars[0] == '1'));
214 	} else {
215 		gtk_combo_box_set_active(GTK_COMBO_BOX(p->scope),0);
216 		gtk_combo_box_set_active(GTK_COMBO_BOX(p->matchtype),0);
217 	}
218 
219 	gtk_widget_show_all(p->table);
220 	return p;
221 }
snippets_delete_pageSnr(Tsnipwiz * snwiz,gpointer data)222 static void snippets_delete_pageSnr(Tsnipwiz *snwiz, gpointer data) {
223 	TpageSnr *p = (TpageSnr *)data;
224 	gtk_widget_destroy(p->table);
225 	g_free(p);
226 }
227 
snippets_test_pageSnr(Tsnipwiz * snwiz,gpointer data)228 static gint snippets_test_pageSnr(Tsnipwiz *snwiz, gpointer data) {
229 	TpageSnr *p = (TpageSnr *)data;
230 	GtkTreePath *parentp;
231 	xmlNodePtr parentn, childn, tmpn;
232 	gchar *tmp="",*search,*replace;
233 	gint i;
234 	gint scope,casesens,matchtype,escapechars;
235 
236 	scope = gtk_combo_box_get_active(GTK_COMBO_BOX(p->scope));
237 	matchtype = gtk_combo_box_get_active(GTK_COMBO_BOX(p->matchtype));
238 	casesens = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p->casesens));
239 	escapechars = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p->escapechars));
240 
241 	if (snwiz->node) {
242 		xmlNodePtr cur;
243 		/* clean the old one */
244 		childn = snwiz->node;
245 		cur = childn->xmlChildrenNode;
246 		while (cur) {
247 			xmlUnlinkNode(cur);
248 			xmlFreeNode(cur);
249 			cur = childn->xmlChildrenNode;
250 		}
251 	} else {
252 		/* find the branch to add this leaf to */
253 		get_parentbranch(snwiz->snw, &parentp, &parentn);
254 		/* build a new one */
255 		childn = xmlNewChild(parentn,NULL,(const xmlChar *)"leaf",NULL);
256 		xmlSetProp(childn, (const xmlChar *)"type", (const xmlChar *)"snr");
257 	}
258 
259 	/* build the leaf */
260 	xmlSetProp(childn, (const xmlChar *)"title", (const xmlChar *)snwiz->name);
261 	if (snwiz->description) {
262 		xmlSetProp(childn, (const xmlChar *)"tooltip", (const xmlChar *)snwiz->description);
263 	}
264 
265 	switch (scope) {
266 		case 1:
267 			tmp = "c";
268 		break;
269 		case 2:
270 			tmp = "s";
271 		break;
272 		case 3:
273 			tmp = "a";
274 		break;
275 		case 0:
276 			tmp = "b";
277 		break;
278 	}
279 	xmlSetProp(childn, (const xmlChar *)"region", (const xmlChar *) tmp);
280 	switch (matchtype) {
281 		case 0:
282 			tmp = "normal";
283 		break;
284 		case 1:
285 			tmp = "perl";
286 		break;
287 	}
288 	xmlSetProp(childn, (const xmlChar *)"matchtype", (const xmlChar *) tmp);
289 
290 	xmlSetProp(childn, (const xmlChar *)"casesens", casesens ? (const xmlChar *)"1": (const xmlChar *)"0");
291 	xmlSetProp(childn, (const xmlChar *)"escapechars", escapechars ? (const xmlChar *)"1": (const xmlChar *)"0");
292 
293 	search = gtk_editable_get_chars(GTK_EDITABLE(p->searchpat),0,-1);
294 	replace = gtk_editable_get_chars(GTK_EDITABLE(p->replace),0,-1);
295 	xmlNewTextChild(childn,NULL,(const xmlChar *)"searchpat",(const xmlChar *)search);
296 	xmlNewTextChild(childn,NULL,(const xmlChar *)"replacepat",(const xmlChar *)replace);
297 	for (i = 0; i <  6; i++) {
298 		gchar *tmpstr;
299 		tmpstr = gtk_editable_get_chars(GTK_EDITABLE(p->entries[i]),0,-1);
300 		if (strlen(tmpstr)>0) {
301 			tmpn = xmlNewChild(childn,NULL,(const xmlChar *)"param", NULL);
302 			xmlSetProp(tmpn, (const xmlChar *)"name", (const xmlChar *)tmpstr);
303 		}
304 	}
305 	if (!snwiz->node) {
306 		/* now add this item to the treestore */
307 		add_item_to_tree(parentp, pixmap_type_snr, snwiz->name, childn);
308 	} else {
309 		update_name_in_tree(snwiz->snw, snwiz->name);
310 	}
311 	return page_finished;
312 }
313 
314 typedef struct {
315 	GtkWidget *table;
316 	GtkWidget *entries[10];
317 	GtkWidget *is_file[10];
318 	GtkWidget *before_v;
319 	GtkWidget *after_v;
320 	GtkTextBuffer *before;
321 	GtkTextBuffer *after;
322 } TpageInsert;
323 
snippets_build_pageInsert(Tsnipwiz * snwiz,GtkWidget * dialog_action)324 static gpointer snippets_build_pageInsert(Tsnipwiz *snwiz, GtkWidget *dialog_action) {
325 	GtkWidget *scrolwin, *label;
326 	gint i;
327 	gchar *tmpstr;
328 	TpageInsert *p2 = g_new(TpageInsert,1);
329 
330 	p2->table = gtk_table_new(13, 5, FALSE);
331 	gtk_table_set_row_spacings(GTK_TABLE (p2->table), 6);
332 	gtk_table_set_col_spacings(GTK_TABLE (p2->table), 12);
333 	gtk_box_pack_start(GTK_BOX(dialog_action), p2->table, TRUE, TRUE, 0);
334 
335 	label = gtk_label_new(_("The <i>before</i> text will be inserted before the cursor position or the current selection, the <i>after</i> text will be inserted after the cursor position or the current selection. You may use %0, %1, ...%9 placeholders to ask for values when you activate this item. Give these placeholders an appropriate name on the right. (Please use %% if you need literal % in your string!)"));
336 	gtk_label_set_use_markup(GTK_LABEL(label),TRUE);
337 	gtk_label_set_line_wrap(GTK_LABEL(label),TRUE);
338 #if GTK_CHECK_VERSION(3,2,0)
339 	gtk_label_set_width_chars(GTK_LABEL(label),50);
340 #endif
341 	gtk_table_attach(GTK_TABLE(p2->table),label, 0,5,0,1
342 					,GTK_FILL|GTK_EXPAND,GTK_FILL,0,0);
343 
344 	label = gtk_label_new(_("<i>Before</i> text"));
345 	gtk_label_set_use_markup(GTK_LABEL(label),TRUE);
346 	gtk_misc_set_alignment(GTK_MISC(label),0,0.5);
347 	gtk_table_attach(GTK_TABLE(p2->table),label, 0,1,1,2,GTK_FILL,GTK_FILL,0,0);
348 	scrolwin = textview_buffer_in_scrolwin(&p2->before_v, -1, -1, NULL, GTK_WRAP_NONE);
349 	gtk_table_attach(GTK_TABLE(p2->table), scrolwin, /*left*/0,/*right*/1,/*top*/2,/*bottom*/6
350 				,/*xoptions*/GTK_EXPAND|GTK_FILL,/*yoptions*/GTK_EXPAND|GTK_FILL
351 				,/*xpadding*/0,/*ypadding*/0);
352 	p2->before = gtk_text_view_get_buffer(GTK_TEXT_VIEW(p2->before_v));
353 
354 	label = gtk_label_new(_("<i>After</i> text"));
355 	gtk_label_set_use_markup(GTK_LABEL(label),TRUE);
356 	gtk_misc_set_alignment(GTK_MISC(label),0,0.5);
357 	gtk_table_attach(GTK_TABLE(p2->table),label, 0,1,6,7,GTK_FILL,GTK_FILL,0,0);
358 	scrolwin = textview_buffer_in_scrolwin(&p2->after_v, -1, -1, NULL, GTK_WRAP_NONE);
359 	gtk_table_attach(GTK_TABLE(p2->table), scrolwin, 0,1,7,11
360 				,GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,0);
361 	p2->after = gtk_text_view_get_buffer(GTK_TEXT_VIEW(p2->after_v));
362 	gtk_table_attach(GTK_TABLE(p2->table),gtk_label_new(_("Number")), 1,2,1,2
363 					,GTK_FILL,GTK_FILL,0,0);
364 	gtk_table_attach(GTK_TABLE(p2->table),gtk_label_new(_("Name")), 2,3,1,2
365 					,GTK_FILL,GTK_FILL,0,0);
366 	gtk_table_attach(GTK_TABLE(p2->table),gtk_label_new(_("Is file path")), 3,4,1,2
367 					,GTK_FILL,GTK_FILL,0,0);
368 	for (i = 0; i <  10; i++) {
369 		tmpstr = g_strdup_printf("%%%d ", i);
370 		label = gtk_label_new(tmpstr);
371 		gtk_misc_set_alignment(GTK_MISC(label),1,0.5);
372 		gtk_table_attach(GTK_TABLE(p2->table),label, 1,2,i+2,i+3
373 					,GTK_FILL,GTK_FILL,0,0);
374 		g_free(tmpstr);
375 		p2->entries[i] = gtk_entry_new();
376 		gtk_table_attach(GTK_TABLE(p2->table),p2->entries[i], 2,3,i+2,i+3
377 					,GTK_FILL,GTK_FILL,0,0);
378 		p2->is_file[i] = gtk_check_button_new();
379 		gtk_table_attach(GTK_TABLE(p2->table),p2->is_file[i], 3,4,i+2,i+3
380 					,GTK_SHRINK,GTK_SHRINK,0,0);
381 	}
382 
383 	if (snwiz->node) {
384 		xmlNodePtr cur;
385 		xmlChar *tmpstr;
386 		gint i=0;
387 		for (cur = snwiz->node->xmlChildrenNode;cur != NULL;cur = cur->next) {
388 			if (i<10 && xmlStrEqual(cur->name, (const xmlChar *)"param")) {
389 				xmlChar *name, *is_file;
390 				name = xmlGetProp(cur, (const xmlChar *)"name");
391 				is_file = xmlGetProp(cur, (const xmlChar *)"is_file");
392 				gtk_entry_set_text(GTK_ENTRY(p2->entries[i]), (gchar *)name);
393 				if (is_file&&is_file[0]=='1')
394 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2->is_file[i]),1);
395 				g_free(name);
396 				g_free(is_file);
397 				i++;
398 			} else if (xmlStrEqual(cur->name, (const xmlChar *)"before")) {
399 				tmpstr = xmlNodeListGetString(snippets_v.doc, cur->xmlChildrenNode, 1);
400 				if (tmpstr) {
401 					gtk_text_buffer_set_text(p2->before,(gchar *)tmpstr,-1);
402 					g_free(tmpstr);
403 				}
404 			} else if (xmlStrEqual(cur->name, (const xmlChar *)"after")) {
405 				tmpstr = xmlNodeListGetString(snippets_v.doc, cur->xmlChildrenNode, 1);
406 				if (tmpstr) {
407 					gtk_text_buffer_set_text(p2->after,(gchar *)tmpstr,-1);
408 					g_free(tmpstr);
409 				}
410 			}
411 		}
412 	}
413 	gtk_widget_show_all(p2->table);
414 	return p2;
415 }
416 
snippets_delete_pageInsert(Tsnipwiz * snwiz,gpointer data)417 static void snippets_delete_pageInsert(Tsnipwiz *snwiz, gpointer data) {
418 	TpageInsert *p2 = (TpageInsert *)data;
419 	gtk_widget_destroy(p2->table);
420 	g_free(p2);
421 }
422 
snippets_test_pageInsert(Tsnipwiz * snwiz,gpointer data)423 static gint snippets_test_pageInsert(Tsnipwiz *snwiz, gpointer data) {
424 	TpageInsert *p2 = (TpageInsert *)data;
425 	GtkTreePath *parentp;
426 	xmlNodePtr parentn, childn, tmpn;
427 	gchar *before, *after;
428 	gint i;
429 
430 	if (snwiz->node) {
431 		xmlNodePtr cur;
432 		/* clean the old one */
433 		childn = snwiz->node;
434 		cur = childn->xmlChildrenNode;
435 		while (cur) {
436 			xmlUnlinkNode(cur);
437 			xmlFreeNode(cur);
438 			cur = childn->xmlChildrenNode;
439 		}
440 	} else {
441 		/* find the branch to add this leaf to */
442 		get_parentbranch(snwiz->snw, &parentp, &parentn);
443 		/* build a new one */
444 		childn = xmlNewChild(parentn,NULL,(const xmlChar *)"leaf",NULL);
445 		xmlSetProp(childn, (const xmlChar *)"type", (const xmlChar *)"insert");
446 	}
447 
448 	/* build the leaf */
449 	before = textbuffer_get_all_chars(p2->before);
450 	after = textbuffer_get_all_chars(p2->after);
451 	xmlSetProp(childn, (const xmlChar *)"title", (const xmlChar *)snwiz->name);
452 	if (snwiz->description) {
453 		xmlSetProp(childn, (const xmlChar *)"tooltip", (const xmlChar *)snwiz->description);
454 	}
455 
456 	xmlNewTextChild(childn,NULL,(const xmlChar *)"before",(const xmlChar *)before);
457 	xmlNewTextChild(childn,NULL,(const xmlChar *)"after",(const xmlChar *)after);
458 	for (i = 0; i <  10; i++) {
459 		gchar *tmpstr;
460 		tmpstr = gtk_editable_get_chars(GTK_EDITABLE(p2->entries[i]),0,-1);
461 		if (strlen(tmpstr)>0) {
462 			tmpn = xmlNewChild(childn,NULL,(const xmlChar *)"param", NULL);
463 			xmlSetProp(tmpn, (const xmlChar *)"name", (const xmlChar *)tmpstr);
464 			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->is_file[i]))) {
465 				xmlSetProp(tmpn, (const xmlChar *)"is_file", (const xmlChar *)"1");
466 			}
467 		}
468 	}
469 	if (!snwiz->node) {
470 		/* now add this item to the treestore */
471 		add_item_to_tree(parentp, pixmap_type_insert, snwiz->name, childn);
472 	} else {
473 		update_name_in_tree(snwiz->snw, snwiz->name);
474 	}
475 	return page_finished;
476 }
477 
478 typedef struct {
479 	GtkWidget *entry;
480 	GtkWidget *vbox;
481 } TpageBranch;
482 
snippets_build_pageBranch(Tsnipwiz * snwiz,GtkWidget * dialog_action)483 static gpointer snippets_build_pageBranch(Tsnipwiz *snwiz, GtkWidget *dialog_action) {
484 	GtkWidget *label;
485 	gchar *namestr=NULL;
486 	TpageBranch *p1 = g_new(TpageBranch,1);
487 	if (snwiz->node) {	/* we're editing a node! */
488 		namestr = (gchar *)xmlGetProp(snwiz->node, (const xmlChar *)"title");
489 	}
490 	p1->vbox = gtk_vbox_new(TRUE,12);
491 	gtk_container_add(GTK_CONTAINER(dialog_action),p1->vbox);
492 	label = gtk_label_new(_("Enter the name of the branch:"));
493 	gtk_box_pack_start(GTK_BOX(p1->vbox),label,TRUE,TRUE,12);
494 	p1->entry = gtk_entry_new();
495 	if (namestr) {
496 		gtk_entry_set_text((GtkEntry *)p1->entry,namestr);
497 	}
498 	gtk_box_pack_start(GTK_BOX(p1->vbox),p1->entry,TRUE,TRUE,12);
499 	gtk_widget_show_all(p1->vbox);
500 	return p1;
501 }
502 
snippets_delete_pageBranch(Tsnipwiz * snwiz,gpointer data)503 static void snippets_delete_pageBranch(Tsnipwiz *snwiz, gpointer data) {
504 	TpageBranch *p1 = (TpageBranch *)data;
505 	gtk_widget_destroy(p1->vbox);
506 }
507 
snippets_test_pageBranch(Tsnipwiz * snwiz,gpointer data)508 static gint snippets_test_pageBranch(Tsnipwiz *snwiz, gpointer data) {
509 	TpageBranch *p1 = (TpageBranch *)data;
510 	gchar *name;
511 	GtkTreePath *parentp=NULL;
512 	xmlNodePtr parent=NULL, child;
513 	GtkTreeIter piter, citer;
514 
515 	name = gtk_editable_get_chars(GTK_EDITABLE(p1->entry),0,-1);
516 
517 	if (snwiz->node) {
518 		xmlSetProp(snwiz->node, (const xmlChar *)"title", (const xmlChar *)name);
519 		update_name_in_tree(snwiz->snw, name);
520 	} else {
521 		/* lets build the branch! */
522 		if (snwiz->snw->lastclickedpath) {
523 			parentp = gtk_tree_path_copy(snwiz->snw->lastclickedpath);
524 		}
525 		if (snwiz->snw->lastclickednode) {
526 			if (xmlStrEqual(snwiz->snw->lastclickednode->name, (const xmlChar *)"leaf")) {
527 				DEBUG_MSG("clicked node was a leaf\n");
528 				parent = snwiz->snw->lastclickednode->parent;
529 				if (parentp) {
530 					if (!gtk_tree_path_up(parentp)) {
531 						DEBUG_MSG("could not go up, set parentp NULL\n");
532 						gtk_tree_path_free(parentp);
533 						parentp = NULL;
534 					}
535 				}
536 			} else {
537 				parent = snwiz->snw->lastclickednode;
538 				DEBUG_MSG("clicked node was a branch\n");
539 			}
540 		} else { /* parent must be the root element <snippets> */
541 			parent = xmlDocGetRootElement(snippets_v.doc);
542 		}
543 		DEBUG_MSG("snippets_test_pageBranch, xml-adding %s to parent %s\n",name,(gchar *)parent->name);
544 		child = xmlNewChild(parent,NULL,(const xmlChar *)"branch",NULL);
545 		xmlSetProp(child, (const xmlChar *)"title", (const xmlChar *)name);
546 		/* add this branch to the treestore */
547 		DEBUG_MSG("snippets_test_pageBranch, store-adding %s to parentp=%p\n",name,parentp);
548 		if (parentp) {
549 			if (gtk_tree_model_get_iter(GTK_TREE_MODEL(snippets_v.store),&piter,parentp)) {
550 				gtk_tree_store_append(snippets_v.store, &citer, &piter);
551 			} else {
552 				g_print("hmm weird error!?!\n");
553 			}
554 		} else {
555 			gtk_tree_store_append(snippets_v.store, &citer, NULL);
556 		}
557 		gtk_tree_store_set(snippets_v.store, &citer, PIXMAP_COLUMN,NULL,TITLE_COLUMN, name,NODE_COLUMN, child,-1);
558 	}
559 
560 	DEBUG_MSG("add branch with title %s\n",name);
561 	g_free(name);
562 	g_idle_add(snippets_store_lcb, NULL);
563 	return page_finished;
564 }
565 
566 typedef struct {
567 	GtkWidget *name;
568 	GtkWidget *description;
569 	GtkWidget *vbox;
570 } TpageName;
571 
snippets_build_pageName(Tsnipwiz * snwiz,GtkWidget * dialog_action)572 static gpointer snippets_build_pageName(Tsnipwiz *snwiz, GtkWidget *dialog_action) {
573 	GtkWidget *label, *scrolwin;
574 	gchar *namestr=NULL, *descstr=NULL;
575 	TpageName *p = g_new(TpageName,1);
576 
577 	if (snwiz->node) {	/* we're editing a node! */
578 		namestr = (gchar *)xmlGetProp(snwiz->node, (const xmlChar *)"title");
579 		descstr = (gchar *)xmlGetProp(snwiz->node, (const xmlChar *)"tooltip");
580 	}
581 
582 	p->vbox = gtk_vbox_new(FALSE,12);
583 	gtk_container_add(GTK_CONTAINER(dialog_action),p->vbox);
584 	label = gtk_label_new(_("Name of the new item:"));
585 	gtk_box_pack_start(GTK_BOX(p->vbox),label,TRUE,FALSE,12);
586 	p->name = gtk_entry_new();
587 	if (namestr) gtk_entry_set_text(GTK_ENTRY(p->name),namestr);
588 	gtk_box_pack_start(GTK_BOX(p->vbox),p->name,TRUE,FALSE,12);
589 	label = gtk_label_new(_("Description:"));
590 	gtk_box_pack_start(GTK_BOX(p->vbox),label,TRUE,FALSE,12);
591 	scrolwin = textview_buffer_in_scrolwin(&p->description, -1, -1, descstr, GTK_WRAP_NONE);
592 	gtk_box_pack_start(GTK_BOX(p->vbox),scrolwin,TRUE,TRUE,12);
593 
594 	gtk_widget_show_all(p->vbox);
595 	g_free(namestr);
596 	g_free(descstr);
597 	return p;
598 }
599 
snippets_delete_pageName(Tsnipwiz * snwiz,gpointer data)600 static void snippets_delete_pageName(Tsnipwiz *snwiz, gpointer data) {
601 	TpageName *p = (TpageName *)data;
602 	gtk_widget_destroy(p->vbox);
603 	g_free(p);
604 }
605 
snippets_test_pageName(Tsnipwiz * snwiz,gpointer data)606 static gint snippets_test_pageName(Tsnipwiz *snwiz, gpointer data) {
607 	TpageName *p = (TpageName *)data;
608 	gchar *name, *desc;
609 
610 	name = gtk_editable_get_chars(GTK_EDITABLE(p->name),0,-1);
611 	desc = textbuffer_get_all_chars(gtk_text_view_get_buffer(GTK_TEXT_VIEW(p->description)));
612 	if (strlen(name)) {
613 		snwiz->name = name;
614 		snwiz->description = desc;
615 		if (snwiz->choice == 1) {
616 			return page_insert;
617 		} else {
618 			return page_snr;
619 		}
620 	} else {
621 		/* warn */
622 
623 		g_free(name);
624 		g_free(desc);
625 		return page_name;
626 	}
627 }
628 
629 typedef struct {
630 	GtkWidget *radio[3];
631 	GtkWidget *vbox;
632 } TpageType;
633 
snippets_build_pageType(Tsnipwiz * snwiz,GtkWidget * dialog_action)634 static gpointer snippets_build_pageType(Tsnipwiz *snwiz, GtkWidget *dialog_action) {
635 	GtkWidget *label;
636 	TpageType *p0 = g_new(TpageType,1);
637 	p0->vbox = gtk_vbox_new(FALSE,12);
638 	gtk_container_add(GTK_CONTAINER(dialog_action),p0->vbox);
639 	label = gtk_label_new(_("Select what you want to add"));
640 	gtk_box_pack_start(GTK_BOX(p0->vbox),label,TRUE,TRUE,12);
641 	p0->radio[0] = gtk_radio_button_new_with_label(NULL, _("Branch"));
642 	gtk_box_pack_start(GTK_BOX(p0->vbox),p0->radio[0],TRUE,TRUE,12);
643 	p0->radio[1] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p0->radio[0]),_("Insert string"));
644 	gtk_box_pack_start(GTK_BOX(p0->vbox),p0->radio[1],TRUE,TRUE,12);
645 	p0->radio[2] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p0->radio[0]),_("Search and replace pattern"));
646 	gtk_box_pack_start(GTK_BOX(p0->vbox),p0->radio[2],TRUE,TRUE,12);
647 	gtk_widget_show_all(p0->vbox);
648 	DEBUG_MSG("snippets_build_pageType, created pageType at %p\n",p0);
649 	return p0;
650 }
651 
snippets_delete_pageType(Tsnipwiz * snwiz,gpointer data)652 static void snippets_delete_pageType(Tsnipwiz *snwiz, gpointer data) {
653 	TpageType *p0 = (TpageType *)data;
654 	DEBUG_MSG("snippets_delete_pageType, destroy pageType at %p\n",p0);
655 	gtk_widget_destroy(p0->vbox);
656 	g_free(p0);
657 }
658 
snippets_test_pageType(Tsnipwiz * snwiz,gpointer data)659 static gint snippets_test_pageType(Tsnipwiz *snwiz, gpointer data) {
660 	TpageType *p0 = (TpageType *)data;
661 	int i;
662 	DEBUG_MSG("snippets_delete_pageType, test pageType at %p\n",p0);
663 	for (i=0;i<3;i++) {
664 		if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p0->radio[i]))) {
665 			snwiz->choice = i;
666 			if (i==0) return page_branch;
667 			else return page_name;
668 		}
669 	}
670 	return page_type;
671 }
672 
snipwiz_dialog_response_lcb(GtkDialog * dialog,gint response,Tsnipwiz * snwiz)673 static void snipwiz_dialog_response_lcb(GtkDialog *dialog, gint response, Tsnipwiz *snwiz) {
674 	Tpagenum newpagenum=page_type;
675 	DEBUG_MSG("snipwiz_dialog_response_lcb, response=%d\n",response);
676 	if (response == GTK_RESPONSE_REJECT) {
677 		gtk_widget_destroy(snwiz->dialog);
678 		g_free(snwiz);
679 		return;
680 	}
681 	switch (snwiz->pagenum) { /* test the current results */
682 		case page_type:
683 			newpagenum = snippets_test_pageType(snwiz,snwiz->pagestruct);
684 			if (newpagenum != page_type) {
685 				snippets_delete_pageType(snwiz,snwiz->pagestruct);
686 			}
687 		break;
688 		case page_name:
689 			newpagenum = snippets_test_pageName(snwiz,snwiz->pagestruct);
690 			if (newpagenum != page_name) {
691 				snippets_delete_pageName(snwiz,snwiz->pagestruct);
692 			}
693 		break;
694 		case page_branch:
695 			newpagenum = snippets_test_pageBranch(snwiz,snwiz->pagestruct);
696 			if (newpagenum != page_branch) {
697 				snippets_delete_pageBranch(snwiz,snwiz->pagestruct);
698 			}
699 		break;
700 		case page_insert:
701 			newpagenum = snippets_test_pageInsert(snwiz,snwiz->pagestruct);
702 			if (newpagenum != page_insert) {
703 				snippets_delete_pageInsert(snwiz,snwiz->pagestruct);
704 			}
705 		break;
706 		case page_snr:
707 			newpagenum = snippets_test_pageSnr(snwiz,snwiz->pagestruct);
708 			if (newpagenum != page_snr) {
709 				snippets_delete_pageSnr(snwiz,snwiz->pagestruct);
710 			}
711 		break;
712 		case page_finished: /* avoid compiler warning */
713 		break;
714 	}
715 	if (snwiz->pagenum != newpagenum) {
716 		GtkWidget *vbox = gtk_dialog_get_content_area(GTK_DIALOG(snwiz->dialog));
717 		switch (newpagenum) { /* build a new page */
718 			case page_type:
719 				snwiz->pagestruct = snippets_build_pageType(snwiz, vbox);
720 			break;
721 			case page_name:
722 				snwiz->pagestruct = snippets_build_pageName(snwiz, vbox);
723 			break;
724 			case page_branch:
725 				snwiz->pagestruct = snippets_build_pageBranch(snwiz, vbox);
726 			break;
727 			case page_insert:
728 				snwiz->pagestruct = snippets_build_pageInsert(snwiz, vbox);
729 			break;
730 			case page_snr:
731 				snwiz->pagestruct = snippets_build_pageSnr(snwiz, vbox);
732 			break;
733 			case page_finished:
734 				gtk_widget_destroy(snwiz->dialog);
735 				if (snwiz->name) g_free(snwiz->name);
736 				if (snwiz->description) g_free(snwiz->description);
737 				g_free(snwiz);
738 				g_idle_add(snippets_store_lcb, NULL);
739 				return;
740 			break;
741 		}
742 		snwiz->pagenum = newpagenum;
743 	}
744 }
745 
746 
snippets_new_item_dialog(Tsnippetswin * snw,xmlNodePtr node)747 void snippets_new_item_dialog(Tsnippetswin *snw, xmlNodePtr node) {
748 	Tsnipwiz *snwiz;
749 	GtkWidget *vbox;
750 
751 	snwiz = g_new0(Tsnipwiz,1);
752 	snwiz->snw = snw;
753 	snwiz->node = node;
754 	snwiz->dialog = gtk_dialog_new_with_buttons(node? _("Edit snippet") :_("New snippet"),GTK_WINDOW(snw->bfwin->main_window),
755 					GTK_DIALOG_DESTROY_WITH_PARENT,
756 					GTK_STOCK_CANCEL,GTK_RESPONSE_REJECT,
757 					GTK_STOCK_GO_FORWARD,1,
758 					NULL);
759 	gtk_window_set_default_size(GTK_WINDOW(snwiz->dialog),500,400);
760 	g_signal_connect(G_OBJECT(snwiz->dialog), "response", G_CALLBACK(snipwiz_dialog_response_lcb), snwiz);
761 	vbox = gtk_dialog_get_content_area(GTK_DIALOG(snwiz->dialog));
762 	if (node) {
763 		if (xmlStrEqual(snw->lastclickednode->name, (const xmlChar *)"leaf")) {
764 			xmlChar *type = xmlGetProp(node, (const xmlChar *)"type");
765 			if (xmlStrEqual(type, (const xmlChar *)"insert")) {
766 				snwiz->choice = 1;
767 			} else if (xmlStrEqual(type, (const xmlChar *)"snr")) {
768 				snwiz->choice = 2;
769 			}
770 			snwiz->pagestruct = snippets_build_pageName(snwiz, vbox);
771 			snwiz->pagenum = page_name;
772 		} else {
773 			snwiz->pagestruct = snippets_build_pageBranch(snwiz, vbox);
774 			snwiz->pagenum = page_branch;
775 		}
776 	} else {
777 		if (!snw->lastclickednode) {
778 			snwiz->pagestruct = snippets_build_pageBranch(snwiz, vbox);
779 			snwiz->pagenum = page_branch;
780 		} else {
781 			snwiz->pagestruct = snippets_build_pageType(snwiz, vbox);
782 			snwiz->pagenum = page_type;
783 		}
784 	}
785 	gtk_widget_show_all(snwiz->dialog);
786 }
787