diff options
author | Marco Pesenti Gritti <mpeseng@src.gnome.org> | 2002-12-31 03:29:24 +0800 |
---|---|---|
committer | Marco Pesenti Gritti <mpeseng@src.gnome.org> | 2002-12-31 03:29:24 +0800 |
commit | 6876ede98282c7db318089bfefb292aa59e55d48 (patch) | |
tree | 76b23252d04da232d0ebf22e53bfe3e022686af9 /lib/ephy-node-filter.c | |
download | gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar.gz gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar.bz2 gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar.lz gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar.xz gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar.zst gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.zip |
Initial revision
Diffstat (limited to 'lib/ephy-node-filter.c')
-rw-r--r-- | lib/ephy-node-filter.c | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/lib/ephy-node-filter.c b/lib/ephy-node-filter.c new file mode 100644 index 000000000..8f0bddbc0 --- /dev/null +++ b/lib/ephy-node-filter.c @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2002 Olivier Martin <omartin@ifrance.com> + * (C) 2002 Jorn Baayen <jorn@nl.linux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "ephy-node-filter.h" + +static void ephy_node_filter_class_init (EphyNodeFilterClass *klass); +static void ephy_node_filter_init (EphyNodeFilter *node); +static void ephy_node_filter_finalize (GObject *object); +static gboolean ephy_node_filter_expression_evaluate (EphyNodeFilterExpression *expression, + EphyNode *node); + +enum +{ + CHANGED, + LAST_SIGNAL +}; + +struct EphyNodeFilterPrivate +{ + GPtrArray *levels; +}; + +struct EphyNodeFilterExpression +{ + EphyNodeFilterExpressionType type; + + union + { + struct + { + EphyNode *a; + EphyNode *b; + } node_args; + + struct + { + int prop_id; + + union + { + EphyNode *node; + char *string; + int number; + } second_arg; + } prop_args; + } args; +}; + +static GObjectClass *parent_class = NULL; + +static guint ephy_node_filter_signals[LAST_SIGNAL] = { 0 }; + +GType +ephy_node_filter_get_type (void) +{ + static GType ephy_node_filter_type = 0; + + if (ephy_node_filter_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyNodeFilterClass), + NULL, + NULL, + (GClassInitFunc) ephy_node_filter_class_init, + NULL, + NULL, + sizeof (EphyNodeFilter), + 0, + (GInstanceInitFunc) ephy_node_filter_init + }; + + ephy_node_filter_type = g_type_register_static (G_TYPE_OBJECT, + "EphyNodeFilter", + &our_info, 0); + } + + return ephy_node_filter_type; +} + +static void +ephy_node_filter_class_init (EphyNodeFilterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_node_filter_finalize; + + ephy_node_filter_signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyNodeFilterClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +ephy_node_filter_init (EphyNodeFilter *filter) +{ + filter->priv = g_new0 (EphyNodeFilterPrivate, 1); + + filter->priv->levels = g_ptr_array_new (); +} + +static void +ephy_node_filter_finalize (GObject *object) +{ + EphyNodeFilter *filter; + + g_return_if_fail (object != NULL); + g_return_if_fail (EPHY_IS_NODE_FILTER (object)); + + filter = EPHY_NODE_FILTER (object); + + g_return_if_fail (filter->priv != NULL); + + ephy_node_filter_empty (filter); + + g_ptr_array_free (filter->priv->levels, FALSE); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +EphyNodeFilter * +ephy_node_filter_new (void) +{ + EphyNodeFilter *filter; + + filter = EPHY_NODE_FILTER (g_object_new (EPHY_TYPE_NODE_FILTER, + NULL)); + + g_return_val_if_fail (filter->priv != NULL, NULL); + + return filter; +} + +void +ephy_node_filter_add_expression (EphyNodeFilter *filter, + EphyNodeFilterExpression *exp, + int level) +{ + while (level >= filter->priv->levels->len) + g_ptr_array_add (filter->priv->levels, NULL); + + g_ptr_array_index (filter->priv->levels, level) = + g_list_append (g_ptr_array_index (filter->priv->levels, level), exp); +} + +void +ephy_node_filter_empty (EphyNodeFilter *filter) +{ + int i; + + for (i = filter->priv->levels->len - 1; i >= 0; i--) + { + GList *list, *l; + + list = g_ptr_array_index (filter->priv->levels, i); + + for (l = list; l != NULL; l = g_list_next (l)) + { + EphyNodeFilterExpression *exp; + + exp = (EphyNodeFilterExpression *) l->data; + + ephy_node_filter_expression_free (exp); + } + + g_list_free (list); + + g_ptr_array_remove_index (filter->priv->levels, i); + } +} + +void +ephy_node_filter_done_changing (EphyNodeFilter *filter) +{ + g_signal_emit (G_OBJECT (filter), ephy_node_filter_signals[CHANGED], 0); +} + +/* + * We go through each level evaluating the filter expressions. + * Every time we get a match we immediately do a break and jump + * to the next level. We'll return FALSE if we arrive to a level + * without matches, TRUE otherwise. + */ +gboolean +ephy_node_filter_evaluate (EphyNodeFilter *filter, + EphyNode *node) +{ + int i; + + for (i = 0; i < filter->priv->levels->len; i++) { + GList *l, *list; + gboolean handled; + + handled = FALSE; + + list = g_ptr_array_index (filter->priv->levels, i); + + for (l = list; l != NULL; l = g_list_next (l)) { + if (ephy_node_filter_expression_evaluate (l->data, node) == TRUE) { + handled = TRUE; + break; + } + } + + if (handled == FALSE) + return FALSE; + } + + return TRUE; +} + +EphyNodeFilterExpression * +ephy_node_filter_expression_new (EphyNodeFilterExpressionType type, + ...) +{ + EphyNodeFilterExpression *exp; + va_list valist; + + va_start (valist, type); + + exp = g_new0 (EphyNodeFilterExpression, 1); + + exp->type = type; + + switch (type) + { + case EPHY_NODE_FILTER_EXPRESSION_NODE_EQUALS: + exp->args.node_args.a = va_arg (valist, EphyNode *); + exp->args.node_args.b = va_arg (valist, EphyNode *); + break; + case EPHY_NODE_FILTER_EXPRESSION_EQUALS: + case EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT: + case EPHY_NODE_FILTER_EXPRESSION_HAS_CHILD: + exp->args.node_args.a = va_arg (valist, EphyNode *); + break; + case EPHY_NODE_FILTER_EXPRESSION_NODE_PROP_EQUALS: + case EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS: + exp->args.prop_args.prop_id = va_arg (valist, int); + exp->args.prop_args.second_arg.node = va_arg (valist, EphyNode *); + break; + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS: + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS: + exp->args.prop_args.prop_id = va_arg (valist, int); + exp->args.prop_args.second_arg.string = g_utf8_casefold (va_arg (valist, char *), -1); + break; + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS: + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS: + { + char *folded; + + exp->args.prop_args.prop_id = va_arg (valist, int); + + folded = g_utf8_casefold (va_arg (valist, char *), -1); + exp->args.prop_args.second_arg.string = g_utf8_collate_key (folded, -1); + g_free (folded); + break; + } + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS: + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN: + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN: + exp->args.prop_args.prop_id = va_arg (valist, int); + exp->args.prop_args.second_arg.number = va_arg (valist, int); + break; + default: + break; + } + + va_end (valist); + + return exp; +} + +void +ephy_node_filter_expression_free (EphyNodeFilterExpression *exp) +{ + switch (exp->type) + { + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS: + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS: + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS: + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS: + g_free (exp->args.prop_args.second_arg.string); + break; + default: + break; + } + + g_free (exp); +} + +static gboolean +ephy_node_filter_expression_evaluate (EphyNodeFilterExpression *exp, + EphyNode *node) +{ + switch (exp->type) + { + case EPHY_NODE_FILTER_EXPRESSION_ALWAYS_TRUE: + return TRUE; + case EPHY_NODE_FILTER_EXPRESSION_NODE_EQUALS: + return (exp->args.node_args.a == exp->args.node_args.b); + case EPHY_NODE_FILTER_EXPRESSION_EQUALS: + return (exp->args.node_args.a == node); + case EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT: + return ephy_node_has_child (exp->args.node_args.a, node); + case EPHY_NODE_FILTER_EXPRESSION_HAS_CHILD: + return ephy_node_has_child (node, exp->args.node_args.a); + case EPHY_NODE_FILTER_EXPRESSION_NODE_PROP_EQUALS: + { + EphyNode *prop; + + prop = ephy_node_get_property_node (node, + exp->args.prop_args.prop_id); + + return (prop == exp->args.prop_args.second_arg.node); + } + case EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS: + { + EphyNode *prop; + GPtrArray *children; + int i; + + children = ephy_node_get_children (node); + for (i = 0; i < children->len; i++) + { + EphyNode *child; + + child = g_ptr_array_index (children, i); + prop = ephy_node_get_property_node + (child, exp->args.prop_args.prop_id); + + if (prop == exp->args.prop_args.second_arg.node) + { + ephy_node_thaw (node); + return TRUE; + } + } + + ephy_node_thaw (node); + return FALSE; + } + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS: + { + const char *prop; + char *folded_case; + gboolean ret; + + prop = ephy_node_get_property_string (node, + exp->args.prop_args.prop_id); + if (prop == NULL) + return FALSE; + + folded_case = g_utf8_casefold (prop, -1); + ret = (strstr (folded_case, exp->args.prop_args.second_arg.string) != NULL); + g_free (folded_case); + + return ret; + } + case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS: + { + const char *prop; + char *folded_case; + gboolean ret; + + prop = ephy_node_get_property_string (node, + exp->args.prop_args.prop_id); + + if (prop == NULL) + return FALSE; + + folded_case = g_utf8_casefold (prop, -1); + ret = (strcmp (folded_case, exp->args.prop_args.second_arg.string) == 0); + g_free (folded_case); + + return ret; + } + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS: + { + const char *prop; + + prop = ephy_node_get_property_string (node, + exp->args.prop_args.prop_id); + + if (prop == NULL) + return FALSE; + + return (strstr (prop, exp->args.prop_args.second_arg.string) != NULL); + } + case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS: + { + const char *prop; + + prop = ephy_node_get_property_string (node, + exp->args.prop_args.prop_id); + + if (prop == NULL) + return FALSE; + + return (strcmp (prop, exp->args.prop_args.second_arg.string) == 0); + } + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS: + { + int prop; + + prop = ephy_node_get_property_int (node, + exp->args.prop_args.prop_id); + + return (prop == exp->args.prop_args.second_arg.number); + } + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN: + { + int prop; + + prop = ephy_node_get_property_int (node, + exp->args.prop_args.prop_id); + + return (prop > exp->args.prop_args.second_arg.number); + } + case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN: + { + int prop; + + prop = ephy_node_get_property_int (node, + exp->args.prop_args.prop_id); + g_print ("%d %d\n", prop, exp->args.prop_args.second_arg.number); + return (prop < exp->args.prop_args.second_arg.number); + } + default: + break; + } + + return FALSE; +} |