diff options
Diffstat (limited to 'e-util/e-filter-part.c')
-rw-r--r-- | e-util/e-filter-part.c | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/e-util/e-filter-part.c b/e-util/e-filter-part.c new file mode 100644 index 0000000000..c9e14e30c6 --- /dev/null +++ b/e-util/e-filter-part.c @@ -0,0 +1,513 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * Not Zed <notzed@lostzed.mmc.com.au> + * Jepartrey Stedfast <fejj@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> + +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +#include "e-filter-file.h" +#include "e-filter-part.h" +#include "e-rule-context.h" + +G_DEFINE_TYPE ( + EFilterPart, + e_filter_part, + G_TYPE_OBJECT) + +static void +filter_part_finalize (GObject *object) +{ + EFilterPart *part = E_FILTER_PART (object); + + g_list_foreach (part->elements, (GFunc) g_object_unref, NULL); + g_list_free (part->elements); + + g_free (part->name); + g_free (part->title); + g_free (part->code); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_filter_part_parent_class)->finalize (object); +} + +static void +e_filter_part_class_init (EFilterPartClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = filter_part_finalize; +} + +static void +e_filter_part_init (EFilterPart *part) +{ +} + +/** + * e_filter_part_new: + * + * Create a new EFilterPart object. + * + * Return value: A new #EFilterPart object. + **/ +EFilterPart * +e_filter_part_new (void) +{ + return g_object_new (E_TYPE_FILTER_PART, NULL); +} + +gboolean +e_filter_part_validate (EFilterPart *part, + EAlert **alert) +{ + GList *link; + + g_return_val_if_fail (E_IS_FILTER_PART (part), FALSE); + + /* The part is valid if all of its elements are valid. */ + for (link = part->elements; link != NULL; link = g_list_next (link)) { + EFilterElement *element = link->data; + + if (!e_filter_element_validate (element, alert)) + return FALSE; + } + + return TRUE; +} + +gint +e_filter_part_eq (EFilterPart *part_a, + EFilterPart *part_b) +{ + GList *link_a, *link_b; + + g_return_val_if_fail (E_IS_FILTER_PART (part_a), FALSE); + g_return_val_if_fail (E_IS_FILTER_PART (part_b), FALSE); + + if (g_strcmp0 (part_a->name, part_b->name) != 0) + return FALSE; + + if (g_strcmp0 (part_a->title, part_b->title) != 0) + return FALSE; + + if (g_strcmp0 (part_a->code, part_b->code) != 0) + return FALSE; + + link_a = part_a->elements; + link_b = part_b->elements; + + while (link_a != NULL && link_b != NULL) { + EFilterElement *element_a = link_a->data; + EFilterElement *element_b = link_b->data; + + if (!e_filter_element_eq (element_a, element_b)) + return FALSE; + + link_a = g_list_next (link_a); + link_b = g_list_next (link_b); + } + + if (link_a != NULL || link_b != NULL) + return FALSE; + + return TRUE; +} + +gint +e_filter_part_xml_create (EFilterPart *part, + xmlNodePtr node, + ERuleContext *context) +{ + xmlNodePtr n; + gchar *type, *str; + EFilterElement *el; + + g_return_val_if_fail (E_IS_FILTER_PART (part), FALSE); + g_return_val_if_fail (node != NULL, FALSE); + g_return_val_if_fail (E_IS_RULE_CONTEXT (context), FALSE); + + str = (gchar *) xmlGetProp (node, (xmlChar *)"name"); + part->name = g_strdup (str); + if (str) + xmlFree (str); + + n = node->children; + while (n) { + if (!strcmp ((gchar *) n->name, "input")) { + type = (gchar *) xmlGetProp (n, (xmlChar *)"type"); + if (type != NULL + && (el = e_rule_context_new_element (context, type)) != NULL) { + e_filter_element_xml_create (el, n); + xmlFree (type); + part->elements = g_list_append (part->elements, el); + } else { + g_warning ("Invalid xml format, missing/unknown input type"); + } + } else if (!strcmp ((gchar *) n->name, "title") || + !strcmp ((gchar *) n->name, "_title")) { + if (!part->title) { + str = (gchar *) xmlNodeGetContent (n); + part->title = g_strdup (str); + if (str) + xmlFree (str); + } + } else if (!strcmp ((gchar *) n->name, "code")) { + if (!part->code) { + str = (gchar *) xmlNodeGetContent (n); + part->code = g_strdup (str); + if (str) + xmlFree (str); + } + } else if (n->type == XML_ELEMENT_NODE) { + g_warning ("Unknown part element in xml: %s\n", n->name); + } + n = n->next; + } + + return 0; +} + +xmlNodePtr +e_filter_part_xml_encode (EFilterPart *part) +{ + xmlNodePtr node; + GList *link; + + g_return_val_if_fail (E_IS_FILTER_PART (part), NULL); + + node = xmlNewNode (NULL, (xmlChar *)"part"); + xmlSetProp (node, (xmlChar *)"name", (xmlChar *) part->name); + + for (link = part->elements; link != NULL; link = g_list_next (link)) { + EFilterElement *element = link->data; + xmlNodePtr value; + + value = e_filter_element_xml_encode (element); + xmlAddChild (node, value); + } + + return node; +} + +gint +e_filter_part_xml_decode (EFilterPart *part, + xmlNodePtr node) +{ + xmlNodePtr child; + + g_return_val_if_fail (E_IS_FILTER_PART (part), -1); + g_return_val_if_fail (node != NULL, -1); + + for (child = node->children; child != NULL; child = child->next) { + EFilterElement *element; + xmlChar *name; + + if (strcmp ((gchar *) child->name, "value") != 0) + continue; + + name = xmlGetProp (child, (xmlChar *) "name"); + element = e_filter_part_find_element (part, (gchar *) name); + xmlFree (name); + + if (element != NULL) + e_filter_element_xml_decode (element, child); + } + + return 0; +} + +EFilterPart * +e_filter_part_clone (EFilterPart *part) +{ + EFilterPart *clone; + GList *link; + + g_return_val_if_fail (E_IS_FILTER_PART (part), NULL); + + clone = g_object_new (G_OBJECT_TYPE (part), NULL, NULL); + clone->name = g_strdup (part->name); + clone->title = g_strdup (part->title); + clone->code = g_strdup (part->code); + + for (link = part->elements; link != NULL; link = g_list_next (link)) { + EFilterElement *element = link->data; + EFilterElement *clone_element; + + clone_element = e_filter_element_clone (element); + clone->elements = g_list_append (clone->elements, clone_element); + } + + return clone; +} + +/* only copies values of matching parts in the right order */ +void +e_filter_part_copy_values (EFilterPart *dst_part, + EFilterPart *src_part) +{ + GList *dst_link, *src_link; + + g_return_if_fail (E_IS_FILTER_PART (dst_part)); + g_return_if_fail (E_IS_FILTER_PART (src_part)); + + /* NOTE: we go backwards, it just works better that way */ + + /* for each source type, search the dest type for + * a matching type in the same order */ + src_link = g_list_last (src_part->elements); + dst_link = g_list_last (dst_part->elements); + + while (src_link != NULL && dst_link != NULL) { + EFilterElement *src_element = src_link->data; + GList *link = dst_link; + + while (link != NULL) { + EFilterElement *dst_element = link->data; + GType dst_type = G_OBJECT_TYPE (dst_element); + GType src_type = G_OBJECT_TYPE (src_element); + + if (dst_type == src_type) { + e_filter_element_copy_value ( + dst_element, src_element); + dst_link = g_list_previous (link); + break; + } + + link = g_list_previous (link); + } + + src_link = g_list_previous (src_link); + } +} + +EFilterElement * +e_filter_part_find_element (EFilterPart *part, + const gchar *name) +{ + GList *link; + + g_return_val_if_fail (E_IS_FILTER_PART (part), NULL); + + if (name == NULL) + return NULL; + + for (link = part->elements; link != NULL; link = g_list_next (link)) { + EFilterElement *element = link->data; + + if (g_strcmp0 (element->name, name) == 0) + return element; + } + + return NULL; +} + +GtkWidget * +e_filter_part_get_widget (EFilterPart *part) +{ + GtkWidget *hbox; + GList *link; + + g_return_val_if_fail (E_IS_FILTER_PART (part), NULL); + + hbox = gtk_hbox_new (FALSE, 3); + + for (link = part->elements; link != NULL; link = g_list_next (link)) { + EFilterElement *element = link->data; + GtkWidget *widget; + + widget = e_filter_element_get_widget (element); + if (widget != NULL) + gtk_box_pack_start ( + GTK_BOX (hbox), widget, + E_IS_FILTER_FILE (element), + E_IS_FILTER_FILE (element), 3); + } + + gtk_widget_show_all (hbox); + + return hbox; +} + +/** + * e_filter_part_build_code: + * @part: + * @out: + * + * Outputs the code of a part. + **/ +void +e_filter_part_build_code (EFilterPart *part, + GString *out) +{ + GList *link; + + g_return_if_fail (E_IS_FILTER_PART (part)); + g_return_if_fail (out != NULL); + + if (part->code != NULL) + e_filter_part_expand_code (part, part->code, out); + + for (link = part->elements; link != NULL; link = g_list_next (link)) { + EFilterElement *element = link->data; + e_filter_element_build_code (element, out, part); + } +} + +/** + * e_filter_part_build_code_list: + * @l: + * @out: + * + * Construct a list of the filter parts code into + * a single string. + **/ +void +e_filter_part_build_code_list (GList *list, + GString *out) +{ + GList *link; + + g_return_if_fail (out != NULL); + + for (link = list; link != NULL; link = g_list_next (link)) { + EFilterPart *part = link->data; + + e_filter_part_build_code (part, out); + g_string_append (out, "\n "); + } +} + +/** + * e_filter_part_find_list: + * @l: + * @name: + * + * Find a filter part stored in a list. + * + * Return value: + **/ +EFilterPart * +e_filter_part_find_list (GList *list, + const gchar *name) +{ + GList *link; + + g_return_val_if_fail (name != NULL, NULL); + + for (link = list; link != NULL; link = g_list_next (link)) { + EFilterPart *part = link->data; + + if (g_strcmp0 (part->name, name) == 0) + return part; + } + + return NULL; +} + +/** + * e_filter_part_next_list: + * @l: + * @last: The last item retrieved, or NULL to start + * from the beginning of the list. + * + * Iterate through a filter part list. + * + * Return value: The next value in the list, or NULL if the + * list is expired. + **/ +EFilterPart * +e_filter_part_next_list (GList *list, + EFilterPart *last) +{ + GList *link = list; + + if (last != NULL) { + link = g_list_find (list, last); + if (link == NULL) + link = list; + else + link = link->next; + } + + return (link != NULL) ? link->data : NULL; +} + +/** + * e_filter_part_expand_code: + * @part: + * @str: + * @out: + * + * Expands the variables in string @str based on the values of the part. + **/ +void +e_filter_part_expand_code (EFilterPart *part, + const gchar *source, + GString *out) +{ + const gchar *newstart, *start, *end; + gchar *name = g_alloca (32); + gint len, namelen = 32; + + g_return_if_fail (E_IS_FILTER_PART (part)); + g_return_if_fail (source != NULL); + g_return_if_fail (out != NULL); + + start = source; + + while (start && (newstart = strstr (start, "${")) + && (end = strstr (newstart + 2, "}"))) { + EFilterElement *element; + + len = end - newstart - 2; + if (len + 1 > namelen) { + namelen = (len + 1) * 2; + name = g_alloca (namelen); + } + memcpy (name, newstart + 2, len); + name[len] = 0; + + element = e_filter_part_find_element (part, name); + if (element != NULL) { + g_string_append_printf (out, "%.*s", (gint)(newstart - start), start); + e_filter_element_format_sexp (element, out); +#if 0 + } else if ((val = g_hash_table_lookup (part->globals, name))) { + g_string_append_printf (out, "%.*s", newstart - start, start); + camel_sexp_encode_string (out, val); +#endif + } else { + g_string_append_printf (out, "%.*s", (gint)(end - start + 1), start); + } + start = end + 1; + } + + g_string_append (out, start); +} |