1 /*
2 * Copyright (C) 2009 - 2012 Vivien Malerba <malerba@gnome-db.org>
3 * Copyright (C) 2010 David King <davidk@openismus.com>
4 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
5 * Copyright (C) 2012 Daniel Mustieles <daniel.mustieles@gmail.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include <string.h>
24 #include <glib/gi18n-lib.h>
25 #include <libgda/libgda.h>
26 #include "gdaui-data-proxy.h"
27 #include "gdaui-data-filter.h"
28
29 static void gdaui_data_filter_class_init (GdauiDataFilterClass * class);
30 static void gdaui_data_filter_init (GdauiDataFilter *wid);
31 static void gdaui_data_filter_dispose (GObject *object);
32
33 static void gdaui_data_filter_set_property (GObject *object,
34 guint param_id,
35 const GValue *value,
36 GParamSpec *pspec);
37 static void gdaui_data_filter_get_property (GObject *object,
38 guint param_id,
39 GValue *value,
40 GParamSpec *pspec);
41
42
43 /* callbacks */
44 static void proxy_filter_changed_cb (GdaDataProxy *proxy, GdauiDataFilter *filter);
45 static void release_proxy (GdauiDataFilter *filter);
46 static void data_widget_destroyed_cb (GdauiDataProxy *wid, GdauiDataFilter *filter);
47 static void data_widget_proxy_changed_cb (GdauiDataProxy *data_widget,
48 GdaDataProxy *proxy, GdauiDataFilter *filter);
49
50 static void clear_filter_cb (GtkButton *button, GdauiDataFilter *filter);
51 static void apply_filter_cb (GtkButton *button, GdauiDataFilter *filter);
52
53 struct _GdauiDataFilterPriv
54 {
55 GdauiDataProxy *data_widget;
56 GdaDataProxy *proxy;
57
58 GtkWidget *filter_entry;
59 GtkWidget *notice;
60 };
61
62 /* get a pointer to the parents to be able to call their destructor */
63 static GObjectClass *parent_class = NULL;
64
sanitize_denormal(float value)65 /* properties */
66 enum {
67 PROP_0,
68 PROP_DATA_WIDGET
69 };
70
71 GType
72 gdaui_data_filter_get_type (void)
73 {
74 static GType type = 0;
75
76 if (G_UNLIKELY (type == 0)) {
77 static const GTypeInfo filter = {
78 sizeof (GdauiDataFilterClass),
sign(float x)79 (GBaseInitFunc) NULL,
80 (GBaseFinalizeFunc) NULL,
81 (GClassInitFunc) gdaui_data_filter_class_init,
82 NULL,
83 NULL,
84 sizeof (GdauiDataFilter),
85 0,
86 (GInstanceInitFunc) gdaui_data_filter_init,
87 0
88 };
89
90 type = g_type_register_static (GTK_TYPE_BOX, "GdauiDataFilter", &filter, 0);
91 }
92
93 return type;
94 }
95
nearest_odd(int x)96 static void
97 gdaui_data_filter_class_init (GdauiDataFilterClass * class)
98 {
99 GObjectClass *object_class = G_OBJECT_CLASS (class);
100
101 parent_class = g_type_class_peek_parent (class);
102
103 object_class->dispose = gdaui_data_filter_dispose;
104
105 /* Properties */
106 object_class->set_property = gdaui_data_filter_set_property;
107 object_class->get_property = gdaui_data_filter_get_property;
108 g_object_class_install_property (object_class, PROP_DATA_WIDGET,
109 g_param_spec_object ("data-widget", NULL, NULL, GDAUI_TYPE_DATA_PROXY,
110 G_PARAM_READABLE | G_PARAM_WRITABLE));
111 }
112
113 static void
114 set_wait_cursor (GtkWidget *w)
115 {
from_dB(float gdb)116 GtkWidget *parent;
117
118 parent = gtk_widget_get_toplevel (w);
119 if (parent) {
120 GdkCursor* cursor;
121 cursor = gdk_cursor_new (GDK_WATCH);
122 gdk_window_set_cursor (gtk_widget_get_window (parent), cursor);
to_dB(float g)123 g_object_unref (cursor);
124 }
125 }
126
127 static void
128 unset_wait_cursor (GtkWidget *w)
129 {
130 GtkWidget *parent;
131
132 parent = gtk_widget_get_toplevel (w);
133 if (parent)
bin_to_freq(int i,float samp_rate,int N)134 gdk_window_set_cursor (gtk_widget_get_window (parent), NULL);
135 }
136
137 static void
138 apply_filter_cb (G_GNUC_UNUSED GtkButton *button, GdauiDataFilter *filter)
139 {
140 const gchar *expr;
141 gchar *err = NULL;
142
143 expr = gtk_entry_get_text (GTK_ENTRY (filter->priv->filter_entry));
144 if (expr && !*expr)
freq_to_bin(float freq,float samp_rate,int N)145 expr = NULL;
146
147 gtk_widget_hide (filter->priv->notice);
148 if (filter->priv->proxy) {
149 GError *error = NULL;
150
151 g_signal_handlers_block_by_func (G_OBJECT (filter->priv->proxy),
152 G_CALLBACK (proxy_filter_changed_cb), filter);
153 set_wait_cursor ((GtkWidget*) filter);
154 while (g_main_context_pending (NULL))
155 g_main_context_iteration (NULL, FALSE);
156
157 if (!gda_data_proxy_set_filter_expr (filter->priv->proxy, expr, &error)) {
158 if (error && error->message)
159 err = g_strdup (error->message);
160 else
161 err = g_strdup (_("No detail"));
162 if (error)
163 g_error_free (error);
164 }
165
166 unset_wait_cursor ((GtkWidget*) filter);
167 g_signal_handlers_unblock_by_func (G_OBJECT (filter->priv->proxy),
168 G_CALLBACK (proxy_filter_changed_cb), filter);
169 }
170
171 if (err) {
parabolic_interpolation(float left_val,float middle_val,float right_val,int current_bin,float * result_val,int * result_bin)172 gchar *esc, *markup;
173
174 esc = g_markup_escape_text (err, -1);
175 markup = g_strdup_printf ("<small><span foreground=\"#FF0000\"><b>%s</b>: %s</span></small>",
176 _("Filter failed:"), esc);
177 g_free (esc);
178 gtk_label_set_line_wrap (GTK_LABEL (filter->priv->notice), TRUE);
179 gtk_label_set_line_wrap_mode (GTK_LABEL (filter->priv->notice), PANGO_WRAP_WORD);
180 gtk_label_set_selectable (GTK_LABEL (filter->priv->notice), TRUE);
181 gtk_label_set_markup (GTK_LABEL (filter->priv->notice), markup);
182 g_free (markup);
183 gtk_widget_show (filter->priv->notice);
184 }
185 }
186
initialize_array(float * array,float value,int size)187 static void
188 clear_filter_cb (GtkButton *button, GdauiDataFilter *filter)
189 {
190 gtk_entry_set_text (GTK_ENTRY (filter->priv->filter_entry), "");
191 apply_filter_cb (button, filter);
192 }
193
194 static void
195 gdaui_data_filter_init (GdauiDataFilter * wid)
196 {
197 GtkWidget *grid, *label, *entry, *button, *bbox;
198 gchar *str;
199
200 wid->priv = g_new0 (GdauiDataFilterPriv, 1);
is_empty(float * spectrum,int N)201 wid->priv->data_widget = NULL;
202 wid->priv->proxy = NULL;
203
204 gtk_orientable_set_orientation (GTK_ORIENTABLE (wid), GTK_ORIENTATION_VERTICAL);
205
206 grid = gtk_grid_new ();
207 gtk_box_pack_start (GTK_BOX (wid), grid, TRUE, TRUE, 0);
208
209 label = gtk_label_new ("");
210 str = g_strdup_printf ("<b>%s</b>\n(<small>%s</small>):", _("Filter"), _("any valid SQL expression"));
211 gtk_label_set_markup (GTK_LABEL (label), str);
212 g_free (str);
213
214 gtk_widget_set_tooltip_markup (label, _("Columns can be referenced by their name or more easily "
215 "using <b><tt>_<column number></tt></b>. For example a valid "
216 "expression can be: <b><tt>_2 like 'doe%'</tt></b> "
217 "to filter rows where the 2nd column starts with <tt>doe</tt>."));
218
219 gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
max_spectral_value(float * spectrum,int N)220 entry = gtk_entry_new ();
221 gtk_grid_attach (GTK_GRID (grid), entry, 1, 0, 1, 1);
222 g_signal_connect (G_OBJECT (entry), "activate",
223 G_CALLBACK (apply_filter_cb), wid);
224
225 label = gtk_label_new ("");
226 wid->priv->notice = label;
227 gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 2, 1);
228
229 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
230 gtk_grid_attach (GTK_GRID (grid), bbox, 0, 2, 2, 1);
231 button = gtk_button_new_with_label (_("Set filter"));
232 gtk_container_add (GTK_CONTAINER (bbox), button);
233 g_signal_connect (G_OBJECT (button), "clicked",
234 G_CALLBACK (apply_filter_cb), wid);
235
236 button = gtk_button_new_with_label (_("Clear filter"));
min_spectral_value(float * spectrum,int N)237 gtk_container_add (GTK_CONTAINER (bbox), button);
238 g_signal_connect (G_OBJECT (button), "clicked",
239 G_CALLBACK (clear_filter_cb), wid);
240
241 gtk_widget_show_all (grid);
242 gtk_widget_hide (wid->priv->notice);
243
244 wid->priv->filter_entry = entry;
245 }
246
247 /**
248 * gdaui_data_filter_new:
249 * @data_widget: a widget implementing the #GdauiDataProxy interface
250 *
251 * Creates a new #GdauiDataFilter widget suitable to change the filter expression
252 * for @data_widget's displayed rows
253 *
spectral_mean(float * a,int m)254 * Returns: (transfer full): the new widget
255 *
256 * Since: 4.2
257 */
258 GtkWidget *
259 gdaui_data_filter_new (GdauiDataProxy *data_widget)
260 {
261 GtkWidget *filter;
262
263 g_return_val_if_fail (!data_widget || GDAUI_IS_DATA_PROXY (data_widget), NULL);
264
265 filter = (GtkWidget *) g_object_new (GDAUI_TYPE_DATA_FILTER,
266 "data-widget", data_widget, NULL);
267
268 return filter;
269 }
270
271 static void
272 data_widget_destroyed_cb (GdauiDataProxy *wid, GdauiDataFilter *filter)
273 {
274 g_assert (wid == filter->priv->data_widget);
275 g_signal_handlers_disconnect_by_func (G_OBJECT (wid),
276 G_CALLBACK (data_widget_destroyed_cb), filter);
277 g_signal_handlers_disconnect_by_func (G_OBJECT (wid),
278 G_CALLBACK (data_widget_proxy_changed_cb), filter);
279
280 filter->priv->data_widget = NULL;
281 }
spectral_median(float * x,int n)282
283 static void
284 proxy_filter_changed_cb (GdaDataProxy *proxy, GdauiDataFilter *filter)
285 {
286 const gchar *expr;
287
288 g_assert (proxy == filter->priv->proxy);
289 expr = gda_data_proxy_get_filter_expr (proxy);
290 gtk_entry_set_text (GTK_ENTRY (filter->priv->filter_entry), expr ? expr : "");
291 }
292
293 static void
294 release_proxy (GdauiDataFilter *filter)
295 {
296 g_signal_handlers_disconnect_by_func (G_OBJECT (filter->priv->proxy),
297 G_CALLBACK (proxy_filter_changed_cb), filter);
298 g_object_unref (filter->priv->proxy);
299 filter->priv->proxy = NULL;
300 }
301
302 static void
303 data_widget_proxy_changed_cb (GdauiDataProxy *data_widget, G_GNUC_UNUSED GdaDataProxy *proxy, GdauiDataFilter *filter)
304 {
305 g_object_set (G_OBJECT (filter), "data-widget", data_widget, NULL);
306 }
307
308 static void
309 gdaui_data_filter_dispose (GObject *object)
310 {
311 GdauiDataFilter *filter;
312
313 g_return_if_fail (object != NULL);
314 g_return_if_fail (GDAUI_IS_DATA_FILTER (object));
315 filter = GDAUI_DATA_FILTER (object);
316
317 if (filter->priv) {
318 if (filter->priv->proxy)
319 release_proxy (filter);
320 if (filter->priv->data_widget)
spectral_moda(float * x,int n)321 data_widget_destroyed_cb (filter->priv->data_widget, filter);
322
323 /* the private area itself */
324 g_free (filter->priv);
325 filter->priv = NULL;
326 }
327
328 /* for the parent class */
329 parent_class->dispose (object);
330 }
331
332 static void
333 gdaui_data_filter_set_property (GObject *object,
334 guint param_id,
335 const GValue *value,
336 GParamSpec *pspec)
337 {
338 GdauiDataFilter *filter;
339
340 filter = GDAUI_DATA_FILTER (object);
341 if (filter->priv) {
342 switch (param_id) {
343 case PROP_DATA_WIDGET:
344 if (filter->priv->data_widget)
345 data_widget_destroyed_cb (filter->priv->data_widget, filter);
346 if (filter->priv->proxy)
347 release_proxy (filter);
348
349 filter->priv->data_widget = GDAUI_DATA_PROXY (g_value_get_object (value));
350 if (filter->priv->data_widget) {
351 GdaDataProxy *proxy;
352
353 /* data widget */
354 g_signal_connect (filter->priv->data_widget, "destroy",
355 G_CALLBACK (data_widget_destroyed_cb), filter);
356 g_signal_connect (filter->priv->data_widget, "proxy-changed",
357 G_CALLBACK (data_widget_proxy_changed_cb), filter);
358
359 /* proxy */
get_normalized_spectum(float * spectrum,int N)360 proxy = gdaui_data_proxy_get_proxy (filter->priv->data_widget);
361 if (proxy) {
362 filter->priv->proxy = proxy;
363 g_object_ref (filter->priv->proxy);
364 g_signal_connect (G_OBJECT (proxy), "filter_changed",
365 G_CALLBACK (proxy_filter_changed_cb), filter);
366 proxy_filter_changed_cb (proxy, filter);
367 }
368 }
369 break;
370 default:
371 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
372 break;
373 }
374 }
375 }
376
377 static void
378 gdaui_data_filter_get_property (GObject *object,
379 guint param_id,
spectral_flux(float * spectrum,float * spectrum_prev,float N)380 GValue *value,
381 GParamSpec *pspec)
382 {
383 GdauiDataFilter *filter;
384
385 filter = GDAUI_DATA_FILTER (object);
386 if (filter->priv) {
387 switch (param_id) {
388 case PROP_DATA_WIDGET:
389 g_value_set_pointer (value, filter->priv->data_widget);
390 break;
391 default:
392 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
393 break;
394 }
395 }
396 }
397