Updated Traditional Chinese translation(Hong Kong and Taiwan)
[evolution.git] / filter / e-rule-context.c
blob95629be7382e0db09f1b52d59a02f091563e49a3
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with the program; if not, see <http://www.gnu.org/licenses/>
17 * Authors:
18 * Not Zed <notzed@lostzed.mmc.com.au>
19 * Jeffrey Stedfast <fejj@ximian.com>
21 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
25 #include <config.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <errno.h>
34 #include <glib.h>
35 #include <glib/gstdio.h>
37 #include <gtk/gtk.h>
39 #include <glib/gi18n.h>
41 #include <libedataserver/e-xml-utils.h>
43 #include "e-util/e-alert-dialog.h"
44 #include "e-util/e-xml-utils.h"
46 #include "e-filter-code.h"
47 #include "e-filter-color.h"
48 #include "e-filter-datespec.h"
49 #include "e-filter-file.h"
50 #include "e-filter-input.h"
51 #include "e-filter-int.h"
52 #include "e-filter-option.h"
53 #include "e-filter-rule.h"
54 #include "e-rule-context.h"
56 #define E_RULE_CONTEXT_GET_PRIVATE(obj) \
57 (G_TYPE_INSTANCE_GET_PRIVATE \
58 ((obj), E_TYPE_RULE_CONTEXT, ERuleContextPrivate))
60 struct _ERuleContextPrivate {
61 gint frozen;
64 enum {
65 RULE_ADDED,
66 RULE_REMOVED,
67 CHANGED,
68 LAST_SIGNAL
71 static guint signals[LAST_SIGNAL];
73 struct _revert_data {
74 GHashTable *rules;
75 gint rank;
78 G_DEFINE_TYPE (
79 ERuleContext,
80 e_rule_context,
81 G_TYPE_OBJECT)
83 static void
84 rule_context_set_error (ERuleContext *context,
85 gchar *error)
87 g_free (context->error);
88 context->error = error;
91 static void
92 new_rule_response (GtkWidget *dialog,
93 gint button,
94 ERuleContext *context)
96 if (button == GTK_RESPONSE_OK) {
97 EFilterRule *rule = g_object_get_data ((GObject *) dialog, "rule");
98 gchar *user = g_object_get_data ((GObject *) dialog, "path");
99 EAlert *alert = NULL;
101 if (!e_filter_rule_validate (rule, &alert)) {
102 e_alert_run_dialog (GTK_WINDOW (dialog), alert);
103 g_object_unref (alert);
104 return;
107 if (e_rule_context_find_rule (context, rule->name, rule->source)) {
108 e_alert_run_dialog_for_args ((GtkWindow *)dialog,
109 "filter:bad-name-notunique",
110 rule->name, NULL);
112 return;
115 g_object_ref (rule);
116 e_rule_context_add_rule (context, rule);
117 if (user)
118 e_rule_context_save (context, user);
121 gtk_widget_destroy (dialog);
124 static void
125 revert_rule_remove (gpointer key,
126 EFilterRule *rule,
127 ERuleContext *context)
129 e_rule_context_remove_rule (context, rule);
130 g_object_unref (rule);
133 static void
134 revert_source_remove (gpointer key,
135 struct _revert_data *rest_data,
136 ERuleContext *context)
138 g_hash_table_foreach (
139 rest_data->rules, (GHFunc) revert_rule_remove, context);
140 g_hash_table_destroy (rest_data->rules);
141 g_free (rest_data);
144 static guint
145 source_hashf (const gchar *a)
147 return (a != NULL) ? g_str_hash (a) : 0;
150 static gint
151 source_eqf (const gchar *a,
152 const gchar *b)
154 return (g_strcmp0 (a, b) == 0);
157 static void
158 free_part_set (struct _part_set_map *map)
160 g_free (map->name);
161 g_free (map);
164 static void
165 free_rule_set (struct _rule_set_map *map)
167 g_free (map->name);
168 g_free (map);
171 static void
172 rule_context_finalize (GObject *obj)
174 ERuleContext *context =(ERuleContext *) obj;
176 g_list_foreach (context->rule_set_list, (GFunc)free_rule_set, NULL);
177 g_list_free (context->rule_set_list);
178 g_hash_table_destroy (context->rule_set_map);
180 g_list_foreach (context->part_set_list, (GFunc)free_part_set, NULL);
181 g_list_free (context->part_set_list);
182 g_hash_table_destroy (context->part_set_map);
184 g_free (context->error);
186 g_list_foreach (context->parts, (GFunc)g_object_unref, NULL);
187 g_list_free (context->parts);
189 g_list_foreach (context->rules, (GFunc)g_object_unref, NULL);
190 g_list_free (context->rules);
192 G_OBJECT_CLASS (e_rule_context_parent_class)->finalize (obj);
195 static gint
196 rule_context_load (ERuleContext *context,
197 const gchar *system,
198 const gchar *user)
200 xmlNodePtr set, rule, root;
201 xmlDocPtr systemdoc, userdoc;
202 struct _part_set_map *part_map;
203 struct _rule_set_map *rule_map;
205 rule_context_set_error (context, NULL);
207 systemdoc = e_xml_parse_file (system);
208 if (systemdoc == NULL) {
209 gchar * err_msg;
211 err_msg = g_strdup_printf (
212 "Unable to load system rules '%s': %s",
213 system, g_strerror (errno));
214 g_warning ("%s: %s", G_STRFUNC, err_msg);
215 rule_context_set_error (context, err_msg);
216 /* no need to free err_msg here */
217 return -1;
220 root = xmlDocGetRootElement (systemdoc);
221 if (root == NULL || strcmp ((gchar *)root->name, "filterdescription")) {
222 gchar * err_msg;
224 err_msg = g_strdup_printf (
225 "Unable to load system rules '%s': "
226 "Invalid format", system);
227 g_warning ("%s: %s", G_STRFUNC, err_msg);
228 rule_context_set_error (context, err_msg);
229 /* no need to free err_msg here */
230 xmlFreeDoc (systemdoc);
231 return -1;
233 /* doesn't matter if this doens't exist */
234 userdoc = NULL;
235 if (g_file_test (user, G_FILE_TEST_IS_REGULAR))
236 userdoc = e_xml_parse_file (user);
238 /* now parse structure */
239 /* get rule parts */
240 set = root->children;
241 while (set) {
242 part_map = g_hash_table_lookup (context->part_set_map, set->name);
243 if (part_map) {
244 rule = set->children;
245 while (rule) {
246 if (!strcmp ((gchar *)rule->name, "part")) {
247 EFilterPart *part = E_FILTER_PART (g_object_new (part_map->type, NULL, NULL));
249 if (e_filter_part_xml_create (part, rule, context) == 0) {
250 part_map->append (context, part);
251 } else {
252 g_object_unref (part);
253 g_warning ("Cannot load filter part");
256 rule = rule->next;
258 } else if ((rule_map = g_hash_table_lookup (context->rule_set_map, set->name))) {
259 rule = set->children;
260 while (rule) {
261 if (!strcmp ((gchar *)rule->name, "rule")) {
262 EFilterRule *part = E_FILTER_RULE (g_object_new (rule_map->type, NULL, NULL));
264 if (e_filter_rule_xml_decode (part, rule, context) == 0) {
265 part->system = TRUE;
266 rule_map->append (context, part);
267 } else {
268 g_object_unref (part);
269 g_warning ("Cannot load filter part");
272 rule = rule->next;
275 set = set->next;
278 /* now load actual rules */
279 if (userdoc) {
280 root = xmlDocGetRootElement (userdoc);
281 set = root?root->children:NULL;
282 while (set) {
283 rule_map = g_hash_table_lookup (context->rule_set_map, set->name);
284 if (rule_map) {
285 rule = set->children;
286 while (rule) {
287 if (!strcmp ((gchar *)rule->name, "rule")) {
288 EFilterRule *part = E_FILTER_RULE (g_object_new (rule_map->type, NULL, NULL));
290 if (e_filter_rule_xml_decode (part, rule, context) == 0) {
291 rule_map->append (context, part);
292 } else {
293 g_object_unref (part);
294 g_warning ("Cannot load filter part");
297 rule = rule->next;
300 set = set->next;
304 xmlFreeDoc (userdoc);
305 xmlFreeDoc (systemdoc);
307 return 0;
310 static gint
311 rule_context_save (ERuleContext *context,
312 const gchar *user)
314 xmlDocPtr doc;
315 xmlNodePtr root, rules, work;
316 GList *l;
317 EFilterRule *rule;
318 struct _rule_set_map *map;
319 gint ret;
321 doc = xmlNewDoc ((xmlChar *)"1.0");
322 /* FIXME: set character encoding to UTF-8? */
323 root = xmlNewDocNode (doc, NULL, (xmlChar *)"filteroptions", NULL);
324 xmlDocSetRootElement (doc, root);
325 l = context->rule_set_list;
326 while (l) {
327 map = l->data;
328 rules = xmlNewDocNode (doc, NULL, (xmlChar *)map->name, NULL);
329 xmlAddChild (root, rules);
330 rule = NULL;
331 while ((rule = map->next (context, rule, NULL))) {
332 if (!rule->system) {
333 work = e_filter_rule_xml_encode (rule);
334 xmlAddChild (rules, work);
337 l = g_list_next (l);
340 ret = e_xml_save_file (user, doc);
342 xmlFreeDoc (doc);
344 return ret;
347 static gint
348 rule_context_revert (ERuleContext *context,
349 const gchar *user)
351 xmlNodePtr set, rule;
352 /*struct _part_set_map *part_map;*/
353 struct _rule_set_map *rule_map;
354 struct _revert_data *rest_data;
355 GHashTable *source_hash;
356 xmlDocPtr userdoc;
357 EFilterRule *frule;
359 rule_context_set_error (context, NULL);
361 userdoc = e_xml_parse_file (user);
362 if (userdoc == NULL)
363 /* clear out anythign we have? */
364 return 0;
366 source_hash = g_hash_table_new ((GHashFunc)source_hashf, (GCompareFunc)source_eqf);
368 /* setup stuff we have now */
369 /* Note that we assume there is only 1 set of rules in a given rule context,
370 although other parts of the code dont assume this */
371 frule = NULL;
372 while ((frule = e_rule_context_next_rule (context, frule, NULL))) {
373 rest_data = g_hash_table_lookup (source_hash, frule->source);
374 if (rest_data == NULL) {
375 rest_data = g_malloc0 (sizeof (*rest_data));
376 rest_data->rules = g_hash_table_new (g_str_hash, g_str_equal);
377 g_hash_table_insert (source_hash, frule->source, rest_data);
379 g_hash_table_insert (rest_data->rules, frule->name, frule);
382 /* make what we have, match what we load */
383 set = xmlDocGetRootElement (userdoc);
384 set = set?set->children:NULL;
385 while (set) {
386 rule_map = g_hash_table_lookup (context->rule_set_map, set->name);
387 if (rule_map) {
388 rule = set->children;
389 while (rule) {
390 if (!strcmp ((gchar *)rule->name, "rule")) {
391 EFilterRule *part = E_FILTER_RULE (g_object_new (rule_map->type, NULL, NULL));
393 if (e_filter_rule_xml_decode (part, rule, context) == 0) {
394 /* use the revert data to keep track of the right rank of this rule part */
395 rest_data = g_hash_table_lookup (source_hash, part->source);
396 if (rest_data == NULL) {
397 rest_data = g_malloc0 (sizeof (*rest_data));
398 rest_data->rules = g_hash_table_new (g_str_hash, g_str_equal);
399 g_hash_table_insert (source_hash, part->source, rest_data);
401 frule = g_hash_table_lookup (rest_data->rules, part->name);
402 if (frule) {
403 if (context->priv->frozen == 0 && !e_filter_rule_eq (frule, part))
404 e_filter_rule_copy (frule, part);
406 g_object_unref (part);
407 e_rule_context_rank_rule (context, frule, frule->source, rest_data->rank);
408 g_hash_table_remove (rest_data->rules, frule->name);
409 } else {
410 e_rule_context_add_rule (context, part);
411 e_rule_context_rank_rule (context, part, part->source, rest_data->rank);
413 rest_data->rank++;
414 } else {
415 g_object_unref (part);
416 g_warning ("Cannot load filter part");
419 rule = rule->next;
422 set = set->next;
425 xmlFreeDoc (userdoc);
427 /* remove any we still have that weren't in the file */
428 g_hash_table_foreach (source_hash, (GHFunc)revert_source_remove, context);
429 g_hash_table_destroy (source_hash);
431 return 0;
434 static EFilterElement *
435 rule_context_new_element (ERuleContext *context,
436 const gchar *type)
438 if (!strcmp (type, "string")) {
439 return (EFilterElement *) e_filter_input_new ();
440 } else if (!strcmp (type, "address")) {
441 /* FIXME: temporary ... need real address type */
442 return (EFilterElement *) e_filter_input_new_type_name (type);
443 } else if (!strcmp (type, "code")) {
444 return (EFilterElement *) e_filter_code_new (FALSE);
445 } else if (!strcmp (type, "rawcode")) {
446 return (EFilterElement *) e_filter_code_new (TRUE);
447 } else if (!strcmp (type, "colour")) {
448 return (EFilterElement *) e_filter_color_new ();
449 } else if (!strcmp (type, "optionlist")) {
450 return (EFilterElement *) e_filter_option_new ();
451 } else if (!strcmp (type, "datespec")) {
452 return (EFilterElement *) e_filter_datespec_new ();
453 } else if (!strcmp (type, "command")) {
454 return (EFilterElement *) e_filter_file_new_type_name (type);
455 } else if (!strcmp (type, "file")) {
456 return (EFilterElement *) e_filter_file_new_type_name (type);
457 } else if (!strcmp (type, "integer")) {
458 return (EFilterElement *) e_filter_int_new ();
459 } else if (!strcmp (type, "regex")) {
460 return (EFilterElement *) e_filter_input_new_type_name (type);
461 } else if (!strcmp (type, "completedpercent")) {
462 return (EFilterElement *) e_filter_int_new_type (
463 "completedpercent", 0,100);
464 } else {
465 g_warning ("Unknown filter type '%s'", type);
466 return NULL;
470 static void
471 e_rule_context_class_init (ERuleContextClass *class)
473 GObjectClass *object_class;
475 g_type_class_add_private (class, sizeof (ERuleContextPrivate));
477 object_class = G_OBJECT_CLASS (class);
478 object_class->finalize = rule_context_finalize;
480 class->load = rule_context_load;
481 class->save = rule_context_save;
482 class->revert = rule_context_revert;
483 class->new_element = rule_context_new_element;
485 signals[RULE_ADDED] = g_signal_new (
486 "rule-added",
487 E_TYPE_RULE_CONTEXT,
488 G_SIGNAL_RUN_LAST,
489 G_STRUCT_OFFSET (ERuleContextClass, rule_added),
490 NULL,
491 NULL,
492 g_cclosure_marshal_VOID__POINTER,
493 G_TYPE_NONE, 1,
494 G_TYPE_POINTER);
496 signals[RULE_REMOVED] = g_signal_new (
497 "rule-removed",
498 E_TYPE_RULE_CONTEXT,
499 G_SIGNAL_RUN_LAST,
500 G_STRUCT_OFFSET (ERuleContextClass, rule_removed),
501 NULL,
502 NULL,
503 g_cclosure_marshal_VOID__POINTER,
504 G_TYPE_NONE, 1,
505 G_TYPE_POINTER);
507 signals[CHANGED] = g_signal_new (
508 "changed",
509 E_TYPE_RULE_CONTEXT,
510 G_SIGNAL_RUN_LAST,
511 G_STRUCT_OFFSET (ERuleContextClass, changed),
512 NULL,
513 NULL,
514 g_cclosure_marshal_VOID__VOID,
515 G_TYPE_NONE, 0);
518 static void
519 e_rule_context_init (ERuleContext *context)
521 context->priv = E_RULE_CONTEXT_GET_PRIVATE (context);
523 context->part_set_map = g_hash_table_new (g_str_hash, g_str_equal);
524 context->rule_set_map = g_hash_table_new (g_str_hash, g_str_equal);
526 context->flags = E_RULE_CONTEXT_GROUPING;
530 * e_rule_context_new:
532 * Create a new ERuleContext object.
534 * Return value: A new #ERuleContext object.
536 ERuleContext *
537 e_rule_context_new (void)
539 return g_object_new (E_TYPE_RULE_CONTEXT, NULL);
542 void
543 e_rule_context_add_part_set (ERuleContext *context,
544 const gchar *setname,
545 GType part_type,
546 ERuleContextPartFunc append,
547 ERuleContextNextPartFunc next)
549 struct _part_set_map *map;
551 g_return_if_fail (E_IS_RULE_CONTEXT (context));
552 g_return_if_fail (setname != NULL);
553 g_return_if_fail (append != NULL);
554 g_return_if_fail (next != NULL);
556 g_return_if_fail (g_hash_table_lookup (context->part_set_map, setname) == NULL);
558 map = g_malloc0 (sizeof (*map));
559 map->type = part_type;
560 map->append = append;
561 map->next = next;
562 map->name = g_strdup (setname);
563 g_hash_table_insert (context->part_set_map, map->name, map);
564 context->part_set_list = g_list_append (context->part_set_list, map);
567 void
568 e_rule_context_add_rule_set (ERuleContext *context,
569 const gchar *setname,
570 GType rule_type,
571 ERuleContextRuleFunc append,
572 ERuleContextNextRuleFunc next)
574 struct _rule_set_map *map;
576 g_return_if_fail (E_IS_RULE_CONTEXT (context));
577 g_return_if_fail (setname != NULL);
578 g_return_if_fail (append != NULL);
579 g_return_if_fail (next != NULL);
581 g_return_if_fail (g_hash_table_lookup (context->rule_set_map, setname) == NULL);
583 map = g_malloc0 (sizeof (*map));
584 map->type = rule_type;
585 map->append = append;
586 map->next = next;
587 map->name = g_strdup (setname);
588 g_hash_table_insert (context->rule_set_map, map->name, map);
589 context->rule_set_list = g_list_append (context->rule_set_list, map);
593 * e_rule_context_load:
594 * @f:
595 * @system:
596 * @user:
598 * Load a rule context from a system and user description file.
600 * Return value:
602 gint
603 e_rule_context_load (ERuleContext *context,
604 const gchar *system,
605 const gchar *user)
607 ERuleContextClass *class;
608 gint result;
610 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), -1);
611 g_return_val_if_fail (system != NULL, -1);
612 g_return_val_if_fail (user != NULL, -1);
614 class = E_RULE_CONTEXT_GET_CLASS (context);
615 g_return_val_if_fail (class->load != NULL, -1);
617 context->priv->frozen++;
618 result = class->load (context, system, user);
619 context->priv->frozen--;
621 return result;
625 * e_rule_context_save:
626 * @f:
627 * @user:
629 * Save a rule context to disk.
631 * Return value:
633 gint
634 e_rule_context_save (ERuleContext *context,
635 const gchar *user)
637 ERuleContextClass *class;
639 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), -1);
640 g_return_val_if_fail (user != NULL, -1);
642 class = E_RULE_CONTEXT_GET_CLASS (context);
643 g_return_val_if_fail (class->save != NULL, -1);
645 return class->save (context, user);
649 * e_rule_context_revert:
650 * @f:
651 * @user:
653 * Reverts a rule context from a user description file. Assumes the
654 * system description file is unchanged from when it was loaded.
656 * Return value:
658 gint
659 e_rule_context_revert (ERuleContext *context,
660 const gchar *user)
662 ERuleContextClass *class;
664 g_return_val_if_fail (E_RULE_CONTEXT (context), 0);
665 g_return_val_if_fail (user != NULL, 0);
667 class = E_RULE_CONTEXT_GET_CLASS (context);
668 g_return_val_if_fail (class->revert != NULL, 0);
670 return class->revert (context, user);
673 EFilterPart *
674 e_rule_context_find_part (ERuleContext *context,
675 const gchar *name)
677 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
678 g_return_val_if_fail (name != NULL, NULL);
680 return e_filter_part_find_list (context->parts, name);
683 EFilterPart *
684 e_rule_context_create_part (ERuleContext *context,
685 const gchar *name)
687 EFilterPart *part;
689 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
690 g_return_val_if_fail (name != NULL, NULL);
692 part = e_rule_context_find_part (context, name);
694 if (part == NULL)
695 return NULL;
697 return e_filter_part_clone (part);
700 EFilterPart *
701 e_rule_context_next_part (ERuleContext *context,
702 EFilterPart *last)
704 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
706 return e_filter_part_next_list (context->parts, last);
709 EFilterRule *
710 e_rule_context_next_rule (ERuleContext *context,
711 EFilterRule *last,
712 const gchar *source)
714 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
716 return e_filter_rule_next_list (context->rules, last, source);
719 EFilterRule *
720 e_rule_context_find_rule (ERuleContext *context,
721 const gchar *name,
722 const gchar *source)
724 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
725 g_return_val_if_fail (name != NULL, NULL);
727 return e_filter_rule_find_list (context->rules, name, source);
730 void
731 e_rule_context_add_part (ERuleContext *context,
732 EFilterPart *part)
734 g_return_if_fail (E_IS_RULE_CONTEXT (context));
735 g_return_if_fail (E_IS_FILTER_PART (part));
737 context->parts = g_list_append (context->parts, part);
740 void
741 e_rule_context_add_rule (ERuleContext *context,
742 EFilterRule *rule)
744 g_return_if_fail (E_IS_RULE_CONTEXT (context));
745 g_return_if_fail (E_IS_FILTER_RULE (rule));
747 context->rules = g_list_append (context->rules, rule);
749 if (context->priv->frozen == 0) {
750 g_signal_emit (context, signals[RULE_ADDED], 0, rule);
751 g_signal_emit (context, signals[CHANGED], 0);
755 /* Add a rule, with a gui, asking for confirmation first,
756 * and optionally save to path. */
757 void
758 e_rule_context_add_rule_gui (ERuleContext *context,
759 EFilterRule *rule,
760 const gchar *title,
761 const gchar *path)
763 GtkDialog *dialog;
764 GtkWidget *widget;
765 GtkWidget *content_area;
767 g_return_if_fail (E_IS_RULE_CONTEXT (context));
768 g_return_if_fail (E_IS_FILTER_RULE (rule));
770 widget = e_filter_rule_get_widget (rule, context);
771 gtk_widget_show (widget);
773 dialog =(GtkDialog *) gtk_dialog_new ();
774 gtk_dialog_add_buttons (dialog,
775 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
776 GTK_STOCK_OK, GTK_RESPONSE_OK,
777 NULL);
778 #if !GTK_CHECK_VERSION(2,90,7)
779 g_object_set (dialog, "has-separator", FALSE, NULL);
780 #endif
782 gtk_window_set_title ((GtkWindow *) dialog, title);
783 gtk_window_set_default_size ((GtkWindow *) dialog, 600, 400);
784 gtk_window_set_resizable ((GtkWindow *) dialog, TRUE);
786 content_area = gtk_dialog_get_content_area (dialog);
787 gtk_box_pack_start (GTK_BOX (content_area), widget, TRUE, TRUE, 0);
789 g_object_set_data_full ((GObject *) dialog, "rule", rule, g_object_unref);
790 if (path)
791 g_object_set_data_full ((GObject *) dialog, "path", g_strdup (path), g_free);
793 g_signal_connect (dialog, "response", G_CALLBACK (new_rule_response), context);
795 g_object_ref (context);
797 g_object_set_data_full ((GObject *) dialog, "context", context, g_object_unref);
799 gtk_widget_show ((GtkWidget *) dialog);
802 void
803 e_rule_context_remove_rule (ERuleContext *context,
804 EFilterRule *rule)
806 g_return_if_fail (E_IS_RULE_CONTEXT (context));
807 g_return_if_fail (E_IS_FILTER_RULE (rule));
809 context->rules = g_list_remove (context->rules, rule);
811 if (context->priv->frozen == 0) {
812 g_signal_emit (context, signals[RULE_REMOVED], 0, rule);
813 g_signal_emit (context, signals[CHANGED], 0);
817 void
818 e_rule_context_rank_rule (ERuleContext *context,
819 EFilterRule *rule,
820 const gchar *source,
821 gint rank)
823 GList *node;
824 gint i = 0, index = 0;
826 g_return_if_fail (E_IS_RULE_CONTEXT (context));
827 g_return_if_fail (E_IS_FILTER_RULE (rule));
829 if (e_rule_context_get_rank_rule (context, rule, source) == rank)
830 return;
832 context->rules = g_list_remove (context->rules, rule);
833 node = context->rules;
834 while (node) {
835 EFilterRule *r = node->data;
837 if (i == rank) {
838 context->rules = g_list_insert (context->rules, rule, index);
839 if (context->priv->frozen == 0)
840 g_signal_emit (context, signals[CHANGED], 0);
842 return;
845 index++;
846 if (source == NULL || (r->source && strcmp (r->source, source) == 0))
847 i++;
849 node = node->next;
852 context->rules = g_list_append (context->rules, rule);
853 if (context->priv->frozen == 0)
854 g_signal_emit (context, signals[CHANGED], 0);
857 gint
858 e_rule_context_get_rank_rule (ERuleContext *context,
859 EFilterRule *rule,
860 const gchar *source)
862 GList *node;
863 gint i = 0;
865 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), -1);
866 g_return_val_if_fail (E_IS_FILTER_RULE (rule), -1);
868 node = context->rules;
869 while (node) {
870 EFilterRule *r = node->data;
872 if (r == rule)
873 return i;
875 if (source == NULL || (r->source && strcmp (r->source, source) == 0))
876 i++;
878 node = node->next;
881 return -1;
884 EFilterRule *
885 e_rule_context_find_rank_rule (ERuleContext *context,
886 gint rank,
887 const gchar *source)
889 GList *node;
890 gint i = 0;
892 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
894 node = context->rules;
895 while (node) {
896 EFilterRule *r = node->data;
898 if (source == NULL || (r->source && strcmp (r->source, source) == 0)) {
899 if (rank == i)
900 return r;
901 i++;
904 node = node->next;
907 return NULL;
910 GList *
911 e_rule_context_rename_uri (ERuleContext *context,
912 const gchar *old_uri,
913 const gchar *new_uri,
914 GCompareFunc compare)
916 ERuleContextClass *class;
918 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
919 g_return_val_if_fail (old_uri != NULL, NULL);
920 g_return_val_if_fail (new_uri != NULL, NULL);
921 g_return_val_if_fail (compare != NULL, NULL);
923 class = E_RULE_CONTEXT_GET_CLASS (context);
925 /* This method is optional. */
926 if (class->rename_uri == NULL)
927 return NULL;
929 return class->rename_uri (context, old_uri, new_uri, compare);
932 GList *
933 e_rule_context_delete_uri (ERuleContext *context,
934 const gchar *uri,
935 GCompareFunc compare)
937 ERuleContextClass *class;
939 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
940 g_return_val_if_fail (uri != NULL, NULL);
941 g_return_val_if_fail (compare != NULL, NULL);
943 class = E_RULE_CONTEXT_GET_CLASS (context);
945 /* This method is optional. */
946 if (class->delete_uri == NULL)
947 return NULL;
949 return class->delete_uri (context, uri, compare);
952 void
953 e_rule_context_free_uri_list (ERuleContext *context,
954 GList *uris)
956 g_return_if_fail (E_IS_RULE_CONTEXT (context));
958 /* TODO: should be virtual */
960 g_list_foreach (uris, (GFunc) g_free, NULL);
961 g_list_free (uris);
965 * e_rule_context_new_element:
966 * @context:
967 * @name:
969 * create a new filter element based on name.
971 * Return value:
973 EFilterElement *
974 e_rule_context_new_element (ERuleContext *context,
975 const gchar *name)
977 ERuleContextClass *class;
979 g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
980 g_return_val_if_fail (name != NULL, NULL);
982 class = E_RULE_CONTEXT_GET_CLASS (context);
983 g_return_val_if_fail (class->new_element != NULL, NULL);
985 return class->new_element (context, name);