Updated Traditional Chinese translation(Hong Kong and Taiwan)
[evolution.git] / filter / e-filter-part.c
blob2b75b3023540c0dfe01f45732c9cc757f2b2facb
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 * Authors:
17 * Not Zed <notzed@lostzed.mmc.com.au>
18 * Jepartrey Stedfast <fejj@ximian.com>
20 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 #include <stdlib.h>
29 #include <string.h>
31 #include <gtk/gtk.h>
32 #include <glib/gi18n.h>
34 #include "e-filter-file.h"
35 #include "e-filter-part.h"
36 #include "e-rule-context.h"
38 G_DEFINE_TYPE (
39 EFilterPart,
40 e_filter_part,
41 G_TYPE_OBJECT)
43 static void
44 filter_part_finalize (GObject *object)
46 EFilterPart *part = E_FILTER_PART (object);
48 g_list_foreach (part->elements, (GFunc) g_object_unref, NULL);
49 g_list_free (part->elements);
51 g_free (part->name);
52 g_free (part->title);
53 g_free (part->code);
55 /* Chain up to parent's finalize() method. */
56 G_OBJECT_CLASS (e_filter_part_parent_class)->finalize (object);
59 static void
60 e_filter_part_class_init (EFilterPartClass *class)
62 GObjectClass *object_class;
64 object_class = G_OBJECT_CLASS (class);
65 object_class->finalize = filter_part_finalize;
68 static void
69 e_filter_part_init (EFilterPart *part)
73 /**
74 * e_filter_part_new:
76 * Create a new EFilterPart object.
78 * Return value: A new #EFilterPart object.
79 **/
80 EFilterPart *
81 e_filter_part_new (void)
83 return g_object_new (E_TYPE_FILTER_PART, NULL);
86 gboolean
87 e_filter_part_validate (EFilterPart *part,
88 EAlert **alert)
90 GList *link;
92 g_return_val_if_fail (E_IS_FILTER_PART (part), FALSE);
94 /* The part is valid if all of its elements are valid. */
95 for (link = part->elements; link != NULL; link = g_list_next (link)) {
96 EFilterElement *element = link->data;
98 if (!e_filter_element_validate (element, alert))
99 return FALSE;
102 return TRUE;
105 gint
106 e_filter_part_eq (EFilterPart *part_a,
107 EFilterPart *part_b)
109 GList *link_a, *link_b;
111 g_return_val_if_fail (E_IS_FILTER_PART (part_a), FALSE);
112 g_return_val_if_fail (E_IS_FILTER_PART (part_b), FALSE);
114 if (g_strcmp0 (part_a->name, part_b->name) != 0)
115 return FALSE;
117 if (g_strcmp0 (part_a->title, part_b->title) != 0)
118 return FALSE;
120 if (g_strcmp0 (part_a->code, part_b->code) != 0)
121 return FALSE;
123 link_a = part_a->elements;
124 link_b = part_b->elements;
126 while (link_a != NULL && link_b != NULL) {
127 EFilterElement *element_a = link_a->data;
128 EFilterElement *element_b = link_b->data;
130 if (!e_filter_element_eq (element_a, element_b))
131 return FALSE;
133 link_a = g_list_next (link_a);
134 link_b = g_list_next (link_b);
137 if (link_a != NULL || link_b != NULL)
138 return FALSE;
140 return TRUE;
143 gint
144 e_filter_part_xml_create (EFilterPart *part,
145 xmlNodePtr node,
146 ERuleContext *context)
148 xmlNodePtr n;
149 gchar *type, *str;
150 EFilterElement *el;
152 g_return_val_if_fail (E_IS_FILTER_PART (part), FALSE);
153 g_return_val_if_fail (node != NULL, FALSE);
154 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), FALSE);
156 str = (gchar *)xmlGetProp (node, (xmlChar *)"name");
157 part->name = g_strdup (str);
158 if (str)
159 xmlFree (str);
161 n = node->children;
162 while (n) {
163 if (!strcmp ((gchar *)n->name, "input")) {
164 type = (gchar *)xmlGetProp (n, (xmlChar *)"type");
165 if (type != NULL
166 && (el = e_rule_context_new_element (context, type)) != NULL) {
167 e_filter_element_xml_create (el, n);
168 xmlFree (type);
169 part->elements = g_list_append (part->elements, el);
170 } else {
171 g_warning ("Invalid xml format, missing/unknown input type");
173 } else if (!strcmp ((gchar *)n->name, "title") ||
174 !strcmp ((gchar *)n->name, "_title")) {
175 if (!part->title) {
176 str = (gchar *)xmlNodeGetContent (n);
177 part->title = g_strdup (str);
178 if (str)
179 xmlFree (str);
181 } else if (!strcmp ((gchar *)n->name, "code")) {
182 if (!part->code) {
183 str = (gchar *)xmlNodeGetContent (n);
184 part->code = g_strdup (str);
185 if (str)
186 xmlFree (str);
188 } else if (n->type == XML_ELEMENT_NODE) {
189 g_warning ("Unknown part element in xml: %s\n", n->name);
191 n = n->next;
194 return 0;
197 xmlNodePtr
198 e_filter_part_xml_encode (EFilterPart *part)
200 xmlNodePtr node;
201 GList *link;
203 g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
205 node = xmlNewNode (NULL, (xmlChar *)"part");
206 xmlSetProp (node, (xmlChar *)"name", (xmlChar *)part->name);
208 for (link = part->elements; link != NULL; link = g_list_next (link)) {
209 EFilterElement *element = link->data;
210 xmlNodePtr value;
212 value = e_filter_element_xml_encode (element);
213 xmlAddChild (node, value);
216 return node;
219 gint
220 e_filter_part_xml_decode (EFilterPart *part,
221 xmlNodePtr node)
223 xmlNodePtr child;
225 g_return_val_if_fail (E_IS_FILTER_PART (part), -1);
226 g_return_val_if_fail (node != NULL, -1);
228 for (child = node->children; child != NULL; child = child->next) {
229 EFilterElement *element;
230 xmlChar *name;
232 if (strcmp ((gchar *) child->name, "value") != 0)
233 continue;
235 name = xmlGetProp (child, (xmlChar *) "name");
236 element = e_filter_part_find_element (part, (gchar *) name);
237 xmlFree (name);
239 if (element != NULL)
240 e_filter_element_xml_decode (element, child);
243 return 0;
246 EFilterPart *
247 e_filter_part_clone (EFilterPart *part)
249 EFilterPart *clone;
250 GList *link;
252 g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
254 clone = g_object_new (G_OBJECT_TYPE (part), NULL, NULL);
255 clone->name = g_strdup (part->name);
256 clone->title = g_strdup (part->title);
257 clone->code = g_strdup (part->code);
259 for (link = part->elements; link != NULL; link = g_list_next (link)) {
260 EFilterElement *element = link->data;
261 EFilterElement *clone_element;
263 clone_element = e_filter_element_clone (element);
264 clone->elements = g_list_append (clone->elements, clone_element);
267 return clone;
270 /* only copies values of matching parts in the right order */
271 void
272 e_filter_part_copy_values (EFilterPart *dst_part,
273 EFilterPart *src_part)
275 GList *dst_link, *src_link;
277 g_return_if_fail (E_IS_FILTER_PART (dst_part));
278 g_return_if_fail (E_IS_FILTER_PART (src_part));
280 /* NOTE: we go backwards, it just works better that way */
282 /* for each source type, search the dest type for
283 a matching type in the same order */
284 src_link = g_list_last (src_part->elements);
285 dst_link = g_list_last (dst_part->elements);
287 while (src_link != NULL && dst_link != NULL) {
288 EFilterElement *src_element = src_link->data;
289 GList *link = dst_link;
291 while (link != NULL) {
292 EFilterElement *dst_element = link->data;
293 GType dst_type = G_OBJECT_TYPE (dst_element);
294 GType src_type = G_OBJECT_TYPE (src_element);
296 if (dst_type == src_type) {
297 e_filter_element_copy_value (
298 dst_element, src_element);
299 dst_link = g_list_previous (link);
300 break;
303 link = g_list_previous (link);
306 src_link = g_list_previous (src_link);
310 EFilterElement *
311 e_filter_part_find_element (EFilterPart *part,
312 const gchar *name)
314 GList *link;
316 g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
318 if (name == NULL)
319 return NULL;
321 for (link = part->elements; link != NULL; link = g_list_next (link)) {
322 EFilterElement *element = link->data;
324 if (g_strcmp0 (element->name, name) == 0)
325 return element;
328 return NULL;
331 GtkWidget *
332 e_filter_part_get_widget (EFilterPart *part)
334 GtkWidget *hbox;
335 GList *link;
337 g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
339 hbox = gtk_hbox_new (FALSE, 3);
341 for (link = part->elements; link != NULL; link = g_list_next (link)) {
342 EFilterElement *element = link->data;
343 GtkWidget *widget;
345 widget = e_filter_element_get_widget (element);
346 if (widget != NULL)
347 gtk_box_pack_start (
348 GTK_BOX (hbox), widget,
349 E_IS_FILTER_FILE (element),
350 E_IS_FILTER_FILE (element), 3);
353 gtk_widget_show_all (hbox);
355 return hbox;
359 * e_filter_part_build_code:
360 * @part:
361 * @out:
363 * Outputs the code of a part.
365 void
366 e_filter_part_build_code (EFilterPart *part,
367 GString *out)
369 GList *link;
371 g_return_if_fail (E_IS_FILTER_PART (part));
372 g_return_if_fail (out != NULL);
374 if (part->code != NULL)
375 e_filter_part_expand_code (part, part->code, out);
377 for (link = part->elements; link != NULL; link = g_list_next (link)) {
378 EFilterElement *element = link->data;
379 e_filter_element_build_code (element, out, part);
384 * e_filter_part_build_code_list:
385 * @l:
386 * @out:
388 * Construct a list of the filter parts code into
389 * a single string.
391 void
392 e_filter_part_build_code_list (GList *list,
393 GString *out)
395 GList *link;
397 g_return_if_fail (out != NULL);
399 for (link = list; link != NULL; link = g_list_next (link)) {
400 EFilterPart *part = link->data;
402 e_filter_part_build_code (part, out);
403 g_string_append (out, "\n ");
408 * e_filter_part_find_list:
409 * @l:
410 * @name:
412 * Find a filter part stored in a list.
414 * Return value:
416 EFilterPart *
417 e_filter_part_find_list (GList *list,
418 const gchar *name)
420 GList *link;
422 g_return_val_if_fail (name != NULL, NULL);
424 for (link = list; link != NULL; link = g_list_next (link)) {
425 EFilterPart *part = link->data;
427 if (g_strcmp0 (part->name, name) == 0)
428 return part;
431 return NULL;
435 * e_filter_part_next_list:
436 * @l:
437 * @last: The last item retrieved, or NULL to start
438 * from the beginning of the list.
440 * Iterate through a filter part list.
442 * Return value: The next value in the list, or NULL if the
443 * list is expired.
445 EFilterPart *
446 e_filter_part_next_list (GList *list,
447 EFilterPart *last)
449 GList *link = list;
451 if (last != NULL) {
452 link = g_list_find (list, last);
453 if (link == NULL)
454 link = list;
455 else
456 link = link->next;
459 return (link != NULL) ? link->data : NULL;
463 * e_filter_part_expand_code:
464 * @part:
465 * @str:
466 * @out:
468 * Expands the variables in string @str based on the values of the part.
470 void
471 e_filter_part_expand_code (EFilterPart *part,
472 const gchar *source,
473 GString *out)
475 const gchar *newstart, *start, *end;
476 gchar *name = g_alloca (32);
477 gint len, namelen = 32;
479 g_return_if_fail (E_IS_FILTER_PART (part));
480 g_return_if_fail (source != NULL);
481 g_return_if_fail (out != NULL);
483 start = source;
485 while (start && (newstart = strstr (start, "${"))
486 && (end = strstr (newstart+2, "}")) ) {
487 EFilterElement *element;
489 len = end - newstart - 2;
490 if (len + 1 > namelen) {
491 namelen = (len + 1) * 2;
492 name = g_alloca (namelen);
494 memcpy (name, newstart+2, len);
495 name[len] = 0;
497 element = e_filter_part_find_element (part, name);
498 if (element != NULL) {
499 g_string_append_printf (out, "%.*s", (gint)(newstart-start), start);
500 e_filter_element_format_sexp (element, out);
501 #if 0
502 } else if ((val = g_hash_table_lookup (part->globals, name))) {
503 g_string_append_printf (out, "%.*s", newstart-start, start);
504 e_sexp_encode_string (out, val);
505 #endif
506 } else {
507 g_string_append_printf (out, "%.*s", (gint)(end-start+1), start);
509 start = end + 1;
512 g_string_append (out, start);