2 * Copyright © 2002 Olivier Martin <omartin@ifrance.com>
3 * (C) 2002 Jorn Baayen <jorn@nl.linux.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include "ephy-node-filter.h"
30 static void ephy_node_filter_class_init (EphyNodeFilterClass *klass);
31 static void ephy_node_filter_init (EphyNodeFilter *node);
32 static void ephy_node_filter_finalize (GObject *object);
33 static gboolean ephy_node_filter_expression_evaluate (EphyNodeFilterExpression *expression,
42 #define EPHY_NODE_FILTER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_NODE_FILTER, EphyNodeFilterPrivate))
44 struct _EphyNodeFilterPrivate
49 struct _EphyNodeFilterExpression
51 EphyNodeFilterExpressionType type;
75 static GObjectClass *parent_class = NULL;
77 static guint ephy_node_filter_signals[LAST_SIGNAL] = { 0 };
80 ephy_node_filter_get_type (void)
82 static GType type = 0;
84 if (G_UNLIKELY (type == 0))
86 const GTypeInfo our_info =
88 sizeof (EphyNodeFilterClass),
91 (GClassInitFunc) ephy_node_filter_class_init,
94 sizeof (EphyNodeFilter),
96 (GInstanceInitFunc) ephy_node_filter_init
99 type = g_type_register_static (G_TYPE_OBJECT,
108 ephy_node_filter_class_init (EphyNodeFilterClass *klass)
110 GObjectClass *object_class = G_OBJECT_CLASS (klass);
112 parent_class = g_type_class_peek_parent (klass);
114 object_class->finalize = ephy_node_filter_finalize;
116 ephy_node_filter_signals[CHANGED] =
117 g_signal_new ("changed",
118 G_OBJECT_CLASS_TYPE (object_class),
120 G_STRUCT_OFFSET (EphyNodeFilterClass, changed),
122 g_cclosure_marshal_VOID__VOID,
126 g_type_class_add_private (object_class, sizeof (EphyNodeFilterPrivate));
130 ephy_node_filter_init (EphyNodeFilter *filter)
132 filter->priv = EPHY_NODE_FILTER_GET_PRIVATE (filter);
134 filter->priv->levels = g_ptr_array_new ();
138 ephy_node_filter_finalize (GObject *object)
140 EphyNodeFilter *filter = EPHY_NODE_FILTER (object);
142 ephy_node_filter_empty (filter);
144 g_ptr_array_free (filter->priv->levels, TRUE);
146 G_OBJECT_CLASS (parent_class)->finalize (object);
150 ephy_node_filter_new (void)
152 return EPHY_NODE_FILTER (g_object_new (EPHY_TYPE_NODE_FILTER, NULL));
156 ephy_node_filter_add_expression (EphyNodeFilter *filter,
157 EphyNodeFilterExpression *exp,
160 while (level >= filter->priv->levels->len)
161 g_ptr_array_add (filter->priv->levels, NULL);
163 /* FIXME bogosity! This only works because g_list_append (x, data) == x */
164 g_ptr_array_index (filter->priv->levels, level) =
165 g_list_append (g_ptr_array_index (filter->priv->levels, level), exp);
169 ephy_node_filter_empty (EphyNodeFilter *filter)
173 for (i = filter->priv->levels->len - 1; i >= 0; i--)
177 list = g_ptr_array_index (filter->priv->levels, i);
179 for (l = list; l != NULL; l = g_list_next (l))
181 EphyNodeFilterExpression *exp;
183 exp = (EphyNodeFilterExpression *) l->data;
185 ephy_node_filter_expression_free (exp);
190 g_ptr_array_remove_index (filter->priv->levels, i);
195 ephy_node_filter_done_changing (EphyNodeFilter *filter)
197 g_signal_emit (G_OBJECT (filter), ephy_node_filter_signals[CHANGED], 0);
201 * We go through each level evaluating the filter expressions.
202 * Every time we get a match we immediately do a break and jump
203 * to the next level. We'll return FALSE if we arrive to a level
204 * without matches, TRUE otherwise.
207 ephy_node_filter_evaluate (EphyNodeFilter *filter,
212 for (i = 0; i < filter->priv->levels->len; i++) {
218 list = g_ptr_array_index (filter->priv->levels, i);
220 for (l = list; l != NULL; l = g_list_next (l)) {
221 if (ephy_node_filter_expression_evaluate (l->data, node) == TRUE) {
227 if (list != NULL && handled == FALSE)
234 EphyNodeFilterExpression *
235 ephy_node_filter_expression_new (EphyNodeFilterExpressionType type,
238 EphyNodeFilterExpression *exp;
241 va_start (valist, type);
243 exp = g_new0 (EphyNodeFilterExpression, 1);
249 case EPHY_NODE_FILTER_EXPRESSION_NODE_EQUALS:
250 exp->args.node_args.a = va_arg (valist, EphyNode *);
251 exp->args.node_args.b = va_arg (valist, EphyNode *);
253 case EPHY_NODE_FILTER_EXPRESSION_EQUALS:
254 case EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT:
255 case EPHY_NODE_FILTER_EXPRESSION_HAS_CHILD:
256 exp->args.node_args.a = va_arg (valist, EphyNode *);
258 case EPHY_NODE_FILTER_EXPRESSION_NODE_PROP_EQUALS:
259 case EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS:
260 exp->args.prop_args.prop_id = va_arg (valist, int);
261 exp->args.prop_args.second_arg.node = va_arg (valist, EphyNode *);
263 case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS:
264 case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS:
265 exp->args.prop_args.prop_id = va_arg (valist, int);
266 exp->args.prop_args.second_arg.string = g_utf8_casefold (va_arg (valist, char *), -1);
268 case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS:
269 case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS:
273 exp->args.prop_args.prop_id = va_arg (valist, int);
275 folded = g_utf8_casefold (va_arg (valist, char *), -1);
276 exp->args.prop_args.second_arg.string = g_utf8_collate_key (folded, -1);
280 case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS:
281 case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN:
282 case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN:
283 exp->args.prop_args.prop_id = va_arg (valist, int);
284 exp->args.prop_args.second_arg.number = va_arg (valist, int);
296 ephy_node_filter_expression_free (EphyNodeFilterExpression *exp)
300 case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS:
301 case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS:
302 case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS:
303 case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS:
304 g_free (exp->args.prop_args.second_arg.string);
314 ephy_node_filter_expression_evaluate (EphyNodeFilterExpression *exp,
319 case EPHY_NODE_FILTER_EXPRESSION_ALWAYS_TRUE:
321 case EPHY_NODE_FILTER_EXPRESSION_NODE_EQUALS:
322 return (exp->args.node_args.a == exp->args.node_args.b);
323 case EPHY_NODE_FILTER_EXPRESSION_EQUALS:
324 return (exp->args.node_args.a == node);
325 case EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT:
326 return ephy_node_has_child (exp->args.node_args.a, node);
327 case EPHY_NODE_FILTER_EXPRESSION_HAS_CHILD:
328 return ephy_node_has_child (node, exp->args.node_args.a);
329 case EPHY_NODE_FILTER_EXPRESSION_NODE_PROP_EQUALS:
333 prop = ephy_node_get_property_node (node,
334 exp->args.prop_args.prop_id);
336 return (prop == exp->args.prop_args.second_arg.node);
338 case EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS:
344 children = ephy_node_get_children (node);
345 for (i = 0; i < children->len; i++)
349 child = g_ptr_array_index (children, i);
350 prop = ephy_node_get_property_node
351 (child, exp->args.prop_args.prop_id);
353 if (prop == exp->args.prop_args.second_arg.node)
361 case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS:
367 prop = ephy_node_get_property_string (node,
368 exp->args.prop_args.prop_id);
372 folded_case = g_utf8_casefold (prop, -1);
373 ret = (strstr (folded_case, exp->args.prop_args.second_arg.string) != NULL);
374 g_free (folded_case);
378 case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS:
384 prop = ephy_node_get_property_string (node,
385 exp->args.prop_args.prop_id);
390 folded_case = g_utf8_casefold (prop, -1);
391 ret = (strcmp (folded_case, exp->args.prop_args.second_arg.string) == 0);
392 g_free (folded_case);
396 case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS:
400 prop = ephy_node_get_property_string (node,
401 exp->args.prop_args.prop_id);
406 return (strstr (prop, exp->args.prop_args.second_arg.string) != NULL);
408 case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS:
412 prop = ephy_node_get_property_string (node,
413 exp->args.prop_args.prop_id);
418 return (strcmp (prop, exp->args.prop_args.second_arg.string) == 0);
420 case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS:
424 prop = ephy_node_get_property_int (node,
425 exp->args.prop_args.prop_id);
427 return (prop == exp->args.prop_args.second_arg.number);
429 case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN:
433 prop = ephy_node_get_property_int (node,
434 exp->args.prop_args.prop_id);
436 return (prop > exp->args.prop_args.second_arg.number);
438 case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN:
442 prop = ephy_node_get_property_int (node,
443 exp->args.prop_args.prop_id);
445 return (prop < exp->args.prop_args.second_arg.number);