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", &param, 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