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 | |
34 | struct _GtkBoolFilter |
35 | { |
36 | GtkFilter parent_instance; |
37 | |
38 | gboolean invert; |
39 | GtkExpression *expression; |
40 | }; |
41 | |
42 | enum { |
43 | PROP_0, |
44 | PROP_EXPRESSION, |
45 | PROP_INVERT, |
46 | NUM_PROPERTIES |
47 | }; |
48 | |
49 | G_DEFINE_TYPE (GtkBoolFilter, gtk_bool_filter, GTK_TYPE_FILTER) |
50 | |
51 | static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; |
52 | |
53 | static gboolean |
54 | gtk_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 | |
74 | static GtkFilterMatch |
75 | gtk_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 | |
85 | static void |
86 | gtk_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 | |
109 | static void |
110 | gtk_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 | |
133 | static void |
134 | gtk_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 | |
143 | static void |
144 | gtk_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 | |
182 | static void |
183 | gtk_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 | */ |
195 | GtkBoolFilter * |
196 | gtk_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 | */ |
218 | GtkExpression * |
219 | gtk_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 | */ |
236 | void |
237 | gtk_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 | */ |
263 | gboolean |
264 | gtk_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 | */ |
278 | void |
279 | gtk_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 | |