Initial import of ephy (rev# 7126) from svn
[ephy-soc.git] / lib / .svn / text-base / ephy-node-filter.c.svn-base
blobabb363e3132fa6469526ee83aa9c1e6b1c269439
1 /* 
2  *  Copyright © 2002 Olivier Martin <omartin@ifrance.com>
3  *            (C) 2002 Jorn Baayen <jorn@nl.linux.org>
4  *
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.
9  *
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.
14  *
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.
18  *
19  *  $Id$
20  */
22 #include "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
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,
34                                                       EphyNode *node);
36 enum
38         CHANGED,
39         LAST_SIGNAL
42 #define EPHY_NODE_FILTER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_NODE_FILTER, EphyNodeFilterPrivate))
44 struct _EphyNodeFilterPrivate
46         GPtrArray *levels;
49 struct _EphyNodeFilterExpression
51         EphyNodeFilterExpressionType type;
53         union
54         {
55                 struct
56                 {
57                         EphyNode *a;
58                         EphyNode *b;
59                 } node_args;
61                 struct
62                 {
63                         int prop_id;
65                         union
66                         {
67                                 EphyNode *node;
68                                 char *string;
69                                 int number;
70                         } second_arg;
71                 } prop_args;
72         } args;
75 static GObjectClass *parent_class = NULL;
77 static guint ephy_node_filter_signals[LAST_SIGNAL] = { 0 };
79 GType
80 ephy_node_filter_get_type (void)
82         static GType type = 0;
84         if (G_UNLIKELY (type == 0))
85         {
86                 const GTypeInfo our_info =
87                 {
88                         sizeof (EphyNodeFilterClass),
89                         NULL,
90                         NULL,
91                         (GClassInitFunc) ephy_node_filter_class_init,
92                         NULL,
93                         NULL,
94                         sizeof (EphyNodeFilter),
95                         0,
96                         (GInstanceInitFunc) ephy_node_filter_init
97                 };
99                 type = g_type_register_static (G_TYPE_OBJECT,
100                                                "EphyNodeFilter",
101                                                &our_info, 0);
102         }
104         return type;
107 static void
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),
119                               G_SIGNAL_RUN_LAST,
120                               G_STRUCT_OFFSET (EphyNodeFilterClass, changed),
121                               NULL, NULL,
122                               g_cclosure_marshal_VOID__VOID,
123                               G_TYPE_NONE,
124                               0);
126         g_type_class_add_private (object_class, sizeof (EphyNodeFilterPrivate));
129 static void
130 ephy_node_filter_init (EphyNodeFilter *filter)
132         filter->priv = EPHY_NODE_FILTER_GET_PRIVATE (filter);
134         filter->priv->levels = g_ptr_array_new ();
137 static void
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);
149 EphyNodeFilter *
150 ephy_node_filter_new (void)
152         return EPHY_NODE_FILTER (g_object_new (EPHY_TYPE_NODE_FILTER, NULL));
155 void
156 ephy_node_filter_add_expression (EphyNodeFilter *filter,
157                                  EphyNodeFilterExpression *exp,
158                                  int level)
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);
168 void
169 ephy_node_filter_empty (EphyNodeFilter *filter)
171         int i;
172         
173         for (i = filter->priv->levels->len - 1; i >= 0; i--)
174         {
175                 GList *list, *l;
177                 list = g_ptr_array_index (filter->priv->levels, i);
179                 for (l = list; l != NULL; l = g_list_next (l))
180                 {
181                         EphyNodeFilterExpression *exp;
183                         exp = (EphyNodeFilterExpression *) l->data;
185                         ephy_node_filter_expression_free (exp);
186                 }
188                 g_list_free (list);
190                 g_ptr_array_remove_index (filter->priv->levels, i);
191         }
194 void
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.
205  */
206 gboolean
207 ephy_node_filter_evaluate (EphyNodeFilter *filter,
208                            EphyNode *node)
210         int i;
212         for (i = 0; i < filter->priv->levels->len; i++) {
213                 GList *l, *list;
214                 gboolean handled;
216                 handled = FALSE;
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) {
222                                 handled = TRUE;
223                                 break;
224                         }
225                 }
227                 if (list != NULL && handled == FALSE)
228                         return FALSE;
229         }
230         
231         return TRUE;
234 EphyNodeFilterExpression *
235 ephy_node_filter_expression_new (EphyNodeFilterExpressionType type,
236                                  ...)
238         EphyNodeFilterExpression *exp;
239         va_list valist;
241         va_start (valist, type);
243         exp = g_new0 (EphyNodeFilterExpression, 1);
245         exp->type = type;
247         switch (type)
248         {
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 *);
252                 break;
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 *);
257                 break;
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 *);
262                 break;
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);
267                 break;
268         case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS:
269         case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS:
270         {
271                 char *folded;
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);
277                 g_free (folded);
278                 break;
279         }
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);
285                 break;
286         default:
287                 break;
288         }
290         va_end (valist);
292         return exp;
295 void
296 ephy_node_filter_expression_free (EphyNodeFilterExpression *exp)
298         switch (exp->type)
299         {
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);
305                 break;
306         default:
307                 break;
308         }
309         
310         g_free (exp);
313 static gboolean
314 ephy_node_filter_expression_evaluate (EphyNodeFilterExpression *exp,
315                                       EphyNode *node)
317         switch (exp->type)
318         {
319         case EPHY_NODE_FILTER_EXPRESSION_ALWAYS_TRUE:
320                 return 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:
330         {
331                 EphyNode *prop;
333                 prop = ephy_node_get_property_node (node,
334                                                   exp->args.prop_args.prop_id);
335                 
336                 return (prop == exp->args.prop_args.second_arg.node);
337         }
338         case EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS:
339         {
340                 EphyNode *prop;
341                 GPtrArray *children;
342                 int i;
343                 
344                 children = ephy_node_get_children (node);
345                 for (i = 0; i < children->len; i++)
346                 {
347                         EphyNode *child;
348                         
349                         child = g_ptr_array_index (children, i);
350                         prop = ephy_node_get_property_node 
351                                 (child, exp->args.prop_args.prop_id);
352                 
353                         if (prop == exp->args.prop_args.second_arg.node)
354                         {
355                                 return TRUE;
356                         }
357                 }
358                 
359                 return FALSE;
360         }
361         case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS:
362         {
363                 const char *prop;
364                 char *folded_case;
365                 gboolean ret;
367                 prop = ephy_node_get_property_string (node,
368                                                     exp->args.prop_args.prop_id);
369                 if (prop == NULL)
370                         return FALSE;
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);
376                 return ret;
377         }
378         case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS:
379         {
380                 const char *prop;
381                 char *folded_case;
382                 gboolean ret;
384                 prop = ephy_node_get_property_string (node,
385                                                     exp->args.prop_args.prop_id);
387                 if (prop == NULL)
388                         return FALSE;
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);
394                 return ret;
395         }
396         case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS:
397         {
398                 const char *prop;
400                 prop = ephy_node_get_property_string (node,
401                                                     exp->args.prop_args.prop_id);
403                 if (prop == NULL)
404                         return FALSE;
406                 return (strstr (prop, exp->args.prop_args.second_arg.string) != NULL);
407         }
408         case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS:
409         {
410                 const char *prop;
412                 prop = ephy_node_get_property_string (node,
413                                                     exp->args.prop_args.prop_id);
415                 if (prop == NULL)
416                         return FALSE;
418                 return (strcmp (prop, exp->args.prop_args.second_arg.string) == 0);
419         }
420         case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS:
421         {
422                 int prop;
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);
428         }
429         case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN:
430         {
431                 int prop;
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);
437         }
438         case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN:
439         {
440                 int prop;
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);
446         }
447         default:
448                 break;
449         }
451         return FALSE;