1 /*
2  * Copyright (C) 2010 David King <davidk@openismus.com>
3  * Copyright (C) 2010 - 2012 Vivien Malerba <malerba@gnome-db.org>
4  * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 
21 #include <string.h>
22 #include <glib/gi18n-lib.h>
23 #include <libgda/libgda.h>
24 #include "ui-formgrid.h"
25 #include <libgda-ui/gdaui-data-proxy.h>
26 #include <libgda-ui/gdaui-raw-form.h>
27 #include <libgda-ui/gdaui-data-selector.h>
28 #include "../support.h"
29 #include "../browser-window.h"
30 #include "../browser-stock-icons.h"
31 #include "widget-overlay.h"
32 #include <libgda/gda-data-model-extra.h>
33 #include "favorites-actions.h"
34 #ifdef HAVE_LDAP
35 #include "../ldap-browser/ldap-browser-perspective.h"
36 #endif
37 #include "../../tool-utils.h"
38 
39 static void ui_formgrid_class_init (UiFormGridClass * class);
40 static void ui_formgrid_init (UiFormGrid *wid);
41 static void ui_formgrid_dispose (GObject *object);
42 
43 static void ui_formgrid_set_property (GObject *object,
44 				      guint param_id,
45 				      const GValue *value,
46 				      GParamSpec *pspec);
47 static void ui_formgrid_get_property (GObject *object,
48 				      guint param_id,
49 				      GValue *value,
50 				      GParamSpec *pspec);
51 static void ui_formgrid_show (GtkWidget *widget);
52 static BrowserConnection *get_browser_connection (UiFormGrid *formgrid);
53 static void compute_modification_statements (UiFormGrid *formgrid, GdaDataModel *model);
54 
55 #define GRID_FLAGS (GDAUI_DATA_PROXY_INFO_CURRENT_ROW | GDAUI_DATA_PROXY_INFO_CHUNCK_CHANGE_BUTTONS)
56 #define FORM_FLAGS (GDAUI_DATA_PROXY_INFO_CURRENT_ROW | GDAUI_DATA_PROXY_INFO_ROW_MOVE_BUTTONS)
57 
58 typedef enum {
59 	MOD_INSERT,
60 	MOD_UPDATE,
61 	MOD_DELETE,
62 	MOD_LAST
63 } ModType;
64 
65 struct _UiFormGridPriv
66 {
67 	GtkWidget   *nb;
68 	GtkWidget   *raw_form;
69 	GtkWidget   *raw_grid;
70 	GtkWidget   *info;
71 	GtkWidget   *overlay_form;
72 	GtkWidget   *overlay_grid;
73 	GtkWidget   *autoupdate_toggle;
74 	gboolean     autoupdate;
75 	gboolean     autoupdate_possible;
76 	GdauiDataProxyInfoFlag flags;
77 
78 	BrowserConnection *bcnc;
79 	gboolean     scroll_form;
80 
81 	/* modifications to the data */
82 	gboolean           compute_mod_stmt; /* if %TRUE, then the INSERT, UPDATE and DELETE
83 					       * statements are automatically computed, see the PROP_AUTOMOD property */
84 	gboolean           mod_stmt_auto_computed; /* %TRUE if mod_stmt[*] have automatically
85 						    * been computed */
86 	GdaStatement      *mod_stmt[MOD_LAST];
87 };
88 
89 /* get a pointer to the parents to be able to call their destructor */
90 static GObjectClass *parent_class = NULL;
91 
92 /* signals */
93 enum {
94         DATA_SET_CHANGED,
95         LAST_SIGNAL
96 };
97 
98 gint ui_formgrid_signals [LAST_SIGNAL] = { 0 };
99 
100 /* properties */
101 enum {
102 	PROP_0,
103 	PROP_RAW_GRID,
104 	PROP_RAW_FORM,
105 	PROP_INFO,
106 	PROP_SCROLL_FORM,
107 	PROP_AUTOMOD
108 };
109 
110 GType
ui_formgrid_get_type(void)111 ui_formgrid_get_type (void)
112 {
113 	static GType type = 0;
114 
115 	if (!type) {
116 		static const GTypeInfo info = {
117 			sizeof (UiFormGridClass),
118 			(GBaseInitFunc) NULL,
119 			(GBaseFinalizeFunc) NULL,
120 			(GClassInitFunc) ui_formgrid_class_init,
121 			NULL,
122 			NULL,
123 			sizeof (UiFormGrid),
124 			0,
125 			(GInstanceInitFunc) ui_formgrid_init,
126 			0
127 		};
128 
129 		type = g_type_register_static (GTK_TYPE_BOX, "UiFormGrid", &info, 0);
130 	}
131 
132 	return type;
133 }
134 
135 static void
ui_formgrid_class_init(UiFormGridClass * klass)136 ui_formgrid_class_init (UiFormGridClass *klass)
137 {
138 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
139 
140 	parent_class = g_type_class_peek_parent (klass);
141 	object_class->dispose = ui_formgrid_dispose;
142 	GTK_WIDGET_CLASS (klass)->show = ui_formgrid_show;
143 
144 	/* signals */
145 	ui_formgrid_signals [DATA_SET_CHANGED] =
146 		g_signal_new ("data-set-changed",
147                               G_TYPE_FROM_CLASS (object_class),
148                               G_SIGNAL_RUN_FIRST,
149                               G_STRUCT_OFFSET (UiFormGridClass, data_set_changed),
150                               NULL, NULL,
151                               g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
152 	klass->data_set_changed = NULL;
153 
154 	/* Properties */
155         object_class->set_property = ui_formgrid_set_property;
156         object_class->get_property = ui_formgrid_get_property;
157 	g_object_class_install_property (object_class, PROP_RAW_GRID,
158                                          g_param_spec_object ("raw_grid", NULL, NULL,
159 							      GDAUI_TYPE_RAW_GRID,
160 							      G_PARAM_READABLE));
161 	g_object_class_install_property (object_class, PROP_RAW_FORM,
162                                          g_param_spec_object ("raw_form", NULL, NULL,
163 							      GDAUI_TYPE_RAW_GRID,
164 							      G_PARAM_READABLE));
165 	g_object_class_install_property (object_class, PROP_INFO,
166                                          g_param_spec_object ("widget_info", NULL, NULL,
167 							      GDAUI_TYPE_DATA_PROXY_INFO,
168 							      G_PARAM_READABLE));
169 	g_object_class_install_property (object_class, PROP_SCROLL_FORM,
170 					 g_param_spec_boolean ("scroll-form", NULL, NULL,
171 							       FALSE,
172 							       G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
173 	g_object_class_install_property (object_class, PROP_AUTOMOD,
174 					 g_param_spec_boolean ("compute-mod-statements", NULL, NULL,
175 							       FALSE,
176 							       G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
177 }
178 
179 static void
ui_formgrid_dispose(GObject * object)180 ui_formgrid_dispose (GObject *object)
181 {
182         UiFormGrid *formgrid;
183 
184         formgrid = UI_FORMGRID (object);
185         if (formgrid->priv) {
186                 if (formgrid->priv->bcnc)
187                         g_object_unref (formgrid->priv->bcnc);
188 
189 		ModType mod;
190 		for (mod = MOD_INSERT; mod < MOD_LAST; mod++) {
191 			if (formgrid->priv->mod_stmt[mod]) {
192 				g_object_unref (formgrid->priv->mod_stmt[mod]);
193 				formgrid->priv->mod_stmt[mod] = NULL;
194 			}
195 		}
196 
197                 g_free (formgrid->priv);
198                 formgrid->priv = NULL;
199         }
200 
201         /* parent class */
202         parent_class->dispose (object);
203 }
204 
205 static void
ui_formgrid_show(GtkWidget * widget)206 ui_formgrid_show (GtkWidget *widget)
207 {
208 	UiFormGrid *formgrid;
209 	GtkWidget *ovl, *packed;
210 	formgrid = UI_FORMGRID (widget);
211 
212 	if (! formgrid->priv->overlay_grid) {
213 		/* finalize packing */
214 		GtkWidget *sw, *vp;
215 		sw = gtk_scrolled_window_new (NULL, NULL);
216 		gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
217 						GTK_POLICY_AUTOMATIC,
218 						GTK_POLICY_AUTOMATIC);
219 		gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
220 						     GTK_SHADOW_NONE);
221 		gtk_container_add (GTK_CONTAINER (sw), formgrid->priv->raw_grid);
222 		gtk_widget_show_all (sw);
223 		packed = sw;
224 
225 		/* overlay */
226 		ovl = widget_overlay_new ();
227 		formgrid->priv->overlay_grid = ovl;
228 		g_object_set (G_OBJECT (ovl), "add-scale", TRUE, NULL);
229 		g_object_set (G_OBJECT (ovl), "add-scale", FALSE, NULL);
230 		gtk_container_add (GTK_CONTAINER (ovl), packed);
231 		widget_overlay_set_child_props (WIDGET_OVERLAY (ovl), packed,
232 						WIDGET_OVERLAY_CHILD_HALIGN,
233 						WIDGET_OVERLAY_ALIGN_FILL,
234 						WIDGET_OVERLAY_CHILD_VALIGN,
235 						WIDGET_OVERLAY_ALIGN_FILL,
236 						WIDGET_OVERLAY_CHILD_SCALE, .9,
237 						-1);
238 		gtk_widget_show (ovl);
239 		gtk_notebook_append_page (GTK_NOTEBOOK (formgrid->priv->nb), ovl, NULL);
240 	}
241 
242 	if (! formgrid->priv->overlay_form) {
243 		/* finalize packing */
244 		if (formgrid->priv->scroll_form) {
245 			GtkWidget *sw, *vp;
246 			sw = gtk_scrolled_window_new (NULL, NULL);
247 			gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
248 							GTK_POLICY_AUTOMATIC,
249 							GTK_POLICY_AUTOMATIC);
250 			gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
251 							     GTK_SHADOW_NONE);
252 			vp = gtk_viewport_new (NULL, NULL);
253 			gtk_widget_set_name (vp, "gdaui-transparent-background");
254 			gtk_container_add (GTK_CONTAINER (sw), vp);
255 			gtk_viewport_set_shadow_type (GTK_VIEWPORT (vp), GTK_SHADOW_NONE);
256 			gtk_container_add (GTK_CONTAINER (vp), formgrid->priv->raw_form);
257 			gtk_widget_show_all (sw);
258 			packed = sw;
259 		}
260 		else {
261 			gtk_widget_show (formgrid->priv->raw_form);
262 			packed = formgrid->priv->raw_form;
263 		}
264 
265 		/* overlay */
266 		ovl = widget_overlay_new ();
267 		formgrid->priv->overlay_form = ovl;
268 		g_object_set (G_OBJECT (ovl), "add-scale", TRUE, NULL);
269 		g_object_set (G_OBJECT (ovl), "add-scale", FALSE, NULL);
270 		gtk_container_add (GTK_CONTAINER (ovl), packed);
271 		widget_overlay_set_child_props (WIDGET_OVERLAY (ovl), packed,
272 						WIDGET_OVERLAY_CHILD_HALIGN,
273 						WIDGET_OVERLAY_ALIGN_FILL,
274 						WIDGET_OVERLAY_CHILD_VALIGN,
275 						WIDGET_OVERLAY_ALIGN_FILL,
276 						WIDGET_OVERLAY_CHILD_SCALE, 1.,
277 						-1);
278 		gtk_widget_show (ovl);
279 		gtk_notebook_append_page (GTK_NOTEBOOK (formgrid->priv->nb), ovl, NULL);
280 		gtk_notebook_set_current_page (GTK_NOTEBOOK (formgrid->priv->nb),
281 					       0);
282 	}
283 
284 	((GtkWidgetClass *)parent_class)->show (widget);
285 	if (! formgrid->priv->autoupdate_possible)
286 		gtk_widget_hide (formgrid->priv->autoupdate_toggle);
287 }
288 
289 static void form_grid_autoupdate_cb (GtkToggleButton *button, UiFormGrid *formgrid);
290 static void form_grid_toggled_cb (GtkToggleAction *action, UiFormGrid *formgrid);
291 static void form_grid_populate_popup_cb (GtkWidget *wid, GtkMenu *menu, UiFormGrid *formgrid);
292 static void selection_changed_cb (GdauiDataSelector *sel, UiFormGrid *formgrid);
293 
294 static void
ui_formgrid_init(UiFormGrid * formgrid)295 ui_formgrid_init (UiFormGrid *formgrid)
296 {
297 	GtkWidget *sw;
298 	GtkWidget *hbox, *button;
299 
300 	formgrid->priv = g_new0 (UiFormGridPriv, 1);
301 	formgrid->priv->raw_grid = NULL;
302 	formgrid->priv->info = NULL;
303 	formgrid->priv->flags = GDAUI_DATA_PROXY_INFO_CURRENT_ROW | GDAUI_DATA_PROXY_INFO_ROW_MODIFY_BUTTONS;
304 	formgrid->priv->bcnc = NULL;
305 	formgrid->priv->autoupdate = TRUE;
306 	formgrid->priv->autoupdate_possible = FALSE;
307 	formgrid->priv->scroll_form = FALSE;
308 	formgrid->priv->compute_mod_stmt = FALSE;
309 
310 	gtk_orientable_set_orientation (GTK_ORIENTABLE (formgrid), GTK_ORIENTATION_VERTICAL);
311 
312 	/* notebook */
313 	formgrid->priv->nb = gtk_notebook_new ();
314 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (formgrid->priv->nb), FALSE);
315 	gtk_notebook_set_show_border (GTK_NOTEBOOK (formgrid->priv->nb), FALSE);
316 	gtk_box_pack_start (GTK_BOX (formgrid), formgrid->priv->nb, TRUE, TRUE, 0);
317 	gtk_widget_show (formgrid->priv->nb);
318 
319 	/* grid on 1st page of notebook, not added there */
320 	formgrid->priv->raw_grid = gdaui_raw_grid_new (NULL);
321 	gdaui_data_proxy_column_show_actions (GDAUI_DATA_PROXY (formgrid->priv->raw_grid), -1, FALSE);
322 	g_signal_connect (formgrid->priv->raw_grid, "populate-popup",
323 			  G_CALLBACK (form_grid_populate_popup_cb), formgrid);
324 
325 	/* form on the 2nd page of the notebook, not added there */
326 	formgrid->priv->raw_form = gdaui_raw_form_new (NULL);
327 	gdaui_data_proxy_column_show_actions (GDAUI_DATA_PROXY (formgrid->priv->raw_form), -1, FALSE);
328 	g_signal_connect (formgrid->priv->raw_form, "populate-popup",
329 			  G_CALLBACK (form_grid_populate_popup_cb), formgrid);
330 
331 	/* info widget and toggle button at last */
332 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
333 	gtk_box_pack_start (GTK_BOX (formgrid), hbox, FALSE, TRUE, 0);
334 	gtk_widget_show (hbox);
335 
336 	/* button to toggle between auto update and not */
337 	button = gtk_toggle_button_new ();
338 	GtkWidget *img = gtk_image_new_from_stock (GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU);
339 	gtk_button_set_image (GTK_BUTTON (button), img);
340 	formgrid->priv->autoupdate_toggle  = button;
341 
342 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), formgrid->priv->autoupdate);
343 	gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, TRUE, 0);
344 	g_signal_connect (G_OBJECT (button), "toggled",
345 			  G_CALLBACK (form_grid_autoupdate_cb), formgrid);
346 	gtk_widget_set_tooltip_text (button, _("Enable or disable auto update of data"));
347 
348 	/* Proxy info */
349 	formgrid->priv->info = gdaui_data_proxy_info_new (GDAUI_DATA_PROXY (formgrid->priv->raw_grid),
350 							  formgrid->priv->flags |
351 							  GDAUI_DATA_PROXY_INFO_CURRENT_ROW |
352 							  GDAUI_DATA_PROXY_INFO_CHUNCK_CHANGE_BUTTONS);
353 
354 	GtkUIManager *uimanager;
355 	GtkActionGroup *agroup;
356 	GtkAction *action;
357 	guint mid;
358 
359 	g_object_get (G_OBJECT (formgrid->priv->info), "ui-manager", &uimanager, NULL);
360 	agroup = gtk_action_group_new ("FormGrid");
361 	gtk_action_group_set_translation_domain (agroup, GETTEXT_PACKAGE);
362 
363 	action = GTK_ACTION (gtk_toggle_action_new ("FGToggle", "FGToggle",
364 						    _("Toggle between grid and form presentations"),
365 						    BROWSER_STOCK_GRID));
366 	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
367 	gtk_action_group_add_action (agroup, action);
368 	g_signal_connect (G_OBJECT (action), "toggled",
369 			  G_CALLBACK (form_grid_toggled_cb), formgrid);
370 	g_object_unref (action);
371 	gtk_ui_manager_insert_action_group (uimanager, agroup, 0);
372 	g_object_unref (agroup);
373 
374 	mid = gtk_ui_manager_new_merge_id (uimanager);
375 	gtk_ui_manager_add_ui (uimanager, mid, "/ToolBar", "FGToggle", "FGToggle",
376 			       GTK_UI_MANAGER_AUTO, TRUE);
377 	gtk_ui_manager_ensure_update (uimanager);
378 	gtk_box_pack_start (GTK_BOX (hbox), formgrid->priv->info, TRUE, TRUE, 0);
379 	gtk_widget_show (formgrid->priv->info);
380 	g_object_unref (G_OBJECT (uimanager));
381 
382 
383 	/*gchar *tmp;
384 	g_object_get (uimanager, "ui", &tmp, NULL);
385 	g_print ("==>[%s]\n", tmp);
386 	g_free (tmp);
387 	*/
388 
389 	/* keep data in sync */
390 	g_signal_connect (formgrid->priv->raw_grid, "selection-changed",
391 			  G_CALLBACK (selection_changed_cb), formgrid);
392 	g_signal_connect (formgrid->priv->raw_form, "selection-changed",
393 			  G_CALLBACK (selection_changed_cb), formgrid);
394 }
395 
396 /**
397  * ui_formgrid_get_ui_manager:
398  *
399  * Returns: (transfer none): the #GtkUIManager
400  */
401 GtkUIManager *
ui_formgrid_get_ui_manager(UiFormGrid * formgrid)402 ui_formgrid_get_ui_manager (UiFormGrid *formgrid)
403 {
404 	GtkUIManager *uimanager;
405 	g_return_val_if_fail (UI_IS_FORMGRID (formgrid), NULL);
406 	g_object_get (G_OBJECT (formgrid->priv->info), "ui-manager", &uimanager, NULL);
407 	g_object_unref (uimanager);
408 	return uimanager;
409 }
410 
411 static void
selection_changed_cb(GdauiDataSelector * sel,UiFormGrid * formgrid)412 selection_changed_cb (GdauiDataSelector *sel, UiFormGrid *formgrid)
413 {
414 	GdaDataModelIter *iter;
415 	GdauiDataSelector *tosel;
416 	gint row;
417 	if (sel == (GdauiDataSelector*) formgrid->priv->raw_grid)
418 		tosel = (GdauiDataSelector*) formgrid->priv->raw_form;
419 	else
420 		tosel = (GdauiDataSelector*) formgrid->priv->raw_grid;
421 
422 	iter = gdaui_data_selector_get_data_set (sel);
423 	g_assert (iter);
424 	row = gda_data_model_iter_get_row (iter);
425 	/*g_print ("Moved %s to row %d\n", sel == (GdauiDataSelector*) formgrid->priv->raw_grid ? "grid" : "form", row);*/
426 	iter = gdaui_data_selector_get_data_set (tosel);
427 	if (iter) {
428 		g_signal_handlers_block_by_func (tosel, G_CALLBACK (selection_changed_cb), formgrid);
429 		gda_data_model_iter_move_to_row (iter, row >= 0 ? row : 0);
430 		g_signal_handlers_unblock_by_func (tosel, G_CALLBACK (selection_changed_cb), formgrid);
431 	}
432 }
433 
434 static void
form_grid_autoupdate_cb(GtkToggleButton * button,UiFormGrid * formgrid)435 form_grid_autoupdate_cb (GtkToggleButton *button, UiFormGrid *formgrid)
436 {
437 	formgrid->priv->autoupdate = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
438 }
439 
440 static void
form_grid_toggled_cb(GtkToggleAction * action,UiFormGrid * formgrid)441 form_grid_toggled_cb (GtkToggleAction *action, UiFormGrid *formgrid)
442 {
443 	if (!gtk_toggle_action_get_active (action)) {
444 		/* switch to form  view */
445 		gtk_notebook_set_current_page (GTK_NOTEBOOK (formgrid->priv->nb), 1);
446 		g_object_set (G_OBJECT (formgrid->priv->info),
447 			      "data-proxy", formgrid->priv->raw_form,
448 			      "flags", formgrid->priv->flags | FORM_FLAGS, NULL);
449 
450 		g_object_set (G_OBJECT (action), "stock-id", BROWSER_STOCK_FORM, NULL);
451 	}
452 	else {
453 		/* switch to grid view */
454 		gtk_notebook_set_current_page (GTK_NOTEBOOK (formgrid->priv->nb), 0);
455 		g_object_set (G_OBJECT (formgrid->priv->info),
456 			      "data-proxy", formgrid->priv->raw_grid,
457 			      "flags", formgrid->priv->flags | GRID_FLAGS, NULL);
458 
459 		g_object_set (G_OBJECT (action), "stock-id", BROWSER_STOCK_GRID, NULL);
460 	}
461 }
462 
463 static BrowserConnection *
get_browser_connection(UiFormGrid * formgrid)464 get_browser_connection (UiFormGrid *formgrid)
465 {
466 	if (formgrid->priv->bcnc)
467 		return formgrid->priv->bcnc;
468 	else {
469 		GtkWidget *toplevel;
470 
471 		toplevel = gtk_widget_get_toplevel (GTK_WIDGET (formgrid));
472 		if (BROWSER_IS_WINDOW (toplevel))
473 			return browser_window_get_connection (BROWSER_WINDOW (toplevel));
474 	}
475 	return NULL;
476 }
477 
478 
479 static void execute_action_mitem_cb (GtkMenuItem *menuitem, UiFormGrid *formgrid);
480 #ifdef HAVE_LDAP
481 static void ldap_view_dn_mitem_cb (GtkMenuItem *menuitem, UiFormGrid *formgrid);
482 #endif
483 static void zoom_form_mitem_cb (GtkCheckMenuItem *checkmenuitem, UiFormGrid *formgrid);
484 static void zoom_grid_mitem_cb (GtkCheckMenuItem *checkmenuitem, UiFormGrid *formgrid);
485 
486 static void
form_grid_populate_popup_cb(GtkWidget * wid,GtkMenu * menu,UiFormGrid * formgrid)487 form_grid_populate_popup_cb (GtkWidget *wid, GtkMenu *menu, UiFormGrid *formgrid)
488 {
489 	/* add actions to execute to menu */
490 	GdaDataModelIter *iter;
491 	BrowserConnection *bcnc = NULL;
492 
493 	bcnc = get_browser_connection (formgrid);
494 	if (!bcnc)
495 		return;
496 
497 	iter = gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR (formgrid->priv->raw_grid));
498 
499 	/* actions */
500 	GSList *actions_list, *list;
501 	actions_list = gda_tools_favorites_get_actions (browser_connection_get_favorites (bcnc),
502 						      bcnc, GDA_SET (iter));
503 	if (actions_list) {
504 		GtkWidget *mitem, *submenu;
505 		mitem = gtk_menu_item_new_with_label (_("Execute action"));
506 		gtk_widget_show (mitem);
507 		gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mitem);
508 
509 		submenu = gtk_menu_new ();
510 		gtk_menu_item_set_submenu (GTK_MENU_ITEM (mitem), submenu);
511 		for (list = actions_list; list; list = list->next) {
512 			ToolsFavoriteAction *act = (ToolsFavoriteAction*) list->data;
513 			mitem = gtk_menu_item_new_with_label (act->name);
514 			gtk_widget_show (mitem);
515 			gtk_menu_shell_append (GTK_MENU_SHELL (submenu), mitem);
516 			g_object_set_data_full (G_OBJECT (mitem), "action", act,
517 						(GDestroyNotify) gda_tools_favorites_free_action);
518 			g_signal_connect (mitem, "activate",
519 					  G_CALLBACK (execute_action_mitem_cb), formgrid);
520 		}
521 		g_slist_free (actions_list);
522 	}
523 
524 #ifdef HAVE_LDAP
525 	/* LDAP specific */
526 	if (browser_connection_is_ldap (bcnc)) {
527 		GdaHolder *dnh;
528 		dnh = gda_set_get_holder (GDA_SET (iter), "dn");
529 		if (dnh) {
530 			const GValue *cvalue;
531 			cvalue = gda_holder_get_value (GDA_HOLDER (dnh));
532 			if (!cvalue && (G_VALUE_TYPE (cvalue) != G_TYPE_STRING))
533 				dnh = NULL;
534 		}
535 		if (!dnh) {
536 			GSList *list;
537 			for (list = GDA_SET (iter)->holders; list; list = list->next) {
538 				const GValue *cvalue;
539 				cvalue = gda_holder_get_value (GDA_HOLDER (list->data));
540 				if (cvalue && (G_VALUE_TYPE (cvalue) == G_TYPE_STRING) &&
541 				    gda_ldap_is_dn (g_value_get_string (cvalue))) {
542 					dnh = GDA_HOLDER (list->data);
543 					break;
544 				}
545 			}
546 		}
547 
548 		if (dnh) {
549 			const GValue *cvalue;
550 			cvalue = gda_holder_get_value (dnh);
551 
552 			GtkWidget *mitem;
553 			mitem = gtk_menu_item_new_with_label (_("View LDAP entry's details"));
554 			gtk_widget_show (mitem);
555 			gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mitem);
556 			g_object_set_data_full (G_OBJECT (mitem), "dn",
557 						g_value_dup_string (cvalue), g_free);
558 			g_signal_connect (mitem, "activate",
559 					  G_CALLBACK (ldap_view_dn_mitem_cb), formgrid);
560 		}
561 	}
562 #endif
563 
564 	if (wid == formgrid->priv->raw_form) {
565 		GtkWidget *mitem;
566 		gboolean add_scale;
567 		g_object_get (G_OBJECT (formgrid->priv->overlay_form), "add-scale", &add_scale, NULL);
568 		mitem = gtk_check_menu_item_new_with_label (_("Zoom..."));
569 		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mitem), add_scale);
570 		gtk_widget_show (mitem);
571 		gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mitem);
572 		g_signal_connect (mitem, "toggled",
573 				  G_CALLBACK (zoom_form_mitem_cb), formgrid);
574 	}
575 	else if (wid == formgrid->priv->raw_grid) {
576 		GtkWidget *mitem;
577 		gboolean add_scale;
578 		g_object_get (G_OBJECT (formgrid->priv->overlay_grid), "add-scale", &add_scale, NULL);
579 		mitem = gtk_check_menu_item_new_with_label (_("Zoom..."));
580 		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mitem), add_scale);
581 		gtk_widget_show (mitem);
582 		gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mitem);
583 		g_signal_connect (mitem, "toggled",
584 				  G_CALLBACK (zoom_grid_mitem_cb), formgrid);
585 	}
586 }
587 
588 static void
zoom_form_mitem_cb(GtkCheckMenuItem * checkmenuitem,UiFormGrid * formgrid)589 zoom_form_mitem_cb (GtkCheckMenuItem *checkmenuitem, UiFormGrid *formgrid)
590 {
591 	g_object_set (G_OBJECT (formgrid->priv->overlay_form), "add-scale",
592 		      gtk_check_menu_item_get_active (checkmenuitem), NULL);
593 }
594 
595 static void
zoom_grid_mitem_cb(GtkCheckMenuItem * checkmenuitem,UiFormGrid * formgrid)596 zoom_grid_mitem_cb (GtkCheckMenuItem *checkmenuitem, UiFormGrid *formgrid)
597 {
598 	g_object_set (G_OBJECT (formgrid->priv->overlay_grid), "add-scale",
599 		      gtk_check_menu_item_get_active (checkmenuitem), NULL);
600 }
601 
602 typedef struct {
603 	BrowserConnection *bcnc; /* ref held */
604 	UiFormGrid    *formgrid; /* ref held */
605 	gchar         *name;
606         GdaStatement  *stmt; /* ref held */
607         GdaSet        *params; /* ref held */
608 	GdaDataModel  *model; /* ref held */
609 	guint          exec_id;
610 	guint          timer_id;
611 } ActionExecutedData;
612 
613 static void action_executed_holder_changed_cb (G_GNUC_UNUSED GdaSet *params, G_GNUC_UNUSED GdaHolder *holder,
614 					       ActionExecutedData *aed);
615 static void
action_executed_data_free(ActionExecutedData * data)616 action_executed_data_free (ActionExecutedData *data)
617 {
618 	g_object_unref ((GObject*) data->bcnc);
619 	if (data->formgrid)
620 		g_object_unref ((GObject*) data->formgrid);
621 	g_free (data->name);
622 	g_object_unref ((GObject*) data->stmt);
623 
624 	if (data->params) {
625 		g_signal_handlers_disconnect_by_func (data->params,
626 						      G_CALLBACK (action_executed_holder_changed_cb), data);
627 		g_object_unref ((GObject*) data->params);
628 	}
629 	if (data->model)
630 		g_object_unref ((GObject*) data->model);
631 	if (data->timer_id)
632 		g_source_remove (data->timer_id);
633 	g_free (data);
634 }
635 
636 static gboolean
exec_end_timeout_cb(ActionExecutedData * aed)637 exec_end_timeout_cb (ActionExecutedData *aed)
638 {
639 	GError *error = NULL;
640 	GObject *obj;
641 	obj = browser_connection_execution_get_result (aed->bcnc, aed->exec_id,
642                                                        NULL, &error);
643 	if (obj) {
644                 if (GDA_IS_DATA_MODEL (obj)) {
645                         g_assert (aed->model == (GdaDataModel*) obj);
646 			gda_data_model_thaw (aed->model);
647 			gda_data_model_reset (aed->model);
648 
649 			aed->exec_id = 0;
650 			aed->timer_id = 0;
651 			return FALSE;
652                 }
653                 else {
654 			g_object_unref (obj);
655                         g_set_error (&error, GDA_TOOLS_ERROR, GDA_TOOLS_COMMAND_ARGUMENTS_ERROR,
656                                      "%s", _("Statement to execute is not a selection statement"));
657                 }
658         }
659 
660         if (error) {
661 		GtkWidget *toplevel;
662 		toplevel = gtk_widget_get_toplevel (GTK_WIDGET (aed->formgrid));
663 		browser_show_error (GTK_WINDOW (toplevel),
664                                     _("Error executing query:\n%s"),
665                                     error->message ?
666                                     error->message : _("No detail"));
667 		g_clear_error (&error);
668 		gda_data_model_thaw (aed->model);
669                 aed->exec_id = 0;
670 		aed->timer_id = 0;
671                 return FALSE;
672         }
673         else
674                 return TRUE; /* keep timer */
675 }
676 
677 static void
action_executed_holder_changed_cb(G_GNUC_UNUSED GdaSet * params,G_GNUC_UNUSED GdaHolder * holder,ActionExecutedData * aed)678 action_executed_holder_changed_cb (G_GNUC_UNUSED GdaSet *params, G_GNUC_UNUSED GdaHolder *holder,
679 				   ActionExecutedData *aed)
680 {
681 	if (! aed->formgrid->priv->autoupdate || ! aed->formgrid->priv->autoupdate_possible)
682 		return;
683 
684 	GError *error = NULL;
685 	guint jid;
686 	gda_data_model_freeze (aed->model);
687 	jid = browser_connection_rerun_select (aed->bcnc, aed->model, &error);
688 	if (!jid) {
689 		GtkWidget *toplevel;
690 		toplevel = gtk_widget_get_toplevel (GTK_WIDGET (aed->formgrid));
691 		browser_show_error (GTK_WINDOW (toplevel),
692                                     _("Error executing query:\n%s"),
693                                     error->message ?
694                                     error->message : _("No detail"));
695 		gda_data_model_thaw (aed->model);
696 	}
697 	else {
698 		/* watch the end of execution */
699 		aed->exec_id = jid;
700 		if (! aed->timer_id)
701 			aed->timer_id = g_timeout_add (50, (GSourceFunc) exec_end_timeout_cb, aed);
702 	}
703 }
704 
705 /*
706  * Called after an action's statement has been executed
707  */
708 static void
statement_executed_cb(G_GNUC_UNUSED BrowserConnection * bcnc,G_GNUC_UNUSED guint exec_id,GObject * out_result,G_GNUC_UNUSED GdaSet * out_last_inserted_row,GError * error,ActionExecutedData * aed)709 statement_executed_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
710 		       G_GNUC_UNUSED guint exec_id,
711 		       GObject *out_result,
712 		       G_GNUC_UNUSED GdaSet *out_last_inserted_row, GError *error,
713 		       ActionExecutedData *aed)
714 {
715 	GtkWidget *toplevel;
716 
717 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (aed->formgrid));
718 	g_object_unref (aed->formgrid);
719 	aed->formgrid = NULL;
720 
721         if (error)
722                 browser_show_error (GTK_WINDOW (toplevel),
723                                     _("Error executing query:\n%s"),
724                                     error->message ?
725                                     error->message : _("No detail"));
726 	else if (out_result && GDA_IS_DATA_MODEL (out_result)) {
727 		GtkWidget *dialog, *label, *fg;
728 		GtkWidget *dcontents;
729 
730 		gchar *tmp;
731 		dialog = gtk_dialog_new_with_buttons (aed->name,
732 						      NULL,
733 						      0,
734 						      GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
735 		dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
736 		gtk_box_set_spacing (GTK_BOX (dcontents), 5);
737 		gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE, TRUE);
738 
739 		tmp = g_markup_printf_escaped ("<b>%s:</b>", aed->name);
740 		label = gtk_label_new ("");
741 		gtk_label_set_markup (GTK_LABEL (label), tmp);
742 		g_free (tmp);
743 		gtk_misc_set_alignment (GTK_MISC (label), 0., 0.);
744 		gtk_box_pack_start (GTK_BOX (dcontents), label, FALSE, FALSE, 5);
745 
746 		fg = ui_formgrid_new (GDA_DATA_MODEL (out_result), TRUE,
747 				      GDAUI_DATA_PROXY_INFO_CURRENT_ROW);
748 		ui_formgrid_set_connection (UI_FORMGRID (fg), aed->bcnc);
749 
750 		if (GDA_IS_DATA_SELECT (out_result)) {
751 			GdaStatement *stmt;
752 			g_object_get (G_OBJECT (out_result), "select-stmt", &stmt, NULL);
753 			if (stmt) {
754 				ui_formgrid_handle_user_prefs (UI_FORMGRID (fg), NULL, stmt);
755 				g_object_unref (stmt);
756 			}
757 			aed->model = g_object_ref (out_result);
758 			g_signal_connect (aed->params, "holder-changed",
759 					  G_CALLBACK (action_executed_holder_changed_cb), aed);
760 
761 			aed->formgrid = g_object_ref (fg);
762 			aed->formgrid->priv->autoupdate_possible = TRUE;
763 			gtk_widget_show (aed->formgrid->priv->autoupdate_toggle);
764 		}
765 		gtk_box_pack_start (GTK_BOX (dcontents), fg, TRUE, TRUE, 0);
766 
767 		gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 600);
768 		gtk_widget_show_all (dialog);
769 
770 		g_signal_connect (dialog, "response",
771 				  G_CALLBACK (gtk_widget_destroy), NULL);
772 		g_signal_connect (dialog, "close",
773 				  G_CALLBACK (gtk_widget_destroy), NULL);
774 		g_object_set_data_full (G_OBJECT (dialog), "aed", aed,
775 					(GDestroyNotify) action_executed_data_free);
776 		aed = NULL; /* don't free it yet */
777 	}
778         else if (BROWSER_IS_WINDOW (toplevel)) {
779 		browser_window_show_notice_printf (BROWSER_WINDOW (toplevel),
780 						   GTK_MESSAGE_INFO,
781 						   "ActionExecution",
782 						   "%s", _("Action successfully executed"));
783 	}
784 	else
785 		browser_show_message (GTK_WINDOW (toplevel),
786 				      "%s", _("Action successfully executed"));
787 
788 	if (aed)
789 		action_executed_data_free (aed);
790 }
791 
792 static void
execute_action_mitem_cb(GtkMenuItem * menuitem,UiFormGrid * formgrid)793 execute_action_mitem_cb (GtkMenuItem *menuitem, UiFormGrid *formgrid)
794 {
795 	ToolsFavoriteAction *act;
796 	GtkWidget *dlg;
797 	gchar *tmp;
798 	gint response;
799 	GtkWidget *toplevel;
800 
801 	act = (ToolsFavoriteAction*) g_object_get_data (G_OBJECT (menuitem), "action");
802 	toplevel = gtk_widget_get_toplevel ((GtkWidget*) formgrid);
803 	tmp = g_strdup_printf (_("Set or confirm the parameters to execute\n"
804 				 "action '%s'"), act->name);
805 	dlg = gdaui_basic_form_new_in_dialog (act->params,
806 					      (GtkWindow*) toplevel,
807 					      _("Execution of action"), tmp);
808 	g_free (tmp);
809 	response = gtk_dialog_run (GTK_DIALOG (dlg));
810 	gtk_widget_destroy (dlg);
811 	if (response == GTK_RESPONSE_ACCEPT) {
812                 GError *lerror = NULL;
813 		BrowserConnection *bcnc;
814 		ActionExecutedData *aed;
815 
816 		bcnc = get_browser_connection (formgrid);
817 		g_assert (bcnc);
818 
819 		aed = g_new0 (ActionExecutedData, 1);
820 		aed->formgrid = g_object_ref (formgrid);
821 		aed->bcnc = g_object_ref (bcnc);
822 		if (act->name)
823 			aed->name = g_strdup (act->name);
824 		aed->stmt = g_object_ref (act->stmt);
825 		aed->params = g_object_ref (act->params);
826 
827                 if (! browser_connection_execute_statement_cb (bcnc,
828                                                                act->stmt, act->params,
829                                                                GDA_STATEMENT_MODEL_RANDOM_ACCESS,
830                                                                FALSE,
831                                                                (BrowserConnectionExecuteCallback) statement_executed_cb,
832                                                                aed, &lerror)) {
833                         browser_show_error (GTK_WINDOW (toplevel),
834                                             _("Error executing query: %s"),
835                                             lerror && lerror->message ? lerror->message : _("No detail"));
836                         g_clear_error (&lerror);
837 			action_executed_data_free (aed);
838                 }
839 	}
840 }
841 
842 #ifdef HAVE_LDAP
ldap_view_dn_mitem_cb(GtkMenuItem * menuitem,UiFormGrid * formgrid)843 static void ldap_view_dn_mitem_cb (GtkMenuItem *menuitem, UiFormGrid *formgrid)
844 {
845 	const gchar *dn;
846 	BrowserWindow *bwin;
847         BrowserPerspective *pers;
848 
849 	dn = g_object_get_data (G_OBJECT (menuitem), "dn");
850         bwin = (BrowserWindow*) gtk_widget_get_toplevel ((GtkWidget*) formgrid);
851         pers = browser_window_change_perspective (bwin, _("LDAP browser"));
852 
853 	ldap_browser_perspective_display_ldap_entry (LDAP_BROWSER_PERSPECTIVE (pers), dn);
854 }
855 #endif
856 
857 static void
proxy_changed_cb(G_GNUC_UNUSED GdauiDataProxy * dp,G_GNUC_UNUSED GdaDataProxy * proxy,UiFormGrid * formgrid)858 proxy_changed_cb (G_GNUC_UNUSED GdauiDataProxy *dp, G_GNUC_UNUSED GdaDataProxy *proxy, UiFormGrid *formgrid)
859 {
860 	g_signal_emit (formgrid, ui_formgrid_signals [DATA_SET_CHANGED], 0);
861 }
862 
863 /**
864  * ui_formgrid_new
865  * @model: a #GdaDataModel
866  * @scroll_form: set to %TRUE to wrap the embedded form in a scrolled window
867  * @flags: the #GdauiDataProxyInfoFlag, specifying what to display in the new widget
868  *
869  * Creates a new #UiFormGrid widget suitable to display the data in @model
870  *
871  *  Returns: the new widget
872  */
873 GtkWidget *
ui_formgrid_new(GdaDataModel * model,gboolean scroll_form,GdauiDataProxyInfoFlag flags)874 ui_formgrid_new (GdaDataModel *model, gboolean scroll_form, GdauiDataProxyInfoFlag flags)
875 {
876 	UiFormGrid *formgrid;
877 	GdaDataProxy *proxy;
878 
879 	g_return_val_if_fail (!model || GDA_IS_DATA_MODEL (model), NULL);
880 
881 	formgrid = (UiFormGrid *) g_object_new (UI_TYPE_FORMGRID, "scroll-form", scroll_form, NULL);
882 	formgrid->priv->flags = flags;
883 
884 	/* a raw form and a raw grid for the same proxy */
885 	g_object_set (formgrid->priv->raw_grid, "model", model, NULL);
886 	proxy = gdaui_data_proxy_get_proxy (GDAUI_DATA_PROXY (formgrid->priv->raw_grid));
887 	g_object_set (formgrid->priv->raw_form, "model", proxy, NULL);
888 	gdaui_data_proxy_set_write_mode (GDAUI_DATA_PROXY (formgrid->priv->raw_form),
889 					 GDAUI_DATA_PROXY_WRITE_ON_DEMAND);
890 	g_object_set (G_OBJECT (formgrid->priv->info),
891 		      "flags", formgrid->priv->flags | GRID_FLAGS, NULL);
892 
893 	g_signal_connect (formgrid->priv->raw_grid, "proxy-changed",
894 			  G_CALLBACK (proxy_changed_cb), formgrid);
895 
896 	/* no more than 300 rows at a time */
897 	if (model) {
898 		gda_data_proxy_set_sample_size (proxy, 300);
899 		if (flags & GDAUI_DATA_PROXY_INFO_ROW_MODIFY_BUTTONS)
900 			g_object_set (G_OBJECT (formgrid), "compute-mod-statements", TRUE, NULL);
901 	}
902 
903 
904 	return (GtkWidget *) formgrid;
905 }
906 
907 static void
handle_user_prefs_for_sql_statement(UiFormGrid * formgrid,BrowserConnection * bcnc,GdaSqlStatement * sqlst)908 handle_user_prefs_for_sql_statement (UiFormGrid *formgrid, BrowserConnection *bcnc,
909 				     GdaSqlStatement *sqlst)
910 {
911 	g_assert (sqlst);
912 	if (sqlst->stmt_type == GDA_SQL_STATEMENT_COMPOUND) {
913 		GdaSqlStatementCompound *comp;
914 		GSList *list;
915 		comp = (GdaSqlStatementCompound*) sqlst->contents;
916 		for (list = comp->stmt_list; list; list = list->next)
917 			handle_user_prefs_for_sql_statement (formgrid, bcnc,
918 							     (GdaSqlStatement *) list->data);
919 	}
920 	else {
921 		GdaSet *set;
922 		set = (GdaSet*) ui_formgrid_get_form_data_set (UI_FORMGRID (formgrid));
923 
924 		GdaSqlStatementSelect *sel;
925 		GSList *list;
926 		gint pos;
927 		sel = (GdaSqlStatementSelect*) sqlst->contents;
928 		for (pos = 0, list = sel->expr_list; list; pos ++, list = list->next) {
929 			GdaSqlSelectField *field = (GdaSqlSelectField*) list->data;
930 			if (! field->validity_meta_object ||
931 			    (field->validity_meta_object->obj_type != GDA_META_DB_TABLE) ||
932 			    !field->validity_meta_table_column)
933 				continue;
934 
935 			gchar *plugin;
936 			plugin = browser_connection_get_table_column_attribute (bcnc,
937 										GDA_META_TABLE (field->validity_meta_object),
938 										field->validity_meta_table_column,
939 										BROWSER_CONNECTION_COLUMN_PLUGIN, NULL);
940 			if (!plugin)
941 				continue;
942 
943 			GdaHolder *holder;
944 			holder = gda_set_get_nth_holder (set, pos);
945 			if (holder) {
946 				GValue *value;
947 				value = gda_value_new_from_string (plugin, G_TYPE_STRING);
948 				gda_holder_set_attribute_static (holder, GDAUI_ATTRIBUTE_PLUGIN, value);
949 				gda_value_free (value);
950 			}
951 			g_free (plugin);
952 		}
953 	}
954 }
955 
956 /**
957  * ui_formgrid_handle_user_prefs
958  * @formgrid: a #UiFormGrid widget
959  * @bcnc: (allow-none): a #BrowserConnection, or %NULL to let @formgrid determine it itself
960  * @stmt: the #GdaStatement which has been executed to produce the #GdaDataModel displayed in @formgrid
961  *
962  * Takes into account the UI preferences of the user
963  */
964 void
ui_formgrid_handle_user_prefs(UiFormGrid * formgrid,BrowserConnection * bcnc,GdaStatement * stmt)965 ui_formgrid_handle_user_prefs (UiFormGrid *formgrid, BrowserConnection *bcnc, GdaStatement *stmt)
966 {
967 	g_return_if_fail (UI_IS_FORMGRID (formgrid));
968 	if (bcnc)
969 		g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
970 	else {
971 		bcnc = get_browser_connection (formgrid);
972 		if (!bcnc)
973 			return;
974 	}
975 	if (stmt)
976 		g_return_if_fail (GDA_IS_STATEMENT (stmt));
977 	else
978 		return;
979 
980 	GdaSqlStatement *sqlst;
981 	g_object_get ((GObject*) stmt, "structure", &sqlst, NULL);
982 	if (!sqlst)
983 		return;
984 
985 	GError *lerror = NULL;
986 	if (((sqlst->stmt_type != GDA_SQL_STATEMENT_SELECT) &&
987 	     (sqlst->stmt_type != GDA_SQL_STATEMENT_COMPOUND)) ||
988 	    !browser_connection_normalize_sql_statement (bcnc, sqlst, &lerror)) {
989 		if (lerror)
990 			g_print ("[%s]\n", lerror->message);
991 		goto out;
992 	}
993 
994 	handle_user_prefs_for_sql_statement (formgrid, bcnc, sqlst);
995  out:
996 	gda_sql_statement_free (sqlst);
997 }
998 
999 
1000 
1001 static void
ui_formgrid_set_property(GObject * object,guint param_id,G_GNUC_UNUSED const GValue * value,GParamSpec * pspec)1002 ui_formgrid_set_property (GObject *object,
1003 			  guint param_id,
1004 			  G_GNUC_UNUSED const GValue *value,
1005 			  GParamSpec *pspec)
1006 {
1007 	UiFormGrid *formgrid;
1008 
1009 	formgrid = UI_FORMGRID (object);
1010 
1011 	switch (param_id) {
1012 	case PROP_SCROLL_FORM:
1013 		formgrid->priv->scroll_form = g_value_get_boolean (value);
1014 		break;
1015 	case PROP_AUTOMOD:
1016 		formgrid->priv->compute_mod_stmt = g_value_get_boolean (value);
1017 		if (formgrid->priv->mod_stmt_auto_computed && !formgrid->priv->compute_mod_stmt) {
1018 			/* clean up the mod stmt */
1019 			ModType mod;
1020 			GdaDataModel *model;
1021 			g_object_get (formgrid->priv->raw_grid, "model", &model, NULL);
1022 			for (mod = MOD_INSERT; mod < MOD_LAST; mod++) {
1023 				if (! formgrid->priv->mod_stmt[mod])
1024 					continue;
1025 				g_object_unref (formgrid->priv->mod_stmt [mod]);
1026 			}
1027 			g_object_set (model, "delete-stmt", NULL,
1028 				      "insert-stmt", NULL, NULL,
1029 				      "update-stmt", NULL, NULL);
1030 			g_object_unref (model);
1031 			formgrid->priv->mod_stmt_auto_computed = FALSE;
1032 		}
1033 		else if (!formgrid->priv->mod_stmt_auto_computed && formgrid->priv->compute_mod_stmt) {
1034 			GdaDataModel *model;
1035 			g_object_get (formgrid->priv->raw_grid, "model", &model, NULL);
1036 			compute_modification_statements (formgrid, model);
1037 			g_object_unref (model);
1038 		}
1039 		break;
1040 	default:
1041 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1042 		break;
1043 	}
1044 }
1045 
1046 static void
ui_formgrid_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)1047 ui_formgrid_get_property (GObject *object,
1048 			  guint param_id,
1049 			  GValue *value,
1050 			  GParamSpec *pspec)
1051 {
1052 	UiFormGrid *formgrid;
1053 
1054 	formgrid = UI_FORMGRID (object);
1055 
1056 	switch (param_id) {
1057 	case PROP_RAW_GRID:
1058 		g_value_set_object (value, formgrid->priv->raw_grid);
1059 		break;
1060 	case PROP_RAW_FORM:
1061 		g_value_set_object (value, formgrid->priv->raw_form);
1062 		break;
1063 	case PROP_INFO:
1064 		g_value_set_object (value, formgrid->priv->info);
1065 		break;
1066 	case PROP_AUTOMOD:
1067 		g_value_set_boolean (value, formgrid->priv->compute_mod_stmt);
1068 		break;
1069 	default:
1070 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1071 		break;
1072 	}
1073 }
1074 
1075 /**
1076  * ui_formgrid_get_selection
1077  * @formgrid: a #UiFormGrid widget
1078  *
1079  * Returns the list of the currently selected rows in a #UiFormGrid widget.
1080  * The returned value is a list of integers, which represent each of the selected rows.
1081  *
1082  * If new rows have been inserted, then those new rows will have a row number equal to -1.
1083  * This function is a wrapper around the gdaui_raw_grid_get_selection() function.
1084  *
1085  * Returns: a new array, should be freed (by calling g_array_free() and passing %TRUE as last argument) when no longer needed.
1086  */
1087 GArray *
ui_formgrid_get_selection(UiFormGrid * formgrid)1088 ui_formgrid_get_selection (UiFormGrid *formgrid)
1089 {
1090 	g_return_val_if_fail (UI_IS_FORMGRID (formgrid), NULL);
1091 	g_return_val_if_fail (formgrid->priv, NULL);
1092 
1093 	return gdaui_data_selector_get_selected_rows (GDAUI_DATA_SELECTOR (formgrid->priv->raw_grid));
1094 }
1095 
1096 /**
1097  * ui_formgrid_get_form_data_set
1098  */
1099 GdaDataModelIter *
ui_formgrid_get_form_data_set(UiFormGrid * formgrid)1100 ui_formgrid_get_form_data_set (UiFormGrid *formgrid)
1101 {
1102 	g_return_val_if_fail (UI_IS_FORMGRID (formgrid), NULL);
1103 	g_return_val_if_fail (formgrid->priv, NULL);
1104 
1105 	return gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR (formgrid->priv->raw_form));
1106 }
1107 
1108 /**
1109  * ui_formgrid_get_grid_data_set
1110  */
1111 GdaDataModelIter *
ui_formgrid_get_grid_data_set(UiFormGrid * formgrid)1112 ui_formgrid_get_grid_data_set (UiFormGrid *formgrid)
1113 {
1114 	g_return_val_if_fail (UI_IS_FORMGRID (formgrid), NULL);
1115 	g_return_val_if_fail (formgrid->priv, NULL);
1116 
1117 	return gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR (formgrid->priv->raw_grid));
1118 }
1119 
1120 
1121 /**
1122  * ui_formgrid_set_sample_size
1123  * @formgrid: a #UiFormGrid widget
1124  * @sample_size: the sample size
1125  *
1126  * Set the size of the sample displayed in @formgrid, see gdaui_raw_grid_set_sample_size()
1127  */
1128 void
ui_formgrid_set_sample_size(UiFormGrid * formgrid,gint sample_size)1129 ui_formgrid_set_sample_size (UiFormGrid *formgrid, gint sample_size)
1130 {
1131 	g_return_if_fail (UI_IS_FORMGRID (formgrid));
1132 	g_return_if_fail (formgrid->priv);
1133 
1134 	gdaui_raw_grid_set_sample_size (GDAUI_RAW_GRID (formgrid->priv->raw_grid), sample_size);
1135 }
1136 
1137 /**
1138  * ui_formgrid_get_grid_widget
1139  * @formgrid: a #UiFormGrid widget
1140  *
1141  * Returns: the #GdauiRawGrid embedded in @formgrid
1142  */
1143 GdauiRawGrid *
ui_formgrid_get_grid_widget(UiFormGrid * formgrid)1144 ui_formgrid_get_grid_widget (UiFormGrid *formgrid)
1145 {
1146 	g_return_val_if_fail (UI_IS_FORMGRID (formgrid), NULL);
1147 	g_return_val_if_fail (formgrid->priv, NULL);
1148 
1149 	return GDAUI_RAW_GRID (formgrid->priv->raw_grid);
1150 }
1151 
1152 /**
1153  * ui_formgrid_set_connection
1154  * @formgrid: a #UiFormGrid widget
1155  * @bcnc: (allow-none): a #BrowserConnection, or %NULL
1156  *
1157  * Tells @formgrid to use @bcnc as connection when actions have to be executed
1158  */
1159 void
ui_formgrid_set_connection(UiFormGrid * formgrid,BrowserConnection * bcnc)1160 ui_formgrid_set_connection (UiFormGrid *formgrid, BrowserConnection *bcnc)
1161 {
1162 	g_return_if_fail (UI_IS_FORMGRID (formgrid));
1163 	g_return_if_fail (!bcnc || BROWSER_IS_CONNECTION (bcnc));
1164 
1165 	if (formgrid->priv->bcnc) {
1166 		g_object_unref (formgrid->priv->bcnc);
1167 		formgrid->priv->bcnc = NULL;
1168 	}
1169 	if (bcnc)
1170 		formgrid->priv->bcnc = g_object_ref (bcnc);
1171 }
1172 
1173 static void
compute_modification_statements(UiFormGrid * formgrid,GdaDataModel * model)1174 compute_modification_statements (UiFormGrid *formgrid, GdaDataModel *model)
1175 {
1176 	/* clear existing modification statements */
1177 	ModType mod;
1178 	for (mod = MOD_INSERT; mod < MOD_LAST; mod++) {
1179 		if (formgrid->priv->mod_stmt[mod]) {
1180 			g_object_unref (formgrid->priv->mod_stmt[mod]);
1181 			formgrid->priv->mod_stmt[mod] = NULL;
1182 		}
1183 	}
1184 
1185 	if (!model || !GDA_IS_DATA_SELECT (model))
1186 		return;
1187 
1188 	if (! formgrid->priv->compute_mod_stmt)
1189 		return;
1190 
1191 	gda_data_select_compute_modification_statements_ext (GDA_DATA_SELECT (model),
1192 							     GDA_DATA_SELECT_COND_ALL_COLUMNS, NULL);
1193 
1194 	formgrid->priv->mod_stmt_auto_computed = TRUE;
1195 	g_object_get (model,
1196 		      "insert-stmt", &formgrid->priv->mod_stmt[MOD_INSERT],
1197 		      "update-stmt", &formgrid->priv->mod_stmt[MOD_UPDATE],
1198 		      "delete-stmt", &formgrid->priv->mod_stmt[MOD_DELETE], NULL);
1199 
1200 	/*
1201 	for (mod = MOD_INSERT; mod < MOD_LAST; mod++) {
1202 		if (formgrid->priv->mod_stmt[mod]) {
1203 			gchar *sql;
1204 			GError *lerror = NULL;
1205 			sql = gda_statement_to_sql_extended (formgrid->priv->mod_stmt[mod], NULL, NULL,
1206 							     GDA_STATEMENT_SQL_PARAMS_LONG, NULL, &lerror);
1207 			g_print ("STMT[%d] = [%s]", mod, sql ? sql : "ERR");
1208 			if (!sql)
1209 				g_print (" --- %s", lerror && lerror->message ? lerror->message : "No detail");
1210 			g_clear_error (&lerror);
1211 			g_print ("\n");
1212 			g_free (sql);
1213 		}
1214 		else
1215 			g_print ("STMT[%d] = ---\n", mod);
1216 	}
1217 	*/
1218 }
1219