1 /*
2 * Copyright (C) 2009 Bas Driessen <bas.driessen@xobas.com>
3 * Copyright (C) 2009 - 2012 Vivien Malerba <malerba@gnome-db.org>
4 * Copyright (C) 2010 David King <davidk@openismus.com>
5 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.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 <gdk/gdkkeysyms.h>
25 #include <libgda/libgda.h>
26 #include <libgda/gda-data-proxy.h>
27 #include <glib/gi18n-lib.h>
28 #include "gdaui-raw-form.h"
29 #include "gdaui-data-selector.h"
30 #include "gdaui-data-proxy.h"
31 #include "gdaui-basic-form.h"
32 #include "gdaui-data-filter.h"
33 #include "internal/utility.h"
34 #include "data-entries/gdaui-entry-shell.h"
35 #include <libgda/gda-debug-macros.h>
36
37 static void gdaui_raw_form_class_init (GdauiRawFormClass * class);
38 static void gdaui_raw_form_init (GdauiRawForm *wid);
39 static void gdaui_raw_form_dispose (GObject *object);
40
41 static void gdaui_raw_form_set_property (GObject *object,
42 guint param_id,
43 const GValue *value,
44 GParamSpec *pspec);
45 static void gdaui_raw_form_get_property (GObject *object,
show_providers(GdauiProviderSelector * selector)46 guint param_id,
47 GValue *value,
48 GParamSpec *pspec);
49
50 static GError *iter_validate_set_cb (GdaDataModelIter *iter, GdauiRawForm *form);
51 static void iter_row_changed_cb (GdaDataModelIter *iter, gint row, GdauiRawForm *form);
52 static void proxy_changed_cb (GdaDataProxy *proxy, GdauiRawForm *form);
53 static void proxy_reset_cb (GdaDataProxy *proxy, GdauiRawForm *form);
54 static void proxy_access_changed_cb (GdaDataProxy *proxy, GdauiRawForm *form);
55 static void proxy_row_inserted_or_removed_cb (GdaDataProxy *proxy, gint row, GdauiRawForm *form);
gdaui_provider_selector_show(GtkWidget * widget)56
57 /* GdauiDataProxy interface */
58 static void gdaui_raw_form_widget_init (GdauiDataProxyIface *iface);
59 static GdaDataProxy *gdaui_raw_form_get_proxy (GdauiDataProxy *iface);
60 static void gdaui_raw_form_set_column_editable (GdauiDataProxy *iface, gint column, gboolean editable);
61 static void gdaui_raw_form_show_column_actions (GdauiDataProxy *iface, gint column, gboolean show_actions);
62 static GtkActionGroup *gdaui_raw_form_get_actions_group (GdauiDataProxy *iface);
63 static gboolean gdaui_raw_form_widget_set_write_mode (GdauiDataProxy *iface, GdauiDataProxyWriteMode mode);
64 static GdauiDataProxyWriteMode gdaui_raw_form_widget_get_write_mode (GdauiDataProxy *iface);
65
66 /* GdauiDataSelector interface */
67 static void gdaui_raw_form_selector_init (GdauiDataSelectorIface *iface);
68 static GdaDataModel *gdaui_raw_form_selector_get_model (GdauiDataSelector *iface);
69 static void gdaui_raw_form_selector_set_model (GdauiDataSelector *iface, GdaDataModel *model);
70 static GArray *gdaui_raw_form_selector_get_selected_rows (GdauiDataSelector *iface);
71 static GdaDataModelIter *gdaui_raw_form_selector_get_data_set (GdauiDataSelector *iface);
72 static gboolean gdaui_raw_form_selector_select_row (GdauiDataSelector *iface, gint row);
73 static void gdaui_raw_form_selector_unselect_row (GdauiDataSelector *iface, gint row);
74 static void gdaui_raw_form_selector_set_column_visible (GdauiDataSelector *iface, gint column, gboolean visible);
75
gdaui_provider_selector_class_init(GdauiProviderSelectorClass * klass)76 struct _GdauiRawFormPriv
77 {
78 GdaDataModel *data_model;
79 GdaDataProxy *proxy; /* proxy for @model */
80 GdaDataModelIter *iter; /* proxy's iter */
81
82 GdauiDataProxyWriteMode write_mode;
83
84 GtkActionGroup *actions_group;
85
86 GtkWidget *filter;
87 GtkWidget *filter_window;
88 };
89
90 #define PAGE_NO_DATA 0
91 #define PAGE_FORM 1
92
93 /* get a pointer to the parents to be able to call their destructor */
94 static GObjectClass *parent_class = NULL;
95
96 /* properties */
gdaui_provider_selector_finalize(GObject * object)97 enum {
98 PROP_0,
99 PROP_MODEL,
100 };
101
102 GType
103 gdaui_raw_form_get_type (void)
104 {
105 static GType type = 0;
106
107 if (G_UNLIKELY (type == 0)) {
108 static const GTypeInfo info = {
109 sizeof (GdauiRawFormClass),
gdaui_provider_selector_get_type(void)110 (GBaseInitFunc) NULL,
111 (GBaseFinalizeFunc) NULL,
112 (GClassInitFunc) gdaui_raw_form_class_init,
113 NULL,
114 NULL,
115 sizeof (GdauiRawForm),
116 0,
117 (GInstanceInitFunc) gdaui_raw_form_init,
118 0
119 };
120
121 static const GInterfaceInfo proxy_info = {
122 (GInterfaceInitFunc) gdaui_raw_form_widget_init,
123 NULL,
124 NULL
125 };
126
127 static const GInterfaceInfo selector_info = {
128 (GInterfaceInitFunc) gdaui_raw_form_selector_init,
129 NULL,
130 NULL
131 };
132
133 type = g_type_register_static (GDAUI_TYPE_BASIC_FORM, "GdauiRawForm", &info, 0);
134 g_type_add_interface_static (type, GDAUI_TYPE_DATA_PROXY, &proxy_info);
135 g_type_add_interface_static (type, GDAUI_TYPE_DATA_SELECTOR, &selector_info);
136 }
137
138 return type;
139 }
gdaui_provider_selector_new(void)140
141 static void
142 gdaui_raw_form_widget_init (GdauiDataProxyIface *iface)
143 {
144 iface->get_proxy = gdaui_raw_form_get_proxy;
145 iface->set_column_editable = gdaui_raw_form_set_column_editable;
146 iface->show_column_actions = gdaui_raw_form_show_column_actions;
147 iface->get_actions_group = gdaui_raw_form_get_actions_group;
148 iface->set_write_mode = gdaui_raw_form_widget_set_write_mode;
149 iface->get_write_mode = gdaui_raw_form_widget_get_write_mode;
150 }
151
152 static void
153 gdaui_raw_form_selector_init (GdauiDataSelectorIface *iface)
154 {
155 iface->get_model = gdaui_raw_form_selector_get_model;
156 iface->set_model = gdaui_raw_form_selector_set_model;
157 iface->get_selected_rows = gdaui_raw_form_selector_get_selected_rows;
158 iface->get_data_set = gdaui_raw_form_selector_get_data_set;
gdaui_provider_selector_get_provider(GdauiProviderSelector * selector)159 iface->select_row = gdaui_raw_form_selector_select_row;
160 iface->unselect_row = gdaui_raw_form_selector_unselect_row;
161 iface->set_column_visible = gdaui_raw_form_selector_set_column_visible;
162 }
163
164 static void
165 basic_form_layout_changed (GdauiBasicForm *bform)
166 {
167 GdauiRawForm *form = GDAUI_RAW_FORM (bform);
168 iter_row_changed_cb (form->priv->iter, gda_data_model_iter_get_row (form->priv->iter), form);
169 }
170
171 static void
172 gdaui_raw_form_class_init (GdauiRawFormClass *class)
173 {
174 GObjectClass *object_class = G_OBJECT_CLASS (class);
175
176 parent_class = g_type_class_peek_parent (class);
177 object_class->dispose = gdaui_raw_form_dispose;
178 GDAUI_BASIC_FORM_CLASS (class)->layout_changed = basic_form_layout_changed;
179
180 /* Properties */
181 object_class->set_property = gdaui_raw_form_set_property;
182 object_class->get_property = gdaui_raw_form_get_property;
183 g_object_class_install_property (object_class, PROP_MODEL,
184 g_param_spec_object ("model", _("Data to display"),
185 NULL, GDA_TYPE_DATA_MODEL,
186 G_PARAM_READABLE | G_PARAM_WRITABLE));
gdaui_provider_selector_set_provider(GdauiProviderSelector * selector,const gchar * provider)187 }
188
189 static void action_new_cb (GtkAction *action, GdauiRawForm *form);
190 static void action_delete_cb (GtkToggleAction *action, GdauiRawForm *form);
191 static void action_commit_cb (GtkAction *action, GdauiRawForm *form);
192 static void action_reset_cb (GtkAction *action, GdauiRawForm *form);
193 static void action_first_record_cb (GtkAction *action, GdauiRawForm *form);
194 static void action_prev_record_cb (GtkAction *action, GdauiRawForm *form);
195 static void action_next_record_cb (GtkAction *action, GdauiRawForm *form);
196 static void action_last_record_cb (GtkAction *action, GdauiRawForm *form);
197 static void action_filter_cb (GtkAction *action, GdauiRawForm *form);
198
199 static GtkToggleActionEntry ui_actions_t[] = {
200 { "ActionDelete", GTK_STOCK_REMOVE, "_Delete", NULL, N_("Delete the current record"), G_CALLBACK (action_delete_cb), FALSE},
201 };
202
203 static GtkActionEntry ui_actions[] = {
204 { "ActionNew", GTK_STOCK_ADD, "_New", NULL, N_("Create a new record"), G_CALLBACK (action_new_cb)},
205 { "ActionCommit", GTK_STOCK_SAVE, "_Commit", NULL, N_("Commit the modifications"), G_CALLBACK (action_commit_cb)},
206 { "ActionReset", GTK_STOCK_CLEAR, "_Clear", NULL, N_("Clear all the modifications"), G_CALLBACK (action_reset_cb)},
207 { "ActionFirstRecord", GTK_STOCK_GOTO_FIRST, "_First record", NULL, N_("Go to first record"), G_CALLBACK (action_first_record_cb)},
208 { "ActionLastRecord", GTK_STOCK_GOTO_LAST, "_Last record", NULL, N_("Go to last record"), G_CALLBACK (action_last_record_cb)},
209 { "ActionPrevRecord", GTK_STOCK_GO_BACK, "_Previous record", NULL, N_("Go to previous record"), G_CALLBACK (action_prev_record_cb)},
210 { "ActionNextRecord", GTK_STOCK_GO_FORWARD, "Ne_xt record", NULL, N_("Go to next record"), G_CALLBACK (action_next_record_cb)},
211 { "ActionFilter", GTK_STOCK_FIND, "Filter", NULL, N_("Filter records"), G_CALLBACK (action_filter_cb)}
212 };
213
214 static void
215 action_new_activated_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *wid)
216 {
217 /* make the first entry grab the focus */
218 if (wid->priv->iter && GDA_SET (wid->priv->iter)->holders)
gdaui_provider_selector_get_provider_obj(GdauiProviderSelector * selector)219 gdaui_basic_form_entry_grab_focus (GDAUI_BASIC_FORM (wid),
220 (GdaHolder *)
221 GDA_SET (wid->priv->iter)->holders->data);
222 }
223
224 static void
225 form_activated_cb (GdauiRawForm *form, G_GNUC_UNUSED gpointer data)
226 {
227 if (form->priv->write_mode == GDAUI_DATA_PROXY_WRITE_ON_VALUE_ACTIVATED) {
228 gint row;
229
230 row = gda_data_model_iter_get_row (form->priv->iter);
231 if (row >= 0) {
232 /* write back the current row */
233 if (gda_data_proxy_row_has_changed (form->priv->proxy, row)) {
234 GError *error = NULL;
235 if (!gda_data_proxy_apply_row_changes (form->priv->proxy, row, &error)) {
236 gboolean discard;
237 discard = _gdaui_utility_display_error_with_keep_or_discard_choice ((GdauiDataProxy *) form,
238 error);
239 if (discard)
240 gda_data_proxy_cancel_row_changes (form->priv->proxy, row, -1);
241 g_error_free (error);
242 }
243 }
244 }
245 }
246 }
247
248 static void
249 form_holder_changed_cb (GdauiRawForm *form, G_GNUC_UNUSED gpointer data)
250 {
251 if (form->priv->write_mode == GDAUI_DATA_PROXY_WRITE_ON_VALUE_CHANGE) {
252 gint row;
253
254 row = gda_data_model_iter_get_row (form->priv->iter);
255 if (row >= 0) {
256 /* write back the current row */
257 if (gda_data_proxy_row_has_changed (form->priv->proxy, row)) {
258 GError *error = NULL;
259 if (!gda_data_proxy_apply_row_changes (form->priv->proxy, row, &error)) {
260 _gdaui_utility_display_error ((GdauiDataProxy *) form, TRUE, error);
261 if (error)
262 g_error_free (error);
263 }
264 }
265 }
266 }
267 }
268
269 static void
270 gdaui_raw_form_init (GdauiRawForm *wid)
271 {
272 GtkAction *action;
273 wid->priv = g_new0 (GdauiRawFormPriv, 1);
274
275 wid->priv->data_model = NULL;
276 wid->priv->proxy = NULL;
277 wid->priv->iter = NULL;
278 wid->priv->write_mode = GDAUI_DATA_PROXY_WRITE_ON_DEMAND;
279
280 g_signal_connect (G_OBJECT (wid), "activated",
281 G_CALLBACK (form_activated_cb), NULL);
282 g_signal_connect (G_OBJECT (wid), "holder-changed",
283 G_CALLBACK (form_holder_changed_cb), NULL);
284
285 /* action group */
286 wid->priv->actions_group = gtk_action_group_new ("Actions");
287 gtk_action_group_set_translation_domain (wid->priv->actions_group, GETTEXT_PACKAGE);
288
289 gtk_action_group_add_actions (wid->priv->actions_group, ui_actions, G_N_ELEMENTS (ui_actions), wid);
290 gtk_action_group_add_toggle_actions (wid->priv->actions_group, ui_actions_t, G_N_ELEMENTS (ui_actions_t), wid);
291 action = gtk_action_group_get_action (wid->priv->actions_group, "ActionNew");
292 g_signal_connect (G_OBJECT (action), "activate",
293 G_CALLBACK (action_new_activated_cb), wid);
294
295 wid->priv->filter = NULL;
296 wid->priv->filter_window = NULL;
297
298 /* raw forms' default unknown color */
299 gdaui_basic_form_set_unknown_color ((GdauiBasicForm*) wid, -1., -1., -1., -1.);
300 }
301
302 /**
303 * gdaui_raw_form_new:
304 * @model: (allow-none): a #GdaDataModel, or %NULL
305 *
306 * Creates a new #GdauiRawForm widget to display data in @model
307 *
308 * Returns: (transfer full): the new widget
309 *
310 * Since: 4.2
311 */
312 GtkWidget *
313 gdaui_raw_form_new (GdaDataModel *model)
314 {
315 GObject *obj;
316
317 obj = g_object_new (GDAUI_TYPE_RAW_FORM, "model", model, NULL);
318
319 return GTK_WIDGET (obj);
320 }
321
322 static void gdaui_raw_form_clean (GdauiRawForm *form);
323 static void
324 gdaui_raw_form_dispose (GObject *object)
325 {
326 GdauiRawForm *form;
327
328 g_return_if_fail (object != NULL);
329 g_return_if_fail (GDAUI_IS_RAW_FORM (object));
330 form = GDAUI_RAW_FORM (object);
331
332 if (form->priv) {
333 gdaui_raw_form_clean (form);
334
335 if (form->priv->filter)
336 gtk_widget_destroy (form->priv->filter);
337 if (form->priv->filter_window)
338 gtk_widget_destroy (form->priv->filter_window);
339
340 /* UI */
341 if (form->priv->actions_group)
342 g_object_unref (G_OBJECT (form->priv->actions_group));
343
344 /* the private area itself */
345 g_free (form->priv);
346 form->priv = NULL;
347 }
348
349 /* for the parent class */
350 parent_class->dispose (object);
351 }
352
353 static void
354 gdaui_raw_form_set_property (GObject *object,
355 guint param_id,
356 const GValue *value,
357 GParamSpec *pspec)
358 {
359 GdauiRawForm *form;
360
361 form = GDAUI_RAW_FORM (object);
362 if (form->priv) {
363 switch (param_id) {
364 case PROP_MODEL: {
365 GdaDataModel *model = (GdaDataModel*) g_value_get_object (value);
366
367 if (model)
368 g_return_if_fail (GDA_IS_DATA_MODEL (model));
369 else
370 return;
371
372 if (form->priv->proxy) {
373 /* data model has been changed */
374 if (GDA_IS_DATA_PROXY (model)) {
375 /* clean all */
376 gdaui_raw_form_clean (form);
377 g_assert (!form->priv->proxy);
378 }
379 else
380 g_object_set (G_OBJECT (form->priv->proxy), "model", model, NULL);
381 }
382
383 if (!form->priv->proxy) {
384 /* first time setting */
385 if (GDA_IS_DATA_PROXY (model))
386 form->priv->proxy = g_object_ref (G_OBJECT (model));
387 else
388 form->priv->proxy = GDA_DATA_PROXY (gda_data_proxy_new (model));
389 form->priv->data_model = gda_data_proxy_get_proxied_model (form->priv->proxy);
390 form->priv->iter = gda_data_model_create_iter (GDA_DATA_MODEL (form->priv->proxy));
391 gda_data_model_iter_move_to_row (form->priv->iter, 0);
392
393 g_signal_connect (form->priv->iter, "validate-set",
394 G_CALLBACK (iter_validate_set_cb), form);
395 g_signal_connect (form->priv->iter, "row-changed",
396 G_CALLBACK (iter_row_changed_cb), form);
397
398 g_signal_connect (G_OBJECT (form->priv->proxy), "row_inserted",
399 G_CALLBACK (proxy_row_inserted_or_removed_cb), form);
400 g_signal_connect (G_OBJECT (form->priv->proxy), "row_removed",
401 G_CALLBACK (proxy_row_inserted_or_removed_cb), form);
402 g_signal_connect (G_OBJECT (form->priv->proxy), "changed",
403 G_CALLBACK (proxy_changed_cb), form);
404 g_signal_connect (G_OBJECT (form->priv->proxy), "reset",
405 G_CALLBACK (proxy_reset_cb), form);
406 g_signal_connect (G_OBJECT (form->priv->proxy), "access-changed",
407 G_CALLBACK (proxy_access_changed_cb), form);
408
409 g_object_set (object, "paramlist", form->priv->iter, NULL);
410
411 /* we don't want chuncking */
412 gda_data_proxy_set_sample_size (form->priv->proxy, 0);
413
414 /* handle invalid iterators' GdaHolder */
415 GSList *list;
416 for (list = GDA_SET (form->priv->iter)->holders; list; list = list->next) {
417 GtkWidget *entry;
418 entry = gdaui_basic_form_get_entry_widget (GDAUI_BASIC_FORM (form),
419 (GdaHolder*) list->data);
420 if (entry)
421 gdaui_entry_shell_set_unknown ((GdauiEntryShell*) entry,
422 !gda_holder_is_valid ((GdaHolder*) list->data));
423 }
424
425 iter_row_changed_cb (form->priv->iter,
426 gda_data_model_iter_get_row (form->priv->iter), form);
427
428 /* actions */
429 if (gda_data_proxy_is_read_only (form->priv->proxy))
430 g_object_set ((GObject*) form, "show-actions", FALSE, NULL);
431
432 /* data display update */
433 proxy_changed_cb (form->priv->proxy, form);
434
435 gdaui_raw_form_widget_set_write_mode ((GdauiDataProxy *) form,
436 form->priv->write_mode);
437
438 g_signal_emit_by_name (object, "proxy-changed", form->priv->proxy);
439 }
440 break;
441 }
442 default:
443 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
444 break;
445 }
446 }
447 }
448
449 static void
450 gdaui_raw_form_get_property (GObject *object,
451 guint param_id,
452 GValue *value,
453 GParamSpec *pspec)
454 {
455 GdauiRawForm *form;
456
457 form = GDAUI_RAW_FORM (object);
458 if (form->priv) {
459 switch (param_id) {
460 case PROP_MODEL:
461 g_value_set_object(value, form->priv->data_model);
462 default:
463 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
464 break;
465 }
466 }
467 }
468
469 static GError *
470 iter_validate_set_cb (GdaDataModelIter *iter, GdauiRawForm *form)
471 {
472 GError *error = NULL;
473 gint row = gda_data_model_iter_get_row (iter);
474
475 if (row < 0)
476 return NULL;
477
478 if ((form->priv->write_mode >= GDAUI_DATA_PROXY_WRITE_ON_ROW_CHANGE) &&
479 /* write back the current row */
480 gda_data_proxy_row_has_changed (form->priv->proxy, row) &&
481 !gda_data_proxy_apply_row_changes (form->priv->proxy, row, &error)) {
482 if (_gdaui_utility_display_error_with_keep_or_discard_choice ((GdauiDataProxy *) form,
483 error)) {
484 gda_data_proxy_cancel_row_changes (form->priv->proxy, row, -1);
485 if (error) {
486 g_error_free (error);
487 error = NULL;
488 }
489 }
490 }
491
492 return error;
493 }
494
495 static void
496 iter_row_changed_cb (GdaDataModelIter *iter, gint row, GdauiRawForm *form)
497 {
498 gdaui_basic_form_set_as_reference (GDAUI_BASIC_FORM (form));
499
500 gtk_widget_set_sensitive (GTK_WIDGET (form), (row == -1) ? FALSE : TRUE);
501 if (row >= 0) {
502 GSList *params;
503 guint attributes;
504 GdaHolder *param;
505 gint i;
506
507 for (i = 0, params = ((GdaSet *) iter)->holders; params; i++, params = params->next) {
508 param = (GdaHolder *) params->data;
509 attributes = gda_data_proxy_get_value_attributes (form->priv->proxy, row, i);
510 gdaui_basic_form_entry_set_editable ((GdauiBasicForm *) form,
511 param, !(attributes & GDA_VALUE_ATTR_NO_MODIF));
512 }
513 }
514 g_signal_emit_by_name (G_OBJECT (form), "selection-changed");
515 }
516
517 static void
518 proxy_changed_cb (G_GNUC_UNUSED GdaDataProxy *proxy, GdauiRawForm *form)
519 {
520 /* TO remove ? */
521 gtk_widget_set_sensitive (GTK_WIDGET (form),
522 gda_data_model_get_n_rows (GDA_DATA_MODEL (form->priv->proxy)) == 0 ? FALSE : TRUE);
523 }
524
525 static gboolean
526 model_reset_was_soft (GdauiRawForm *form, GdaDataModel *new_model)
527 {
528 GdaDataModelIter *iter;
529 gboolean retval = FALSE;
530
531 if (!new_model)
532 return FALSE;
533 else if (new_model == (GdaDataModel*) form->priv->proxy)
534 return TRUE;
535 else if (!form->priv->iter)
536 return FALSE;
537
538 iter = gda_data_model_create_iter (new_model);
539 retval = ! _gdaui_utility_iter_differ (form->priv->iter, iter);
540 g_object_unref (iter);
541 return retval;
542 }
543
544 static void
545 gdaui_raw_form_clean (GdauiRawForm *form)
546 {
547 /* proxy's iterator */
548 if (form->priv->iter) {
549 g_signal_handlers_disconnect_by_func (form->priv->iter,
550 G_CALLBACK (iter_row_changed_cb), form);
551 g_signal_handlers_disconnect_by_func (form->priv->iter,
552 G_CALLBACK (iter_validate_set_cb), form);
553 g_object_unref (form->priv->iter);
554 form->priv->iter = NULL;
555 }
556
557 /* proxy */
558 if (form->priv->proxy) {
559 g_signal_handlers_disconnect_by_func (G_OBJECT (form->priv->proxy),
560 G_CALLBACK (proxy_row_inserted_or_removed_cb), form);
561 g_signal_handlers_disconnect_by_func (G_OBJECT (form->priv->proxy),
562 G_CALLBACK (proxy_changed_cb), form);
563 g_signal_handlers_disconnect_by_func (G_OBJECT (form->priv->proxy),
564 G_CALLBACK (proxy_reset_cb), form);
565 g_signal_handlers_disconnect_by_func (G_OBJECT (form->priv->proxy),
566 G_CALLBACK (proxy_access_changed_cb), form);
567 g_object_unref (form->priv->proxy);
568 form->priv->proxy = NULL;
569 }
570 }
571
572 static void
573 proxy_reset_cb (GdaDataProxy *proxy, GdauiRawForm *form)
574 {
575 gint iter_row;
576 gboolean reset_soft;
577
578 iter_row = gda_data_model_iter_get_row (form->priv->iter);
579 reset_soft = model_reset_was_soft (form, gda_data_proxy_get_proxied_model (form->priv->proxy));
580
581 if (iter_row >= 0)
582 gda_data_model_iter_move_to_row (form->priv->iter, iter_row);
583 else
584 gda_data_model_iter_move_to_row (form->priv->iter, 0);
585
586 form->priv->data_model = gda_data_proxy_get_proxied_model (form->priv->proxy);
587 iter_row_changed_cb (form->priv->iter, gda_data_model_iter_get_row (form->priv->iter), form);
588
589 if (! reset_soft)
590 g_signal_emit_by_name (form, "proxy-changed", form->priv->proxy);
591 }
592
593 static void
594 proxy_access_changed_cb (G_GNUC_UNUSED GdaDataProxy *proxy, GdauiRawForm *form)
595 {
596 iter_row_changed_cb (form->priv->iter, gda_data_model_iter_get_row (form->priv->iter), form);
597 }
598
599 static void
600 proxy_row_inserted_or_removed_cb (G_GNUC_UNUSED GdaDataProxy *proxy, gint row, GdauiRawForm *form)
601 {
602 if (gda_data_model_get_n_rows (GDA_DATA_MODEL (form->priv->proxy)) != 0)
603 if (gda_data_model_iter_get_row (form->priv->iter) == -1)
604 gda_data_model_iter_move_to_row (form->priv->iter, row > 0 ? row - 1 : 0);
605 }
606
607 /*
608 *
609 * Modification buttons (Commit changes, Reset form, New entry, Delete)
610 *
611 */
612 static void
613 action_new_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
614 {
615 gint newrow;
616 GError *error = NULL;
617 GSList *list;
618
619 if (form->priv->write_mode >= GDAUI_DATA_PROXY_WRITE_ON_ROW_CHANGE) {
620 /* validate current row (forces calling iter_validate_set_cb()) */
621 if (gda_data_model_iter_is_valid (form->priv->iter) &&
622 ! gda_set_is_valid (GDA_SET (form->priv->iter), NULL))
623 return;
624 }
625
626 /* append a row in the proxy */
627 g_signal_handlers_block_by_func (form, G_CALLBACK (form_holder_changed_cb), NULL);
628 newrow = gda_data_model_append_row (GDA_DATA_MODEL (form->priv->proxy), &error);
629 if (newrow == -1) {
630 g_warning (_("Can't append row to data model: %s"),
631 error && error->message ? error->message : _("Unknown error"));
632 g_error_free (error);
633 g_signal_handlers_unblock_by_func (form, G_CALLBACK (form_holder_changed_cb), NULL);
634 return;
635 }
636
637 if (!gda_data_model_iter_move_to_row (form->priv->iter, newrow)) {
638 g_warning ("Can't set GdaDataModelIterator on new row");
639 g_signal_handlers_unblock_by_func (form, G_CALLBACK (form_holder_changed_cb), NULL);
640 return;
641 }
642
643 /* set parameters to their default values */
644 for (list = GDA_SET (form->priv->iter)->holders; list; list = list->next) {
645 GdaHolder *param;
646 const GValue *value;
647
648 g_object_get (G_OBJECT (list->data), "full_bind", ¶m, NULL);
649 if (! param) {
650 value = gda_holder_get_default_value (GDA_HOLDER (list->data));
651 if (value)
652 gda_holder_set_value_to_default (GDA_HOLDER (list->data));
653 }
654 else
655 g_object_unref (param);
656 }
657
658 g_signal_handlers_unblock_by_func (form, G_CALLBACK (form_holder_changed_cb), NULL);
659 form_holder_changed_cb (form, NULL);
660 }
661
662 static void
663 action_delete_cb (GtkToggleAction *action, GdauiRawForm *form)
664 {
665 if (gtk_toggle_action_get_active (action)) {
666 gint row;
667 row = gda_data_model_iter_get_row (form->priv->iter);
668 g_return_if_fail (row >= 0);
669 gda_data_proxy_delete (form->priv->proxy, row);
670
671 if (form->priv->write_mode >= GDAUI_DATA_PROXY_WRITE_ON_ROW_CHANGE) {
672 /* force the proxy to apply the current row deletion */
673 gint newrow;
674
675 newrow = gda_data_model_iter_get_row (form->priv->iter);
676 if (row == newrow) {/* => row has been marked as delete but not yet really deleted */
677 GError *error = NULL;
678 if (!gda_data_proxy_apply_row_changes (form->priv->proxy, row, &error)) {
679 _gdaui_utility_display_error ((GdauiDataProxy *) form, TRUE, error);
680 if (error)
681 g_error_free (error);
682 }
683 }
684 }
685 }
686 else {
687 gint row;
688
689 row = gda_data_model_iter_get_row (form->priv->iter);
690 g_return_if_fail (row >= 0);
691 gda_data_proxy_undelete (form->priv->proxy, row);
692 }
693 }
694
695 static void
696 action_commit_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
697 {
698 gint row;
699 GError *error = NULL;
700 gboolean allok = TRUE;
701 gint mod1, mod2;
702
703 mod1 = gda_data_proxy_get_n_modified_rows (form->priv->proxy);
704 row = gda_data_model_iter_get_row (form->priv->iter);
705 if (form->priv->write_mode >= GDAUI_DATA_PROXY_WRITE_ON_ROW_CHANGE) {
706 gint newrow;
707
708 allok = gda_data_proxy_apply_row_changes (form->priv->proxy, row, &error);
709 if (allok) {
710 newrow = gda_data_model_iter_get_row (form->priv->iter);
711 if (row != newrow) /* => current row has changed because the proxy had to emit a "row_removed" when
712 actually succeeded the commit
713 => we need to come back to that row
714 */
715 gda_data_model_iter_move_to_row (form->priv->iter, row);
716 }
717 }
718 else
719 allok = gda_data_proxy_apply_all_changes (form->priv->proxy, &error);
720
721 mod2 = gda_data_proxy_get_n_modified_rows (form->priv->proxy);
722 if (!allok) {
723 if (mod1 != mod2)
724 /* the data model has changed while doing the writing */
725 _gdaui_utility_display_error ((GdauiDataProxy *) form, FALSE, error);
726 else
727 _gdaui_utility_display_error ((GdauiDataProxy *) form, TRUE, error);
728 g_error_free (error);
729 }
730
731 /* get to a correct selected row */
732 for (; (row >= 0) &&!gda_data_model_iter_move_to_row (form->priv->iter, row); row--);
733 }
734
735 static void
736 action_reset_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
737 {
738 gda_data_proxy_cancel_all_changes (form->priv->proxy);
739 gda_data_model_send_hint (GDA_DATA_MODEL (form->priv->proxy), GDA_DATA_MODEL_HINT_REFRESH, NULL);
740 }
741
742 static void arrow_actions_real_do (GdauiRawForm *form, gint movement);
743 static void
744 action_first_record_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
745 {
746 arrow_actions_real_do (form, -2);
747 }
748
749 static void
750 action_prev_record_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
751 {
752 arrow_actions_real_do (form, -1);
753 }
754
755 static void
756 action_next_record_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
757 {
758 arrow_actions_real_do (form, 1);
759 }
760
761 static void
762 action_last_record_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
763 {
764 arrow_actions_real_do (form, 2);
765 }
766
767 static void
768 hide_filter_window (GdauiRawForm *form)
769 {
770 gtk_widget_hide (form->priv->filter_window);
771 gtk_grab_remove (form->priv->filter_window);
772 }
773
774 static gboolean
775 filter_event (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkEventAny *event, GdauiRawForm *form)
776 {
777 hide_filter_window (form);
778 return TRUE;
779 }
780
781 static gboolean
782 key_press_filter_event (G_GNUC_UNUSED GtkWidget *widget, GdkEventKey *event, GdauiRawForm *form)
783 {
784 if (event->keyval == GDK_KEY_Escape ||
785 event->keyval == GDK_KEY_Tab ||
786 event->keyval == GDK_KEY_KP_Tab ||
787 event->keyval == GDK_KEY_ISO_Left_Tab) {
788 hide_filter_window (form);
789 return TRUE;
790 }
791 return FALSE;
792 }
793
794 static void
795 filter_position_func (GtkWidget *widget,
796 GtkWidget *search_dialog,
797 G_GNUC_UNUSED gpointer user_data)
798 {
799 gint x, y;
800 gint tree_x, tree_y;
801 gint tree_width, tree_height;
802 GdkWindow *window;
803 GdkScreen *screen;
804 GtkRequisition requisition;
805 gint monitor_num;
806 GdkRectangle monitor;
807
808 window = gtk_widget_get_window (widget);
809 screen = gdk_window_get_screen (window);
810 monitor_num = gdk_screen_get_monitor_at_window (screen, window);
811 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
812
813 gtk_widget_realize (search_dialog);
814
815 gdk_window_get_origin (window, &tree_x, &tree_y);
816 tree_width = gdk_window_get_width (window);
817 tree_height = gdk_window_get_height (window);
818 gtk_widget_get_preferred_size (search_dialog, NULL, &requisition);
819
820 if (tree_x + tree_width > gdk_screen_get_width (screen))
821 x = gdk_screen_get_width (screen) - requisition.width;
822 else if (tree_x + tree_width - requisition.width < 0)
823 x = 0;
824 else
825 x = tree_x + tree_width - requisition.width;
826
827 if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
828 y = gdk_screen_get_height (screen) - requisition.height;
829 else if (tree_y + tree_height < 0) /* isn't really possible ... */
830 y = 0;
831 else
832 y = tree_y + tree_height;
833
834 gtk_window_move (GTK_WINDOW (search_dialog), x, y);
835 }
836
837 static gboolean
838 popup_grab_on_window (GtkWidget *widget, guint32 activate_time)
839 {
840 GdkDeviceManager *manager;
841 GdkDevice *pointer;
842 GdkWindow *window;
843 window = gtk_widget_get_window (widget);
844 manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
845 pointer = gdk_device_manager_get_client_pointer (manager);
846 if (gdk_device_grab (pointer, window, GDK_OWNERSHIP_WINDOW, TRUE,
847 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK,
848 NULL, activate_time) == GDK_GRAB_SUCCESS) {
849 GdkDevice *keyb;
850 keyb = gdk_device_get_associated_device (pointer);
851 if (gdk_device_grab (keyb, window, GDK_OWNERSHIP_WINDOW, TRUE,
852 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, NULL, activate_time) == 0)
853 return TRUE;
854 else {
855 gdk_device_ungrab (pointer, activate_time);
856 return FALSE;
857 }
858 }
859 return FALSE;
860 }
861
862 static void
863 action_filter_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
864 {
865 GtkWidget *toplevel;
866 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (form));
867
868 if (!form->priv->filter_window) {
869 /* create filter window */
870 GtkWidget *frame, *vbox;
871
872 form->priv->filter_window = gtk_window_new (GTK_WINDOW_POPUP);
873
874 gtk_widget_set_events (form->priv->filter_window,
875 gtk_widget_get_events (form->priv->filter_window) | GDK_KEY_PRESS_MASK);
876
877 if (gtk_widget_is_toplevel (toplevel) && gtk_window_get_group ((GtkWindow*) toplevel))
878 gtk_window_group_add_window (gtk_window_get_group ((GtkWindow*) toplevel),
879 GTK_WINDOW (form->priv->filter_window));
880
881 g_signal_connect (form->priv->filter_window, "delete-event",
882 G_CALLBACK (filter_event), form);
883 g_signal_connect (form->priv->filter_window, "button-press-event",
884 G_CALLBACK (filter_event), form);
885 g_signal_connect (form->priv->filter_window, "key-press-event",
886 G_CALLBACK (key_press_filter_event), form);
887 frame = gtk_frame_new (NULL);
888 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
889 gtk_widget_show (frame);
890 gtk_container_add (GTK_CONTAINER (form->priv->filter_window), frame);
891
892 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
893 gtk_widget_show (vbox);
894 gtk_container_add (GTK_CONTAINER (frame), vbox);
895 gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
896
897 /* add real filter widget */
898 if (! form->priv->filter) {
899 form->priv->filter = gdaui_data_filter_new (GDAUI_DATA_PROXY (form));
900 gtk_widget_show (form->priv->filter);
901 }
902 gtk_container_add (GTK_CONTAINER (vbox), form->priv->filter);
903 }
904 else if (gtk_widget_is_toplevel (toplevel)) {
905 if (gtk_window_get_group ((GtkWindow*) toplevel))
906 gtk_window_group_add_window (gtk_window_get_group ((GtkWindow*) toplevel),
907 GTK_WINDOW (form->priv->filter_window));
908 else if (gtk_window_get_group ((GtkWindow*) form->priv->filter_window))
909 gtk_window_group_remove_window (gtk_window_get_group ((GtkWindow*) form->priv->filter_window),
910 GTK_WINDOW (form->priv->filter_window));
911 }
912
913 /* move the filter window to a correct location */
914 /* FIXME: let the user specify the position function like GtkTreeView -> search_position_func() */
915 gtk_widget_show (form->priv->filter_window);
916 gtk_grab_add (form->priv->filter_window);
917 filter_position_func (GTK_WIDGET (form), form->priv->filter_window, NULL);
918 gtk_widget_show (form->priv->filter_window);
919 popup_grab_on_window (form->priv->filter_window,
920 gtk_get_current_event_time ());
921 }
922
923
924 static void
925 arrow_actions_real_do (GdauiRawForm *form, gint movement)
926 {
927 gint row, oldrow;
928
929 row = gda_data_model_iter_get_row (form->priv->iter);
930 g_return_if_fail (row >= 0);
931 oldrow = row;
932
933 /* see if some data have been modified and need to be written to the DBMS */
934 /* if ((form->priv->mode & GDAUI_ACTION_MODIF_AUTO_COMMIT) && */
935 /* gda_data_proxy_has_changed (form->priv->proxy)) */
936 /* action_commit_cb (NULL, form); */
937
938 /* movement */
939 switch (movement) {
940 case -2:
941 row = 0;
942 break;
943 case -1:
944 if (row > 0)
945 row--;
946 break;
947 case 1:
948 if (row < gda_data_model_get_n_rows (GDA_DATA_MODEL (form->priv->proxy)) - 1 )
949 row++;
950 break;
951 case 2:
952 row = gda_data_model_get_n_rows (GDA_DATA_MODEL (form->priv->proxy)) - 1;
953 break;
954 default:
955 g_assert_not_reached ();
956 }
957
958 if (oldrow != row)
959 gda_data_model_iter_move_to_row (form->priv->iter, row);
960 }
961
962 /*
963 * GdauiDataProxy interface implementation
964 */
965 static GdaDataProxy *
966 gdaui_raw_form_get_proxy (GdauiDataProxy *iface)
967 {
968 GdauiRawForm *form;
969
970 g_return_val_if_fail (GDAUI_IS_RAW_FORM (iface), NULL);
971 form = GDAUI_RAW_FORM (iface);
972 g_return_val_if_fail (form->priv, NULL);
973
974 return form->priv->proxy;
975 }
976
977 void
978 gdaui_raw_form_set_column_editable (GdauiDataProxy *iface, G_GNUC_UNUSED gint column, G_GNUC_UNUSED gboolean editable)
979 {
980 GdauiRawForm *form;
981
982 g_return_if_fail (GDAUI_IS_RAW_FORM (iface));
983 form = GDAUI_RAW_FORM (iface);
984 g_return_if_fail (form->priv);
985
986 TO_IMPLEMENT;
987 /* What needs to be done:
988 * - create a gdaui_basic_form_set_entry_editable() function for GdauiBasicForm, and call it
989 * - in the GdauiDataEntry, add a GDA_VALUE_ATTR_EDITABLE property which defaults to TRUE.
990 * - imtplement the gdaui_basic_form_set_entry_editable() in the same way as gdaui_basic_form_set_entries_to_default()
991 * by setting that new property
992 * - implement the new property in GdauiEntryWrapper and GdauiEntryCombo.
993 */
994 }
995
996 static void
997 gdaui_raw_form_show_column_actions (GdauiDataProxy *iface, G_GNUC_UNUSED gint column, gboolean show_actions)
998 {
999 GdauiRawForm *form;
1000
1001 g_return_if_fail (GDAUI_IS_RAW_FORM (iface));
1002 form = GDAUI_RAW_FORM (iface);
1003 g_return_if_fail (form->priv);
1004
1005 /* REM: don't take care of the @column argument */
1006 g_object_set ((GObject*) form, "show-actions", show_actions, NULL);
1007 }
1008
1009 static GtkActionGroup *
1010 gdaui_raw_form_get_actions_group (GdauiDataProxy *iface)
1011 {
1012 GdauiRawForm *form;
1013
1014 g_return_val_if_fail (GDAUI_IS_RAW_FORM (iface), NULL);
1015 form = GDAUI_RAW_FORM (iface);
1016 g_return_val_if_fail (form->priv, NULL);
1017
1018 return form->priv->actions_group;
1019 }
1020
1021 static gboolean
1022 gdaui_raw_form_widget_set_write_mode (GdauiDataProxy *iface, GdauiDataProxyWriteMode mode)
1023 {
1024 GdauiRawForm *form;
1025
1026 g_return_val_if_fail (GDAUI_IS_RAW_FORM (iface), FALSE);
1027 form = GDAUI_RAW_FORM (iface);
1028 g_return_val_if_fail (form->priv, FALSE);
1029
1030 form->priv->write_mode = mode;
1031 return TRUE;
1032 }
1033
1034 static GdauiDataProxyWriteMode
1035 gdaui_raw_form_widget_get_write_mode (GdauiDataProxy *iface)
1036 {
1037 GdauiRawForm *form;
1038
1039 g_return_val_if_fail (GDAUI_IS_RAW_FORM (iface), GDAUI_DATA_PROXY_WRITE_ON_DEMAND);
1040 form = GDAUI_RAW_FORM (iface);
1041 g_return_val_if_fail (form->priv, GDAUI_DATA_PROXY_WRITE_ON_DEMAND);
1042
1043 return form->priv->write_mode;
1044 }
1045
1046 /* GdauiDataSelector interface */
1047 static GdaDataModel *
1048 gdaui_raw_form_selector_get_model (GdauiDataSelector *iface)
1049 {
1050 GdauiRawForm *form;
1051
1052 g_return_val_if_fail (GDAUI_IS_RAW_FORM (iface), NULL);
1053 form = GDAUI_RAW_FORM (iface);
1054
1055 return GDA_DATA_MODEL (form->priv->proxy);
1056 }
1057
1058 static void
1059 gdaui_raw_form_selector_set_model (GdauiDataSelector *iface, GdaDataModel *model)
1060 {
1061 GdauiRawForm *form;
1062
1063 g_return_if_fail (GDAUI_IS_RAW_FORM (iface));
1064 form = GDAUI_RAW_FORM (iface);
1065
1066 g_object_set (form, "model", model, NULL);
1067 }
1068
1069 static GArray *
1070 gdaui_raw_form_selector_get_selected_rows (GdauiDataSelector *iface)
1071 {
1072 GdauiRawForm *form;
1073
1074 g_return_val_if_fail (GDAUI_IS_RAW_FORM (iface), NULL);
1075 form = GDAUI_RAW_FORM (iface);
1076
1077 if (gda_data_model_iter_is_valid (form->priv->iter)) {
1078 GArray *array;
1079 gint row;
1080 array = g_array_new (FALSE, FALSE, sizeof (gint));
1081 row = gda_data_model_iter_get_row (form->priv->iter);
1082 g_array_append_val (array, row);
1083 return array;
1084 }
1085 else
1086 return NULL;
1087 }
1088
1089 static GdaDataModelIter *
1090 gdaui_raw_form_selector_get_data_set (GdauiDataSelector *iface)
1091 {
1092 GdauiRawForm *form;
1093
1094 g_return_val_if_fail (GDAUI_IS_RAW_FORM (iface), NULL);
1095 form = GDAUI_RAW_FORM (iface);
1096
1097 return form->priv->iter;
1098 }
1099
1100 static gboolean
1101 gdaui_raw_form_selector_select_row (GdauiDataSelector *iface, gint row)
1102 {
1103 GdauiRawForm *form;
1104
1105 g_return_val_if_fail (GDAUI_IS_RAW_FORM (iface), FALSE);
1106 form = (GdauiRawForm*) iface;
1107
1108 return gda_data_model_iter_move_to_row (form->priv->iter, row);
1109 }
1110
1111 static void
1112 gdaui_raw_form_selector_unselect_row (G_GNUC_UNUSED GdauiDataSelector *iface, G_GNUC_UNUSED gint row)
1113 {
1114 g_warning ("%s() method not supported\n", __FUNCTION__);
1115 }
1116
1117 static void
1118 gdaui_raw_form_selector_set_column_visible (GdauiDataSelector *iface, gint column, gboolean visible)
1119 {
1120 GdauiRawForm *form;
1121 GdaHolder *param;
1122
1123 g_return_if_fail (GDAUI_IS_RAW_FORM (iface));
1124 form = GDAUI_RAW_FORM (iface);
1125
1126 param = gda_data_model_iter_get_holder_for_field (form->priv->iter, column);
1127 g_return_if_fail (param);
1128 gdaui_basic_form_entry_set_visible (GDAUI_BASIC_FORM (form), param, visible);
1129 }
1130