diff options
-rw-r--r-- | filter/e-filter-option.c | 85 | ||||
-rw-r--r-- | filter/e-filter-option.h | 7 | ||||
-rw-r--r-- | mail/filtertypes.xml | 10 | ||||
-rw-r--r-- | mail/searchtypes.xml | 10 | ||||
-rw-r--r-- | mail/vfoldertypes.xml | 8 | ||||
-rw-r--r-- | modules/mail/e-mail-shell-backend.c | 143 | ||||
-rw-r--r-- | modules/mail/e-mail-shell-backend.h | 10 |
7 files changed, 234 insertions, 39 deletions
diff --git a/filter/e-filter-option.c b/filter/e-filter-option.c index 2f6c73454d..dd6d9b8874 100644 --- a/filter/e-filter-option.c +++ b/filter/e-filter-option.c @@ -45,6 +45,7 @@ free_option (struct _filter_option *opt) g_free (opt->title); g_free (opt->value); g_free (opt->code); + g_free (opt->code_gen_func); g_free (opt); } @@ -101,6 +102,29 @@ filter_option_get_dynamic_options (EFilterOption *option) } static void +filter_option_generate_code (EFilterOption *option, + GString *out, + EFilterPart *part) +{ + GModule *module; + void (*code_gen_func) (EFilterElement *element, GString *out, EFilterPart *part); + + if (!option || !option->current || !option->current->code_gen_func) + return; + + module = g_module_open (NULL, G_MODULE_BIND_LAZY); + + if (g_module_symbol (module, option->current->code_gen_func, (gpointer) &code_gen_func)) { + code_gen_func (E_FILTER_ELEMENT (option), out, part); + } else { + g_warning ("optionlist dynamic code function '%s' not found", + option->current->code_gen_func); + } + + g_module_close (module); +} + +static void filter_option_finalize (GObject *object) { EFilterOption *option = E_FILTER_OPTION (object); @@ -149,7 +173,7 @@ filter_option_xml_create (EFilterElement *element, n = node->children; while (n) { if (!strcmp ((gchar *)n->name, "option")) { - gchar *tmp, *value, *title = NULL, *code = NULL; + gchar *tmp, *value, *title = NULL, *code = NULL, *code_gen_func = NULL; value = (gchar *)xmlGetProp (n, (xmlChar *)"value"); work = n->children; @@ -164,21 +188,43 @@ filter_option_xml_create (EFilterElement *element, xmlFree (tmp); } } else if (!strcmp ((gchar *)work->name, "code")) { - if (!code) { - if (!(tmp = (gchar *) xmlNodeGetContent (work))) - tmp = (gchar *)xmlStrdup ((xmlChar *)""); + if (code || code_gen_func) { + g_warning ("Element 'code' defined twice in '%s'", + element->name); + } else { + xmlChar *fn; + + /* if element 'code' has attribute 'func', then + the content of the element is ignored and only + the 'func' is used to generate actual rule code; + The function prototype is: + void code_gen_func (EFilterElement *element, GString *out, EFilterPart *part); + where @element is the one on which was called, + @out is GString where to add the code, and + @part is part which contains @element and other options of it. + */ + fn = xmlGetProp (work, (xmlChar *)"func"); + if (fn && *fn) { + code_gen_func = g_strdup ((const gchar *) fn); + } else { + if (!(tmp = (gchar *) xmlNodeGetContent (work))) + tmp = (gchar *)xmlStrdup ((xmlChar *)""); + + code = g_strdup (tmp); + xmlFree (tmp); + } - code = g_strdup (tmp); - xmlFree (tmp); + xmlFree (fn); } } work = work->next; } - e_filter_option_add (option, value, title, code, FALSE); + e_filter_option_add (option, value, title, code, code_gen_func, FALSE); xmlFree (value); g_free (title); g_free (code); + g_free (code_gen_func); } else if (g_str_equal ((gchar *)n->name, "dynamic")) { if (option->dynamic_func) { g_warning ( @@ -217,6 +263,7 @@ filter_option_xml_create (EFilterElement *element, op->value, op->title, op->code, + op->code_gen_func, TRUE); free_option (op); } @@ -295,7 +342,7 @@ filter_option_clone (EFilterElement *element) newop = e_filter_option_add ( clone_option, op->value, - op->title, op->code, op->is_dynamic); + op->title, op->code, op->code_gen_func, op->is_dynamic); if (option->current == op) clone_option->current = newop; } @@ -335,8 +382,8 @@ filter_option_get_widget (EFilterElement *element) break; } else { e_filter_option_add ( - option, op->value, - op->title, op->code, FALSE); + option, op->value, op->title, + op->code, op->code_gen_func, FALSE); } } @@ -346,8 +393,8 @@ filter_option_get_widget (EFilterElement *element) if (op) { e_filter_option_add ( - option, op->value, - op->title, op->code, TRUE); + option, op->value, op->title, + op->code, op->code_gen_func, TRUE); free_option (op); } } @@ -360,8 +407,8 @@ filter_option_get_widget (EFilterElement *element) if (!op->is_dynamic) e_filter_option_add ( - option, op->value, - op->title, op->code, FALSE); + option, op->value, op->title, + op->code, op->code_gen_func, FALSE); } if (old_cur) @@ -402,8 +449,11 @@ filter_option_build_code (EFilterElement *element, { EFilterOption *option = E_FILTER_OPTION (element); - if (option->current && option->current->code) + if (option->current && option->current->code_gen_func) { + filter_option_generate_code (option, out, part); + } else if (option->current && option->current->code) { e_filter_part_expand_code (part, option->current->code, out); + } } static void @@ -464,6 +514,7 @@ e_filter_option_add (EFilterOption *option, const gchar *value, const gchar *title, const gchar *code, + const gchar *code_gen_func, gboolean is_dynamic) { struct _filter_option *op; @@ -471,10 +522,14 @@ e_filter_option_add (EFilterOption *option, g_return_val_if_fail (E_IS_FILTER_OPTION (option), NULL); g_return_val_if_fail (find_option (option, value) == NULL, NULL); + if (code_gen_func && !*code_gen_func) + code_gen_func = NULL; + op = g_malloc (sizeof (*op)); op->title = g_strdup (title); op->value = g_strdup (value); op->code = g_strdup (code); + op->code_gen_func = g_strdup (code_gen_func); op->is_dynamic = is_dynamic; option->options = g_list_append (option->options, op); diff --git a/filter/e-filter-option.h b/filter/e-filter-option.h index 45d426b761..84b98bd104 100644 --- a/filter/e-filter-option.h +++ b/filter/e-filter-option.h @@ -55,8 +55,12 @@ struct _filter_option { gchar *title; /* button title */ gchar *value; /* value, if it has one */ gchar *code; /* used to string code segments together */ + gchar *code_gen_func; /* function to generate the code; + either @code or @code_gen_func is non-NULL, + never both */ - gboolean is_dynamic; /* whether is the option dynamic, FALSE if static */ + gboolean is_dynamic; /* whether is the option dynamic, FALSE if static; + dynamic means "generated by EFilterOption::dynamic_func" */ }; struct _EFilterOption { @@ -84,6 +88,7 @@ struct _filter_option * const gchar *name, const gchar *title, const gchar *code, + const gchar *code_gen_func, gboolean is_dynamic); void e_filter_option_remove_all (EFilterOption *option); diff --git a/mail/filtertypes.xml b/mail/filtertypes.xml index c655c32cb8..02bea7fadd 100644 --- a/mail/filtertypes.xml +++ b/mail/filtertypes.xml @@ -648,15 +648,11 @@ <input type="optionlist" name="label-type"> <option value="is"> <title>is</title> - <code> - (match-all (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus}))) - </code> + <code func="e_mail_labels_get_filter_code"/> </option> <option value="is-not"> <title>is not</title> - <code> - (match-all (not (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus})))) - </code> + <code func="e_mail_labels_get_filter_code"/> </option> </input> <input type="optionlist" name="versus"> @@ -947,7 +943,7 @@ <title>Set Label</title> <code>(set-label ${label})</code> <input type="optionlist" name="label"> - <dynamic func="e_mail_labels_get_filter_options"/> + <dynamic func="e_mail_labels_get_filter_options_without_none"/> </input> </part> <part name="colour"> diff --git a/mail/searchtypes.xml b/mail/searchtypes.xml index 0173066aa2..bf933d8342 100644 --- a/mail/searchtypes.xml +++ b/mail/searchtypes.xml @@ -644,16 +644,12 @@ <input type="optionlist" name="label-type"> <option value="is"> <title>is</title> - <code> - (match-all (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus}))) - </code> + <code func="e_mail_labels_get_filter_code"/> </option> <option value="is-not"> <title>is not</title> - <code> - (match-all (not (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus})))) - </code> - </option> + <code func="e_mail_labels_get_filter_code"/> + </option> </input> <input type="optionlist" name="versus"> <dynamic func="e_mail_labels_get_filter_options"/> diff --git a/mail/vfoldertypes.xml b/mail/vfoldertypes.xml index 5f8bbd19a4..9195271c9c 100644 --- a/mail/vfoldertypes.xml +++ b/mail/vfoldertypes.xml @@ -640,15 +640,11 @@ <input type="optionlist" name="label-type"> <option value="is"> <title>is</title> - <code> - (match-all (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus}))) - </code> + <code func="e_mail_labels_get_filter_code"/> </option> <option value="is-not"> <title>is not</title> - <code> - (match-all (not (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus})))) - </code> + <code func="e_mail_labels_get_filter_code"/> </option> </input> <input type="optionlist" name="versus"> diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c index 6fab84bb96..2079d28cdc 100644 --- a/modules/mail/e-mail-shell-backend.c +++ b/modules/mail/e-mail-shell-backend.c @@ -871,8 +871,8 @@ e_mail_shell_backend_edit_account (EMailShellBackend *mail_shell_backend, #include "filter/e-filter-option.h" #include "shell/e-shell-settings.h" -GSList * -e_mail_labels_get_filter_options (void) +static GSList * +mail_labels_get_filter_options (gboolean include_none) { EShell *shell; EShellBackend *shell_backend; @@ -892,6 +892,16 @@ e_mail_labels_get_filter_options (void) label_store = e_mail_ui_session_get_label_store ( E_MAIL_UI_SESSION (session)); + if (include_none) { + struct _filter_option *option; + + option = g_new0 (struct _filter_option, 1); + /* Translators: The first item in the list, to be able to set rule: [Label] [is/is-not] [None] */ + option->title = g_strdup (C_("label", "None")); + option->value = g_strdup (""); + list = g_slist_prepend (list, option); + } + model = GTK_TREE_MODEL (label_store); valid = gtk_tree_model_get_iter_first (model, &iter); @@ -923,6 +933,135 @@ e_mail_labels_get_filter_options (void) return g_slist_reverse (list); } + +GSList * +e_mail_labels_get_filter_options (void) +{ + return mail_labels_get_filter_options (TRUE); +} + +GSList * +e_mail_labels_get_filter_options_without_none (void) +{ + return mail_labels_get_filter_options (FALSE); +} + +static const gchar * +get_filter_option_value (EFilterPart *part, + const gchar *name) +{ + EFilterElement *elem; + EFilterOption *opt; + + g_return_val_if_fail (part != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + elem = e_filter_part_find_element (part, name); + g_return_val_if_fail (elem != NULL, NULL); + g_return_val_if_fail (E_IS_FILTER_OPTION (elem), NULL); + + opt = E_FILTER_OPTION (elem); + return e_filter_option_get_current (opt); +} + +static void +append_one_label_expr (GString *out, + const gchar *versus) +{ + GString *encoded; + + g_return_if_fail (out != NULL); + g_return_if_fail (versus != NULL); + + encoded = g_string_new (""); + camel_sexp_encode_string (encoded, versus); + + g_string_append_printf (out, + " (= (user-tag \"label\") %s) (user-flag (+ \"$Label\" %s)) (user-flag %s)", + encoded->str, encoded->str, encoded->str); + + g_string_free (encoded, TRUE); +} + +void +e_mail_labels_get_filter_code (EFilterElement *element, + GString *out, + EFilterPart *part) +{ + const gchar *label_type, *versus; + gboolean is_not; + + label_type = get_filter_option_value (part, "label-type"); + versus = get_filter_option_value (part, "versus"); + + g_return_if_fail (label_type != NULL); + g_return_if_fail (versus != NULL); + + is_not = g_str_equal (label_type, "is-not"); + + if (!g_str_equal (label_type, "is") && !is_not) { + g_warning ("%s: Unknown label-type: '%s'", G_STRFUNC, label_type); + return; + } + + /* the 'None' item has 'is-not' inverted */ + if (!*versus) + is_not = !is_not; + + g_string_append (out, " (match-all ("); + if (is_not) + g_string_append (out, " not ("); + g_string_append (out, "or"); + + /* the 'None' item; "is None" means "has not set any label" */ + if (!*versus) { + EShell *shell; + EShellBackend *shell_backend; + EMailBackend *backend; + EMailSession *session; + EMailLabelListStore *label_store; + GtkTreeModel *model; + GtkTreeIter iter; + gboolean valid; + + shell = e_shell_get_default (); + shell_backend = e_shell_get_backend_by_name (shell, "mail"); + + backend = E_MAIL_BACKEND (shell_backend); + session = e_mail_backend_get_session (backend); + label_store = e_mail_ui_session_get_label_store (E_MAIL_UI_SESSION (session)); + + model = GTK_TREE_MODEL (label_store); + valid = gtk_tree_model_get_iter_first (model, &iter); + + while (valid) { + gchar *tag; + + tag = e_mail_label_list_store_get_tag (label_store, &iter); + + if (g_str_has_prefix (tag, "$Label")) { + gchar *tmp = tag; + + tag = g_strdup (tag + 6); + + g_free (tmp); + } + + append_one_label_expr (out, tag); + + g_free (tag); + + valid = gtk_tree_model_iter_next (model, &iter); + } + } else { + append_one_label_expr (out, versus); + } + + if (is_not) + g_string_append (out, ")"); + g_string_append (out, " ))"); +} + static void message_parsed_cb (GObject *source_object, GAsyncResult *res, diff --git a/modules/mail/e-mail-shell-backend.h b/modules/mail/e-mail-shell-backend.h index 0b76ea39b6..5b2da24e5f 100644 --- a/modules/mail/e-mail-shell-backend.h +++ b/modules/mail/e-mail-shell-backend.h @@ -23,6 +23,8 @@ #define E_MAIL_SHELL_BACKEND_H #include <mail/e-mail-backend.h> +#include <filter/e-filter-element.h> +#include <filter/e-filter-rule.h> /* Standard GObject macros */ #define E_TYPE_MAIL_SHELL_BACKEND \ @@ -71,7 +73,13 @@ void e_mail_shell_backend_edit_account ESource *mail_account); /* XXX Find a better place for this function. */ -GSList * e_mail_labels_get_filter_options (void); +GSList * e_mail_labels_get_filter_options + (void); +GSList * e_mail_labels_get_filter_options_without_none + (void); +void e_mail_labels_get_filter_code (EFilterElement *element, + GString *out, + EFilterPart *part); G_END_DECLS |