1 /*
2  * This program is free software; you can redistribute it and/or modify it
3  * under the terms of the GNU Lesser General Public License as published by
4  * the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful, but
7  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
9  * for more details.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, see <http://www.gnu.org/licenses/>.
13  *
14  *
15  * Authors:
16  *		Not Zed <notzed@lostzed.mmc.com.au>
17  *      Jeffrey Stedfast <fejj@ximian.com>
18  *
19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20  *
21  */
22 
23 #include "evolution-config.h"
24 
25 #include <string.h>
26 #include <stdlib.h>
27 
28 #include "e-filter-element.h"
29 #include "e-filter-part.h"
30 
31 typedef EFilterElement * (*EFilterElementFunc) (gpointer data);
32 
33 struct _element_type {
34 	gchar *name;
35 
36 	EFilterElementFunc create;
37 	gpointer data;
38 };
39 
G_DEFINE_TYPE(EFilterElement,e_filter_element,G_TYPE_OBJECT)40 G_DEFINE_TYPE (
41 	EFilterElement,
42 	e_filter_element,
43 	G_TYPE_OBJECT)
44 
45 static gboolean
46 filter_element_validate (EFilterElement *element,
47                          EAlert **alert)
48 {
49 	return TRUE;
50 }
51 
52 static gint
filter_element_eq(EFilterElement * element_a,EFilterElement * element_b)53 filter_element_eq (EFilterElement *element_a,
54                    EFilterElement *element_b)
55 {
56 	return (g_strcmp0 (element_a->name, element_b->name) == 0);
57 }
58 
59 static void
filter_element_xml_create(EFilterElement * element,xmlNodePtr node)60 filter_element_xml_create (EFilterElement *element,
61                            xmlNodePtr node)
62 {
63 	element->name = (gchar *) xmlGetProp (node, (xmlChar *) "name");
64 }
65 
66 static EFilterElement *
filter_element_clone(EFilterElement * element)67 filter_element_clone (EFilterElement *element)
68 {
69 	EFilterElement *clone;
70 	xmlNodePtr node;
71 
72 	clone = g_object_new (G_OBJECT_TYPE (element), NULL);
73 
74 	node = e_filter_element_xml_encode (element);
75 	e_filter_element_xml_decode (clone, node);
76 	xmlFreeNodeList (node);
77 
78 	return clone;
79 }
80 
81 /* This is somewhat hackish, implement all the base cases in here */
82 #include "e-filter-input.h"
83 #include "e-filter-option.h"
84 #include "e-filter-code.h"
85 #include "e-filter-color.h"
86 #include "e-filter-datespec.h"
87 #include "e-filter-int.h"
88 #include "e-filter-file.h"
89 
90 static void
filter_element_copy_value(EFilterElement * dst_element,EFilterElement * src_element)91 filter_element_copy_value (EFilterElement *dst_element,
92                            EFilterElement *src_element)
93 {
94 	if (E_IS_FILTER_INPUT (src_element)) {
95 		EFilterInput *src_input;
96 
97 		src_input = E_FILTER_INPUT (src_element);
98 
99 		if (E_IS_FILTER_INPUT (dst_element)) {
100 			EFilterInput *dst_input;
101 
102 			dst_input = E_FILTER_INPUT (dst_element);
103 
104 			if (src_input->values)
105 				e_filter_input_set_value (
106 					dst_input,
107 					src_input->values->data);
108 
109 		} else if (E_IS_FILTER_INT (dst_element)) {
110 			EFilterInt *dst_int;
111 
112 			dst_int = E_FILTER_INT (dst_element);
113 
114 			dst_int->val = atoi (src_input->values->data);
115 		}
116 
117 	} else if (E_IS_FILTER_COLOR (src_element)) {
118 		EFilterColor *src_color;
119 
120 		src_color = E_FILTER_COLOR (src_element);
121 
122 		if (E_IS_FILTER_COLOR (dst_element)) {
123 			EFilterColor *dst_color;
124 
125 			dst_color = E_FILTER_COLOR (dst_element);
126 
127 			dst_color->color = src_color->color;
128 		}
129 
130 	} else if (E_IS_FILTER_DATESPEC (src_element)) {
131 		EFilterDatespec *src_datespec;
132 
133 		src_datespec = E_FILTER_DATESPEC (src_element);
134 
135 		if (E_IS_FILTER_DATESPEC (dst_element)) {
136 			EFilterDatespec *dst_datespec;
137 
138 			dst_datespec = E_FILTER_DATESPEC (dst_element);
139 
140 			dst_datespec->type = src_datespec->type;
141 			dst_datespec->value = src_datespec->value;
142 		}
143 
144 	} else if (E_IS_FILTER_INT (src_element)) {
145 		EFilterInt *src_int;
146 
147 		src_int = E_FILTER_INT (src_element);
148 
149 		if (E_IS_FILTER_INT (dst_element)) {
150 			EFilterInt *dst_int;
151 
152 			dst_int = E_FILTER_INT (dst_element);
153 
154 			dst_int->val = src_int->val;
155 
156 		} else if (E_IS_FILTER_INPUT (dst_element)) {
157 			EFilterInput *dst_input;
158 			gchar *values;
159 
160 			dst_input = E_FILTER_INPUT (dst_element);
161 
162 			values = g_strdup_printf ("%d", src_int->val);
163 			e_filter_input_set_value (dst_input, values);
164 			g_free (values);
165 		}
166 
167 	} else if (E_IS_FILTER_OPTION (src_element)) {
168 		EFilterOption *src_option;
169 
170 		src_option = E_FILTER_OPTION (src_element);
171 
172 		if (E_IS_FILTER_OPTION (dst_element)) {
173 			EFilterOption *dst_option;
174 
175 			dst_option = E_FILTER_OPTION (dst_element);
176 
177 			if (src_option->current)
178 				e_filter_option_set_current (
179 					dst_option,
180 					src_option->current->value);
181 		}
182 	}
183 }
184 
185 static void
filter_element_finalize(GObject * object)186 filter_element_finalize (GObject *object)
187 {
188 	EFilterElement *element = E_FILTER_ELEMENT (object);
189 
190 	xmlFree (element->name);
191 
192 	/* Chain up to parent's finalize () method. */
193 	G_OBJECT_CLASS (e_filter_element_parent_class)->finalize (object);
194 }
195 
196 static void
e_filter_element_class_init(EFilterElementClass * class)197 e_filter_element_class_init (EFilterElementClass *class)
198 {
199 	GObjectClass *object_class;
200 
201 	object_class = G_OBJECT_CLASS (class);
202 	object_class->finalize = filter_element_finalize;
203 
204 	class->validate = filter_element_validate;
205 	class->eq = filter_element_eq;
206 	class->xml_create = filter_element_xml_create;
207 	class->clone = filter_element_clone;
208 	class->copy_value = filter_element_copy_value;
209 }
210 
211 static void
e_filter_element_init(EFilterElement * element)212 e_filter_element_init (EFilterElement *element)
213 {
214 }
215 
216 /**
217  * filter_element_new:
218  *
219  * Create a new EFilterElement object.
220  *
221  * Return value: A new #EFilterElement object.
222  **/
223 EFilterElement *
e_filter_element_new(void)224 e_filter_element_new (void)
225 {
226 	return g_object_new (E_TYPE_FILTER_ELEMENT, NULL);
227 }
228 
229 gboolean
e_filter_element_validate(EFilterElement * element,EAlert ** alert)230 e_filter_element_validate (EFilterElement *element,
231                            EAlert **alert)
232 {
233 	EFilterElementClass *class;
234 
235 	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element), FALSE);
236 
237 	class = E_FILTER_ELEMENT_GET_CLASS (element);
238 	g_return_val_if_fail (class != NULL, FALSE);
239 	g_return_val_if_fail (class->validate != NULL, FALSE);
240 
241 	return class->validate (element, alert);
242 }
243 
244 gint
e_filter_element_eq(EFilterElement * element_a,EFilterElement * element_b)245 e_filter_element_eq (EFilterElement *element_a,
246                      EFilterElement *element_b)
247 {
248 	EFilterElementClass *class;
249 
250 	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element_a), FALSE);
251 	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element_b), FALSE);
252 
253 	/* The elements must be the same type. */
254 	if (G_OBJECT_TYPE (element_a) != G_OBJECT_TYPE (element_b))
255 		return FALSE;
256 
257 	class = E_FILTER_ELEMENT_GET_CLASS (element_a);
258 	g_return_val_if_fail (class != NULL, FALSE);
259 	g_return_val_if_fail (class->eq != NULL, FALSE);
260 
261 	return class->eq (element_a, element_b);
262 }
263 
264 /**
265  * filter_element_xml_create:
266  * @fe: filter element
267  * @node: xml node
268  *
269  * Create a new filter element based on an xml definition of
270  * that element.
271  **/
272 void
e_filter_element_xml_create(EFilterElement * element,xmlNodePtr node)273 e_filter_element_xml_create (EFilterElement *element,
274                              xmlNodePtr node)
275 {
276 	EFilterElementClass *class;
277 
278 	g_return_if_fail (E_IS_FILTER_ELEMENT (element));
279 	g_return_if_fail (node != NULL);
280 
281 	class = E_FILTER_ELEMENT_GET_CLASS (element);
282 	g_return_if_fail (class != NULL);
283 	g_return_if_fail (class->xml_create != NULL);
284 
285 	class->xml_create (element, node);
286 }
287 
288 /**
289  * filter_element_xml_encode:
290  * @fe: filter element
291  *
292  * Encode the values of a filter element into xml format.
293  *
294  * Return value:
295  **/
296 xmlNodePtr
e_filter_element_xml_encode(EFilterElement * element)297 e_filter_element_xml_encode (EFilterElement *element)
298 {
299 	EFilterElementClass *class;
300 
301 	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element), NULL);
302 
303 	class = E_FILTER_ELEMENT_GET_CLASS (element);
304 	g_return_val_if_fail (class != NULL, NULL);
305 	g_return_val_if_fail (class->xml_encode != NULL, NULL);
306 
307 	return class->xml_encode (element);
308 }
309 
310 /**
311  * filter_element_xml_decode:
312  * @fe: filter element
313  * @node: xml node
314  *
315  * Decode the values of a fitler element from xml format.
316  *
317  * Return value:
318  **/
319 gint
e_filter_element_xml_decode(EFilterElement * element,xmlNodePtr node)320 e_filter_element_xml_decode (EFilterElement *element,
321                              xmlNodePtr node)
322 {
323 	EFilterElementClass *class;
324 
325 	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element), FALSE);
326 	g_return_val_if_fail (node != NULL, FALSE);
327 
328 	class = E_FILTER_ELEMENT_GET_CLASS (element);
329 	g_return_val_if_fail (class != NULL, FALSE);
330 	g_return_val_if_fail (class->xml_decode != NULL, FALSE);
331 
332 	return class->xml_decode (element, node);
333 }
334 
335 /**
336  * filter_element_clone:
337  * @fe: filter element
338  *
339  * Clones the EFilterElement @fe.
340  *
341  * Return value:
342  **/
343 EFilterElement *
e_filter_element_clone(EFilterElement * element)344 e_filter_element_clone (EFilterElement *element)
345 {
346 	EFilterElementClass *class;
347 
348 	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element), NULL);
349 
350 	class = E_FILTER_ELEMENT_GET_CLASS (element);
351 	g_return_val_if_fail (class != NULL, NULL);
352 	g_return_val_if_fail (class->clone != NULL, NULL);
353 
354 	return class->clone (element);
355 }
356 
357 /**
358  * e_filter_element_get_widget:
359  * @fe: filter element
360  *
361  * Create a widget to represent this element.
362  *
363  * Returns: (transfer full): a new GtkWidget
364  **/
365 GtkWidget *
e_filter_element_get_widget(EFilterElement * element)366 e_filter_element_get_widget (EFilterElement *element)
367 {
368 	EFilterElementClass *class;
369 
370 	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element), NULL);
371 
372 	class = E_FILTER_ELEMENT_GET_CLASS (element);
373 	g_return_val_if_fail (class != NULL, NULL);
374 	g_return_val_if_fail (class->get_widget != NULL, NULL);
375 
376 	return class->get_widget (element);
377 }
378 
379 /**
380  * filter_element_build_code:
381  * @fe: filter element
382  * @out: output buffer
383  * @ff:
384  *
385  * Add the code representing this element to the output string @out.
386  **/
387 void
e_filter_element_build_code(EFilterElement * element,GString * out,EFilterPart * part)388 e_filter_element_build_code (EFilterElement *element,
389                              GString *out,
390                              EFilterPart *part)
391 {
392 	EFilterElementClass *class;
393 
394 	g_return_if_fail (E_IS_FILTER_ELEMENT (element));
395 	g_return_if_fail (out != NULL);
396 	g_return_if_fail (E_IS_FILTER_PART (part));
397 
398 	class = E_FILTER_ELEMENT_GET_CLASS (element);
399 	g_return_if_fail (class != NULL);
400 
401 	/* This method is optional. */
402 	if (class->build_code != NULL)
403 		class->build_code (element, out, part);
404 }
405 
406 /**
407  * filter_element_format_sexp:
408  * @fe: filter element
409  * @out: output buffer
410  *
411  * Format the value(s) of this element in a method suitable for the context of
412  * sexp where it is used.  Usually as space separated, double-quoted strings.
413  **/
414 void
e_filter_element_format_sexp(EFilterElement * element,GString * out)415 e_filter_element_format_sexp (EFilterElement *element,
416                               GString *out)
417 {
418 	EFilterElementClass *class;
419 
420 	g_return_if_fail (E_IS_FILTER_ELEMENT (element));
421 	g_return_if_fail (out != NULL);
422 
423 	class = E_FILTER_ELEMENT_GET_CLASS (element);
424 	g_return_if_fail (class != NULL);
425 	g_return_if_fail (class->format_sexp != NULL);
426 
427 	class->format_sexp (element, out);
428 }
429 
430 void
e_filter_element_set_data(EFilterElement * element,gpointer data)431 e_filter_element_set_data (EFilterElement *element,
432                            gpointer data)
433 {
434 	g_return_if_fail (E_IS_FILTER_ELEMENT (element));
435 
436 	element->data = data;
437 }
438 
439 /* only copies the value, not the name/type */
440 void
e_filter_element_copy_value(EFilterElement * dst_element,EFilterElement * src_element)441 e_filter_element_copy_value (EFilterElement *dst_element,
442                              EFilterElement *src_element)
443 {
444 	EFilterElementClass *class;
445 
446 	g_return_if_fail (E_IS_FILTER_ELEMENT (dst_element));
447 	g_return_if_fail (E_IS_FILTER_ELEMENT (src_element));
448 
449 	class = E_FILTER_ELEMENT_GET_CLASS (dst_element);
450 	g_return_if_fail (class != NULL);
451 	g_return_if_fail (class->copy_value != NULL);
452 
453 	class->copy_value (dst_element, src_element);
454 }
455 
456 /**
457  * e_filter_element_describe:
458  * @fe: filter element
459  * @out: a #GString to add the description to
460  *
461  * Describes the @element in a human-readable way.
462  **/
463 void
e_filter_element_describe(EFilterElement * element,GString * out)464 e_filter_element_describe (EFilterElement *element,
465 			   GString *out)
466 {
467 	EFilterElementClass *klass;
468 
469 	g_return_if_fail (E_IS_FILTER_ELEMENT (element));
470 	g_return_if_fail (out != NULL);
471 
472 	klass = E_FILTER_ELEMENT_GET_CLASS (element);
473 	g_return_if_fail (klass != NULL);
474 	g_return_if_fail (klass->describe != NULL);
475 
476 	klass->describe (element, out);
477 }
478