1/*
2 * Copyright © 2020 Benjamin Otte
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Benjamin Otte <otte@gnome.org>
18 */
19
20#include "config.h"
21
22#include "gtkboolfilter.h"
23
24#include "gtkintl.h"
25#include "gtktypebuiltins.h"
26
27/**
28 * GtkBoolFilter:
29 *
30 * `GtkBoolFilter` evaluates a boolean `GtkExpression`
31 * to determine whether to include items.
32 */
33
34struct _GtkBoolFilter
35{
36 GtkFilter parent_instance;
37
38 gboolean invert;
39 GtkExpression *expression;
40};
41
42enum {
43 PROP_0,
44 PROP_EXPRESSION,
45 PROP_INVERT,
46 NUM_PROPERTIES
47};
48
49G_DEFINE_TYPE (GtkBoolFilter, gtk_bool_filter, GTK_TYPE_FILTER)
50
51static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
52
53static gboolean
54gtk_bool_filter_match (GtkFilter *filter,
55 gpointer item)
56{
57 GtkBoolFilter *self = GTK_BOOL_FILTER (ptr: filter);
58 GValue value = G_VALUE_INIT;
59 gboolean result;
60
61 if (self->expression == NULL ||
62 !gtk_expression_evaluate (self: self->expression, this_: item, value: &value))
63 return FALSE;
64 result = g_value_get_boolean (value: &value);
65
66 g_value_unset (value: &value);
67
68 if (self->invert)
69 result = !result;
70
71 return result;
72}
73
74static GtkFilterMatch
75gtk_bool_filter_get_strictness (GtkFilter *filter)
76{
77 GtkBoolFilter *self = GTK_BOOL_FILTER (ptr: filter);
78
79 if (self->expression == NULL)
80 return GTK_FILTER_MATCH_NONE;
81
82 return GTK_FILTER_MATCH_SOME;
83}
84
85static void
86gtk_bool_filter_set_property (GObject *object,
87 guint prop_id,
88 const GValue *value,
89 GParamSpec *pspec)
90{
91 GtkBoolFilter *self = GTK_BOOL_FILTER (ptr: object);
92
93 switch (prop_id)
94 {
95 case PROP_EXPRESSION:
96 gtk_bool_filter_set_expression (self, expression: gtk_value_get_expression (value));
97 break;
98
99 case PROP_INVERT:
100 gtk_bool_filter_set_invert (self, invert: g_value_get_boolean (value));
101 break;
102
103 default:
104 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
105 break;
106 }
107}
108
109static void
110gtk_bool_filter_get_property (GObject *object,
111 guint prop_id,
112 GValue *value,
113 GParamSpec *pspec)
114{
115 GtkBoolFilter *self = GTK_BOOL_FILTER (ptr: object);
116
117 switch (prop_id)
118 {
119 case PROP_EXPRESSION:
120 gtk_value_set_expression (value, expression: self->expression);
121 break;
122
123 case PROP_INVERT:
124 g_value_set_boolean (value, v_boolean: self->invert);
125 break;
126
127 default:
128 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
129 break;
130 }
131}
132
133static void
134gtk_bool_filter_dispose (GObject *object)
135{
136 GtkBoolFilter *self = GTK_BOOL_FILTER (ptr: object);
137
138 g_clear_pointer (&self->expression, gtk_expression_unref);
139
140 G_OBJECT_CLASS (gtk_bool_filter_parent_class)->dispose (object);
141}
142
143static void
144gtk_bool_filter_class_init (GtkBoolFilterClass *class)
145{
146 GtkFilterClass *filter_class = GTK_FILTER_CLASS (ptr: class);
147 GObjectClass *object_class = G_OBJECT_CLASS (class);
148
149 filter_class->match = gtk_bool_filter_match;
150 filter_class->get_strictness = gtk_bool_filter_get_strictness;
151
152 object_class->get_property = gtk_bool_filter_get_property;
153 object_class->set_property = gtk_bool_filter_set_property;
154 object_class->dispose = gtk_bool_filter_dispose;
155
156 /**
157 * GtkBoolFilter:expression: (type GtkExpression) (attributes org.gtk.Property.get=gtk_bool_filter_get_expression org.gtk.Property.set=gtk_bool_filter_set_expression)
158 *
159 * The boolean expression to evaluate on item.
160 */
161 properties[PROP_EXPRESSION] =
162 gtk_param_spec_expression (name: "expression",
163 P_("Expression"),
164 P_("Expression to evaluate"),
165 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
166
167 /**
168 * GtkBoolFilter:invert: (attributes org.gtk.Property.get=gtk_bool_filter_get_invert org.gtk.Property.set=gtk_bool_filter_set_invert)
169 *
170 * If the expression result should be inverted.
171 */
172 properties[PROP_INVERT] =
173 g_param_spec_boolean (name: "invert",
174 P_("Invert"),
175 P_("If the expression result should be inverted"),
176 FALSE,
177 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
178
179 g_object_class_install_properties (oclass: object_class, n_pspecs: NUM_PROPERTIES, pspecs: properties);
180}
181
182static void
183gtk_bool_filter_init (GtkBoolFilter *self)
184{
185}
186
187/**
188 * gtk_bool_filter_new:
189 * @expression: (transfer full) (nullable): The expression to evaluate
190 *
191 * Creates a new bool filter.
192 *
193 * Returns: a new `GtkBoolFilter`
194 */
195GtkBoolFilter *
196gtk_bool_filter_new (GtkExpression *expression)
197{
198 GtkBoolFilter *result;
199
200 result = g_object_new (GTK_TYPE_BOOL_FILTER,
201 first_property_name: "expression", expression,
202 NULL);
203
204 g_clear_pointer (&expression, gtk_expression_unref);
205
206 return result;
207}
208
209/**
210 * gtk_bool_filter_get_expression: (attributes org.gtk.Method.get_property=expression)
211 * @self: a `GtkBoolFilter`
212 *
213 * Gets the expression that the filter uses to evaluate if
214 * an item should be filtered.
215 *
216 * Returns: (transfer none) (nullable): a `GtkExpression`
217 */
218GtkExpression *
219gtk_bool_filter_get_expression (GtkBoolFilter *self)
220{
221 g_return_val_if_fail (GTK_IS_BOOL_FILTER (self), NULL);
222
223 return self->expression;
224}
225
226/**
227 * gtk_bool_filter_set_expression: (attributes org.gtk.Method.set_property=expression)
228 * @self: a `GtkBoolFilter`
229 * @expression: (nullable): a `GtkExpression`
230 *
231 * Sets the expression that the filter uses to check if items
232 * should be filtered.
233 *
234 * The expression must have a value type of %G_TYPE_BOOLEAN.
235 */
236void
237gtk_bool_filter_set_expression (GtkBoolFilter *self,
238 GtkExpression *expression)
239{
240 g_return_if_fail (GTK_IS_BOOL_FILTER (self));
241 g_return_if_fail (expression == NULL || gtk_expression_get_value_type (expression) == G_TYPE_BOOLEAN);
242
243 if (self->expression == expression)
244 return;
245
246 g_clear_pointer (&self->expression, gtk_expression_unref);
247 if (expression)
248 self->expression = gtk_expression_ref (self: expression);
249
250 gtk_filter_changed (self: GTK_FILTER (ptr: self), change: GTK_FILTER_CHANGE_DIFFERENT);
251
252 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_EXPRESSION]);
253}
254
255/**
256 * gtk_bool_filter_get_invert: (attributes org.gtk.Method.get_property=invert)
257 * @self: a `GtkBoolFilter`
258 *
259 * Returns whether the filter inverts the expression.
260 *
261 * Returns: %TRUE if the filter inverts
262 */
263gboolean
264gtk_bool_filter_get_invert (GtkBoolFilter *self)
265{
266 g_return_val_if_fail (GTK_IS_BOOL_FILTER (self), TRUE);
267
268 return self->invert;
269}
270
271/**
272 * gtk_bool_filter_set_invert: (attributes org.gtk.Method.set_property=invert)
273 * @self: a `GtkBoolFilter`
274 * @invert: %TRUE to invert
275 *
276 * Sets whether the filter should invert the expression.
277 */
278void
279gtk_bool_filter_set_invert (GtkBoolFilter *self,
280 gboolean invert)
281{
282 g_return_if_fail (GTK_IS_BOOL_FILTER (self));
283
284 if (self->invert == invert)
285 return;
286
287 self->invert = invert;
288
289 gtk_filter_changed (self: GTK_FILTER (ptr: self), change: GTK_FILTER_CHANGE_DIFFERENT);
290
291 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_INVERT]);
292}
293
294

source code of gtk/gtk/gtkboolfilter.c