1 /*
2 * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org>
3 * Copyright (C) 2010 David King <davidk@openismus.com>
4 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <gtk/gtk.h>
25 #include <glib/gi18n-lib.h>
26 #include "gdaui-server-operation.h"
27 #include "gdaui-basic-form.h"
28 #include "gdaui-raw-grid.h"
29 #include "gdaui-raw-form.h"
30 #include "gdaui-data-store.h"
31 #include "gdaui-data-proxy.h"
32 #include "gdaui-data-selector.h"
33 #include "gdaui-data-proxy-info.h"
34 #include <libgda/gda-debug-macros.h>
35
36 static void gdaui_server_operation_class_init (GdauiServerOperationClass *class);
37 static void gdaui_server_operation_init (GdauiServerOperation *wid);
38 static void gdaui_server_operation_dispose (GObject *object);
39
40 static void gdaui_server_operation_set_property (GObject *object,
41 guint param_id,
42 const GValue *value,
43 GParamSpec *pspec);
44 static void gdaui_server_operation_get_property (GObject *object,
45 guint param_id,
46 GValue *value,
47 GParamSpec *pspec);
48
49 static void gdaui_server_operation_fill (GdauiServerOperation *form);
50
51 /* properties */
52 enum {
53 PROP_0,
54 PROP_SERVER_OP_OBJ,
55 PROP_OPT_HEADER
56 };
57
58 typedef struct _WidgetData {
59 struct _WidgetData *parent;
60 gchar *path_name; /* NULL if for SEQUENCE_ITEM */
61 GSList *children;
62 GtkWidget *widget;
63 } WidgetData;
64 #define WIDGET_DATA(x) ((WidgetData*)(x))
65
66 struct _GdauiServerOperationPriv
67 {
68 GdaServerOperation *op;
69 GSList *widget_data; /* list of WidgetData structures */
70 #ifdef HAVE_LIBGLADE
71 GladeXML *glade;
72 #endif
73 gboolean opt_header;
74 };
75
76 WidgetData *widget_data_new (WidgetData *parent, const gchar *path_name);
77 void widget_data_free (WidgetData *wd);
78 WidgetData *widget_data_find (GdauiServerOperation *form, const gchar *path);
79
80 WidgetData *
widget_data_new(WidgetData * parent,const gchar * path_name)81 widget_data_new (WidgetData *parent, const gchar *path_name)
82 {
83 WidgetData *wd;
84
85 wd = g_new0 (WidgetData, 1);
86 wd->parent = parent;
87 if (path_name)
88 wd->path_name = g_strdup (path_name);
89 if (parent)
90 parent->children = g_slist_append (parent->children, wd);
91 return wd;
92 }
93
94 void
widget_data_free(WidgetData * wd)95 widget_data_free (WidgetData *wd)
96 {
97 g_free (wd->path_name);
98 g_slist_foreach (wd->children, (GFunc) widget_data_free, NULL);
99 g_slist_free (wd->children);
100 g_free (wd);
101 }
102
103 WidgetData *
widget_data_find(GdauiServerOperation * form,const gchar * path)104 widget_data_find (GdauiServerOperation *form, const gchar *path)
105 {
106 gchar **array;
107 gint i, index;
108 WidgetData *wd = NULL;
109 GSList *list;
110
111 if (!path)
112 return NULL;
113 g_assert (*path == '/');
114
115 array = g_strsplit (path, "/", 0);
116 if (!array [1]) {
117 g_strfreev (array);
118 return NULL;
119 }
120
121 list = form->priv->widget_data;
122 while (list && !wd) {
123 if (WIDGET_DATA (list->data)->path_name &&
124 !strcmp (WIDGET_DATA (list->data)->path_name, array[1]))
125 wd = WIDGET_DATA (list->data);
126 list = list->next;
127 }
128
129 i = 2;
130 while (array[i] && wd) {
131 char *end;
132 list = wd->children;
133
134 index = strtol (array[i], &end, 10);
135 if (end && *end)
136 index = -1; /* could not convert array[i] to an int */
137
138 if ((index >= 0) && wd->children && !WIDGET_DATA (wd->children->data)->path_name)
139 wd = g_slist_nth_data (wd->children, index);
140 else {
141 wd = NULL;
142 while (list && !wd) {
143 if (WIDGET_DATA (list->data)->path_name &&
144 !strcmp (WIDGET_DATA (list->data)->path_name, array[i]))
145 wd = WIDGET_DATA (list->data);
146 list = list->next;
147 }
148 }
149 i++;
150 }
151
152 /*g_print ("## %s (%s): %p\n", __FUNCTION__, path, wd);*/
153 g_strfreev (array);
154 return wd;
155 }
156
157 /* get a pointer to the parents to be able to call their destructor */
158 static GObjectClass *parent_class = NULL;
159
160 GType
gdaui_server_operation_get_type(void)161 gdaui_server_operation_get_type (void)
162 {
163 static GType type = 0;
164
165 if (G_UNLIKELY (type == 0)) {
166 static const GTypeInfo info = {
167 sizeof (GdauiServerOperationClass),
168 (GBaseInitFunc) NULL,
169 (GBaseFinalizeFunc) NULL,
170 (GClassInitFunc) gdaui_server_operation_class_init,
171 NULL,
172 NULL,
173 sizeof (GdauiServerOperation),
174 0,
175 (GInstanceInitFunc) gdaui_server_operation_init,
176 0
177 };
178
179 type = g_type_register_static (GTK_TYPE_BOX, "GdauiServerOperation", &info, 0);
180 }
181
182 return type;
183 }
184
185 static void
gdaui_server_operation_class_init(GdauiServerOperationClass * class)186 gdaui_server_operation_class_init (GdauiServerOperationClass *class)
187 {
188 GObjectClass *object_class = G_OBJECT_CLASS (class);
189
190 parent_class = g_type_class_peek_parent (class);
191
192 object_class->dispose = gdaui_server_operation_dispose;
193
194 /* Properties */
195 object_class->set_property = gdaui_server_operation_set_property;
196 object_class->get_property = gdaui_server_operation_get_property;
197 g_object_class_install_property (object_class, PROP_SERVER_OP_OBJ,
198 g_param_spec_object ("server-operation",
199 _("The specification of the operation to implement"),
200 NULL, GDA_TYPE_SERVER_OPERATION,
201 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
202 G_PARAM_READABLE));
203 g_object_class_install_property (object_class, PROP_OPT_HEADER,
204 g_param_spec_boolean ("hide-single-header",
205 _("Request section header to be hidden if there is only one section"),
206 NULL, FALSE, G_PARAM_CONSTRUCT | G_PARAM_READABLE |
207 G_PARAM_WRITABLE));
208 }
209
210 static void
gdaui_server_operation_init(GdauiServerOperation * wid)211 gdaui_server_operation_init (GdauiServerOperation * wid)
212 {
213 wid->priv = g_new0 (GdauiServerOperationPriv, 1);
214 wid->priv->op = NULL;
215 wid->priv->widget_data = NULL;
216 #ifdef HAVE_LIBGLADE
217 wid->priv->glade = NULL;
218 #endif
219 wid->priv->opt_header = FALSE;
220
221 gtk_orientable_set_orientation (GTK_ORIENTABLE (wid), GTK_ORIENTATION_VERTICAL);
222 }
223
224
225 /**
226 * gdaui_server_operation_new:
227 * @op: a #GdaServerOperation structure
228 *
229 * Creates a new #GdauiServerOperation widget using all the parameters provided in @paramlist.
230 *
231 * The global layout is rendered using a table (a #GtkTable), and an entry is created for each
232 * node of @paramlist.
233 *
234 * Returns: the new widget
235 *
236 * Since: 4.2
237 */
238 GtkWidget *
gdaui_server_operation_new(GdaServerOperation * op)239 gdaui_server_operation_new (GdaServerOperation *op)
240 {
241 GObject *obj;
242
243 obj = g_object_new (GDAUI_TYPE_SERVER_OPERATION, "server-operation", op, NULL);
244
245 return (GtkWidget *) obj;
246 }
247
248 static void sequence_item_added_cb (GdaServerOperation *op, const gchar *seq_path, gint item_index, GdauiServerOperation *form);
249 static void sequence_item_remove_cb (GdaServerOperation *op, const gchar *seq_path, gint item_index, GdauiServerOperation *form);
250
251 static void
gdaui_server_operation_dispose(GObject * object)252 gdaui_server_operation_dispose (GObject *object)
253 {
254 GdauiServerOperation *form;
255
256 g_return_if_fail (object != NULL);
257 g_return_if_fail (GDAUI_IS_SERVER_OPERATION (object));
258 form = GDAUI_SERVER_OPERATION (object);
259
260 if (form->priv) {
261 /* paramlist */
262 if (form->priv->op) {
263 g_signal_handlers_disconnect_by_func (G_OBJECT (form->priv->op),
264 G_CALLBACK (sequence_item_added_cb), form);
265 g_signal_handlers_disconnect_by_func (G_OBJECT (form->priv->op),
266 G_CALLBACK (sequence_item_remove_cb), form);
267 g_object_unref (form->priv->op);
268 }
269
270 if (form->priv->widget_data) {
271 g_slist_foreach (form->priv->widget_data, (GFunc) widget_data_free, NULL);
272 g_slist_free (form->priv->widget_data);
273 form->priv->widget_data = NULL;
274 }
275
276 #ifdef HAVE_LIBGLADE
277 if (form->priv->glade)
278 g_object_unref (form->priv->glade);
279 #endif
280
281 /* the private area itself */
282 g_free (form->priv);
283 form->priv = NULL;
284 }
285
286 /* for the parent class */
287 parent_class->dispose (object);
288 }
289
290
291 static void
gdaui_server_operation_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)292 gdaui_server_operation_set_property (GObject *object,
293 guint param_id,
294 const GValue *value,
295 GParamSpec *pspec)
296 {
297 GdauiServerOperation *form;
298
299 form = GDAUI_SERVER_OPERATION (object);
300 if (form->priv) {
301 switch (param_id) {
302 case PROP_SERVER_OP_OBJ:
303 if (form->priv->op) {
304 TO_IMPLEMENT;
305 g_assert_not_reached ();
306 }
307
308 form->priv->op = GDA_SERVER_OPERATION(g_value_get_object (value));
309 if (form->priv->op) {
310 g_return_if_fail (GDA_IS_SERVER_OPERATION (form->priv->op));
311
312 g_object_ref (form->priv->op);
313
314 gdaui_server_operation_fill (form);
315 g_signal_connect (G_OBJECT (form->priv->op), "sequence-item-added",
316 G_CALLBACK (sequence_item_added_cb), form);
317 g_signal_connect (G_OBJECT (form->priv->op), "sequence-item-remove",
318 G_CALLBACK (sequence_item_remove_cb), form);
319 }
320 break;
321 case PROP_OPT_HEADER:
322 form->priv->opt_header = g_value_get_boolean (value);
323 break;
324 default:
325 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
326 break;
327 }
328 }
329 }
330
331 static void
gdaui_server_operation_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)332 gdaui_server_operation_get_property (GObject *object,
333 guint param_id,
334 GValue *value,
335 GParamSpec *pspec)
336 {
337 GdauiServerOperation *form;
338
339 form = GDAUI_SERVER_OPERATION (object);
340 if (form->priv) {
341 switch (param_id) {
342 case PROP_SERVER_OP_OBJ:
343 g_value_set_object (value, form->priv->op);
344 break;
345 case PROP_OPT_HEADER:
346 g_value_set_boolean (value, form->priv->opt_header);
347 break;
348 default:
349 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
350 break;
351 }
352 }
353 }
354
355 /*
356 * create the entries in the widget
357 */
358
359 static GtkWidget *fill_create_widget (GdauiServerOperation *form, const gchar *path,
360 gchar **section_str, GSList **label_widgets);
361 static void seq_add_item (GtkButton *button, GdauiServerOperation *form);
362 static void seq_del_item (GtkButton *button, GdauiServerOperation *form);
363
364
365 /*
366 * @path is like "/SEQ", DOES NOT contain the index of the item to add, which is also in @index
367 */
368 static void
sequence_grid_attach_widget(GdauiServerOperation * form,GtkWidget * grid,GtkWidget * wid,const gchar * path,gint index)369 sequence_grid_attach_widget (GdauiServerOperation *form, GtkWidget *grid, GtkWidget *wid,
370 const gchar *path, gint index)
371 {
372 GtkWidget *image;
373 guint min, size;
374
375 min = gda_server_operation_get_sequence_min_size (form->priv->op, path);
376 size = gda_server_operation_get_sequence_size (form->priv->op, path);
377
378 /* new widget */
379 gtk_grid_attach (GTK_GRID (grid), wid, 0, index, 1, 1);
380 gtk_widget_show (wid);
381
382 /* "-" button */
383 image = gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU);
384 wid = gtk_button_new ();
385 gtk_button_set_image (GTK_BUTTON (wid), image);
386 gtk_grid_attach (GTK_GRID (grid), wid, 1, index, 1, 1);
387 gtk_widget_show (wid);
388 g_object_set_data_full (G_OBJECT (wid), "_seq_path", g_strdup (path), g_free);
389 g_object_set_data (G_OBJECT (wid), "_index", GINT_TO_POINTER (index+1));
390 g_signal_connect (G_OBJECT (wid), "clicked",
391 G_CALLBACK (seq_del_item), form);
392 if (size <= min)
393 gtk_widget_set_sensitive (wid, FALSE);
394 }
395
396 static GtkWidget *create_table_fields_array_create_widget (GdauiServerOperation *form, const gchar *path,
397 gchar **section_str, GSList **label_widgets);
398 static GtkWidget *
fill_create_widget(GdauiServerOperation * form,const gchar * path,gchar ** section_str,GSList ** label_widgets)399 fill_create_widget (GdauiServerOperation *form, const gchar *path, gchar **section_str, GSList **label_widgets)
400 {
401 GdaServerOperationNode *info_node;
402 GtkWidget *plwid = NULL;
403
404 info_node = gda_server_operation_get_node_info (form->priv->op, path);
405 g_assert (info_node);
406
407 if (label_widgets)
408 *label_widgets = NULL;
409 if (section_str)
410 *section_str = NULL;
411
412 /* very custom widget rendering goes here */
413 if ((gda_server_operation_get_op_type (form->priv->op) == GDA_SERVER_OPERATION_CREATE_TABLE) &&
414 !strcmp (path, "/FIELDS_A"))
415 return create_table_fields_array_create_widget (form, path, section_str, label_widgets);
416
417 /* generic widget rendering */
418 switch (info_node->type) {
419 case GDA_SERVER_OPERATION_NODE_PARAMLIST: {
420 GdaSet *plist;
421
422 plist = info_node->plist;
423 plwid = gdaui_basic_form_new (plist);
424 gdaui_basic_form_set_unknown_color (GDAUI_BASIC_FORM (plwid), 0., 0., 0., 0.);
425 g_object_set ((GObject*) plwid, "show-actions", FALSE, NULL);
426
427 if (section_str) {
428 const gchar *name;
429 name = g_object_get_data (G_OBJECT (plist), "name");
430 if (name && *name)
431 *section_str = g_strdup_printf ("<b>%s:</b>", name);
432 else
433 *section_str = NULL;
434 }
435 if (label_widgets) {
436 GSList *params;
437
438 params = plist->holders;
439 while (params) {
440 GtkWidget *label_entry;
441
442 label_entry = gdaui_basic_form_get_label_widget (GDAUI_BASIC_FORM (plwid),
443 GDA_HOLDER (params->data));
444 if (label_entry && !g_slist_find (*label_widgets, label_entry))
445 *label_widgets = g_slist_prepend (*label_widgets, label_entry);
446 params = params->next;
447 }
448 *label_widgets = g_slist_reverse (*label_widgets);
449 }
450 break;
451 }
452 case GDA_SERVER_OPERATION_NODE_DATA_MODEL: {
453 GdaDataModel *model;
454 GtkWidget *winfo;
455 GtkWidget *box, *grid;
456
457 plwid = gtk_scrolled_window_new (NULL, NULL);
458 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (plwid),
459 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
460 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (plwid),
461 GTK_SHADOW_NONE);
462
463 model = info_node->model;
464 grid = gdaui_raw_grid_new (model);
465 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (plwid), grid);
466 gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (plwid))),
467 GTK_SHADOW_NONE);
468 gdaui_data_proxy_set_write_mode (GDAUI_DATA_PROXY (grid),
469 GDAUI_DATA_PROXY_WRITE_ON_ROW_CHANGE);
470 gtk_widget_show (grid);
471
472 g_object_set (G_OBJECT (grid), "info-cell-visible", FALSE, NULL);
473
474 winfo = gdaui_data_proxy_info_new (GDAUI_DATA_PROXY (grid),
475 GDAUI_DATA_PROXY_INFO_ROW_MODIFY_BUTTONS);
476
477 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
478 gtk_box_pack_start (GTK_BOX (box), plwid, TRUE, TRUE, 0);
479 gtk_widget_show (plwid);
480
481 gtk_box_pack_start (GTK_BOX (box), winfo, FALSE, TRUE, 0);
482 gtk_widget_show (winfo);
483
484 plwid = box;
485
486 if (section_str)
487 *section_str = g_strdup_printf ("<b>%s:</b>",
488 (gchar*) g_object_get_data (G_OBJECT (model), "name"));
489
490 if (label_widgets) {
491 GtkWidget *label_entry;
492 gchar *str;
493
494 if (info_node->status == GDA_SERVER_OPERATION_STATUS_REQUIRED) {
495 str = g_strdup_printf ("<b>%s:</b>",
496 (gchar*) g_object_get_data (G_OBJECT (model), "name"));
497 label_entry = gtk_label_new (str);
498 gtk_label_set_use_markup (GTK_LABEL (label_entry), TRUE);
499 }
500 else {
501 str = g_strdup_printf ("%s:", (gchar*) g_object_get_data (G_OBJECT (model), "name"));
502 label_entry = gtk_label_new (str);
503 }
504 g_free (str);
505 gtk_misc_set_alignment (GTK_MISC (label_entry), 0., 0.);
506
507 gtk_widget_show (label_entry);
508 str = (gchar *) g_object_get_data (G_OBJECT (model), "descr");
509 if (str && *str)
510 gtk_widget_set_tooltip_text (label_entry, str);
511
512 *label_widgets = g_slist_prepend (*label_widgets, label_entry);
513 }
514
515 gtk_widget_set_vexpand (plwid, TRUE);
516 break;
517 }
518 case GDA_SERVER_OPERATION_NODE_PARAM: {
519 GdaSet *plist;
520 GdaHolder *param;
521 GSList *list;
522
523 param = info_node->param;
524 list = g_slist_append (NULL, param);
525 plist = gda_set_new (list);
526 g_slist_free (list);
527 plwid = gdaui_basic_form_new (plist);
528 gdaui_basic_form_set_unknown_color (GDAUI_BASIC_FORM (plwid), 0., 0., 0., 0.);
529 g_object_set ((GObject*) plwid, "show-actions", FALSE, NULL);
530 /* we don't need plist anymore */
531 g_object_unref (plist);
532
533 if (section_str)
534 *section_str = g_strdup_printf ("<b>%s:</b>",
535 (gchar*) g_object_get_data (G_OBJECT (param), "name"));
536 if (label_widgets) {
537 GtkWidget *label_entry;
538
539 label_entry = gdaui_basic_form_get_label_widget (GDAUI_BASIC_FORM (plwid), param);
540 *label_widgets = g_slist_prepend (*label_widgets, label_entry);
541 }
542 break;
543 }
544 case GDA_SERVER_OPERATION_NODE_SEQUENCE: {
545 guint n, size;
546 GtkWidget *grid, *wid, *image;
547 WidgetData *wdp, *wd;
548 gchar *parent_path = NULL, *path_name = NULL;
549 guint max;
550
551 max = gda_server_operation_get_sequence_max_size (form->priv->op, path);
552 if (section_str) {
553 const gchar *seq_name;
554 seq_name = gda_server_operation_get_sequence_name (form->priv->op, path);
555 *section_str = g_strdup_printf ("<b>%s:</b>", seq_name);
556 }
557
558 plwid = gtk_scrolled_window_new (NULL, NULL);
559
560 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (plwid),
561 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
562 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (plwid),
563 GTK_SHADOW_NONE);
564
565 size = gda_server_operation_get_sequence_size (form->priv->op, path);
566 grid = gtk_grid_new ();
567 gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
568 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (plwid), grid);
569 gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (plwid))),
570 GTK_SHADOW_NONE);
571 gtk_widget_show (grid);
572
573 parent_path = gda_server_operation_get_node_parent (form->priv->op, path);
574 path_name = gda_server_operation_get_node_path_portion (form->priv->op, path);
575 wdp = widget_data_find (form, parent_path);
576 wd = widget_data_new (wdp, path_name);
577 wd->widget = grid;
578 if (! wdp)
579 form->priv->widget_data = g_slist_append (form->priv->widget_data, wd);
580 g_free (parent_path);
581 g_free (path_name);
582
583 /* existing entries */
584 for (n = 0; n < size; n++) {
585 GtkWidget *wid;
586 gchar *str;
587
588 str = g_strdup_printf ("%s/%d", path, n);
589 wid = fill_create_widget (form, str, NULL, NULL);
590 sequence_grid_attach_widget (form, grid, wid, path, n);
591 g_free (str);
592 }
593
594 if (size < max) {
595 /* last row is for new entries */
596 wid = gtk_label_new (_("Add"));
597 gtk_misc_set_alignment (GTK_MISC (wid), .0, -1);
598 gtk_grid_attach (GTK_GRID (grid), wid, 0, size, 1, 1);
599 gtk_widget_show (wid);
600
601 image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
602 wid = gtk_button_new ();
603 gtk_button_set_image (GTK_BUTTON (wid), image);
604 gtk_grid_attach (GTK_GRID (grid), wid, 1, size, 1, 1);
605 gtk_widget_show (wid);
606
607 g_signal_connect (G_OBJECT (wid), "clicked",
608 G_CALLBACK (seq_add_item), form);
609 g_object_set_data_full (G_OBJECT (wid), "_seq_path", g_strdup (path), g_free);
610 }
611
612 gtk_widget_set_vexpand (plwid, TRUE);
613 break;
614 }
615 case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM: {
616 gchar **node_names;
617 gint size;
618 gchar *parent_path;
619 WidgetData *wdp, *wdi;
620
621 node_names = gda_server_operation_get_sequence_item_names (form->priv->op, path);
622 size = g_strv_length (node_names);
623 if (size > 1) {
624 GtkWidget *grid;
625 gint i, tab_index;
626
627 grid = gtk_grid_new ();
628 for (i = 0, tab_index = 0; i < size; i++) {
629 GtkWidget *wid;
630 GSList *lab_list, *list;
631 gint nb_labels = 0;
632
633 wid = fill_create_widget (form, node_names[i], NULL, &lab_list);
634 for (list = lab_list; list; list = list->next) {
635 GtkWidget *label_entry = (GtkWidget *) list->data;
636 GtkWidget *parent;
637
638 if (label_entry) {
639 parent = gtk_widget_get_parent (label_entry);
640 if (parent) {
641 g_object_ref (label_entry);
642 gtk_container_remove (GTK_CONTAINER (parent), label_entry);
643 }
644 gtk_grid_attach (GTK_GRID (grid), label_entry,
645 0, tab_index, 1, 1);
646 if (parent)
647 g_object_unref (label_entry);
648 }
649 nb_labels++;
650 tab_index++;
651 }
652 g_slist_free (lab_list);
653
654 if (nb_labels > 0)
655 gtk_grid_attach (GTK_GRID (grid), wid, 1,
656 tab_index - nb_labels, 1, nb_labels);
657 else {
658 gtk_grid_attach (GTK_GRID (grid), wid, 1, tab_index, 1, 1);
659 tab_index += 1;
660 }
661 gtk_widget_show (wid);
662 }
663 plwid = grid;
664 }
665 else
666 plwid = fill_create_widget (form, node_names[0], NULL, NULL);
667
668 parent_path = gda_server_operation_get_node_parent (form->priv->op, path);
669 wdp = widget_data_find (form, parent_path);
670 g_assert (wdp);
671 wdi = widget_data_new (wdp, NULL);
672 wdi->widget = plwid;
673
674 g_free (parent_path);
675 g_strfreev (node_names);
676 break;
677 }
678 default:
679 g_assert_not_reached ();
680 break;
681 }
682
683 return plwid;
684 }
685
686 static void
gdaui_server_operation_fill(GdauiServerOperation * form)687 gdaui_server_operation_fill (GdauiServerOperation *form)
688 {
689 gint i;
690 gchar **topnodes;
691 #ifdef HAVE_LIBGLADE
692 gchar *glade_file;
693 #endif
694
695 /* parameters list management */
696 if (!form->priv->op)
697 /* nothing to do */
698 return;
699
700 /* load Glade file for specific GUI if it exists */
701 #ifdef HAVE_LIBGLADE
702 glade_file = gdaui_gbr_get_data_dir_path ("server_operation.glade");
703 form->priv->glade = glade_xml_new (glade_file,
704 gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (form->priv->op)),
705 NULL);
706 g_free (glade_file);
707 if (form->priv->glade) {
708 GtkWidget *mainw;
709 mainw = glade_xml_get_widget (form->priv->glade,
710 gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (form->priv->op)));
711 if (mainw) {
712 gtk_box_pack_start (GTK_BOX (form), mainw, TRUE, TRUE, 0);
713 gtk_widget_show (mainw);
714 }
715 else {
716 g_object_unref (form->priv->glade);
717 form->priv->glade = NULL;
718 }
719 }
720 #endif
721
722 /* user visible widgets */
723 topnodes = gda_server_operation_get_root_nodes (form->priv->op);
724 i = 0;
725 while (topnodes[i]) {
726 GtkWidget *plwid;
727 gchar *section_str;
728 GtkWidget *container = NULL;
729
730 #ifdef HAVE_LIBGLADE
731 if (form->priv->glade) {
732 container = glade_xml_get_widget (form->priv->glade, topnodes[i]);
733 if (!container) {
734 i++;
735 continue;
736 }
737 }
738 #endif
739 if (!container)
740 container = (GtkWidget *) form;
741
742 plwid = fill_create_widget (form, topnodes[i], §ion_str, NULL);
743 if (plwid) {
744 GdaServerOperationNodeStatus status;
745 GtkWidget *label = NULL, *hbox = NULL;
746
747 if (! (form->priv->opt_header && (g_strv_length (topnodes) == 1)) && section_str) {
748 GtkWidget *lab;
749 label = gtk_label_new ("");
750 gtk_widget_show (label);
751 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
752 gtk_label_set_markup (GTK_LABEL (label), section_str);
753 g_free (section_str);
754
755 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); /* HIG */
756 gtk_widget_show (hbox);
757 lab = gtk_label_new (" ");
758 gtk_box_pack_start (GTK_BOX (hbox), lab, FALSE, FALSE, 0);
759 gtk_widget_show (lab);
760
761 gtk_box_pack_start (GTK_BOX (hbox), plwid, TRUE, TRUE, 0);
762 gtk_widget_show (plwid);
763 }
764 else
765 gtk_widget_show (plwid);
766
767
768 gda_server_operation_get_node_type (form->priv->op, topnodes[i], &status);
769 switch (status) {
770 case GDA_SERVER_OPERATION_STATUS_OPTIONAL: {
771 GtkWidget *exp;
772 exp = gtk_expander_new ("");
773 if (!label) {
774 gchar *str;
775 label = gtk_label_new ("");
776 gtk_widget_show (label);
777 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
778 str = g_strdup_printf ("<b>%s:</b>", _("Options"));
779 gtk_label_set_markup (GTK_LABEL (label), str);
780 g_free (str);
781 }
782
783 gtk_expander_set_label_widget (GTK_EXPANDER (exp), label);
784 gtk_box_pack_start (GTK_BOX (container), exp, TRUE, TRUE, 5);
785 if (hbox)
786 gtk_container_add (GTK_CONTAINER (exp), hbox);
787 else
788 gtk_container_add (GTK_CONTAINER (exp), plwid);
789 gtk_widget_show (exp);
790 break;
791 }
792 case GDA_SERVER_OPERATION_STATUS_REQUIRED: {
793 gboolean expand;
794 expand = gtk_widget_get_vexpand (plwid);
795
796 if (label)
797 gtk_box_pack_start (GTK_BOX (container), label, FALSE, TRUE, 5);
798 if (hbox)
799 gtk_box_pack_start (GTK_BOX (container), hbox, expand, TRUE, 0);
800 else
801 gtk_box_pack_start (GTK_BOX (container), plwid, expand, TRUE, 0);
802 break;
803 }
804 default:
805 break;
806 }
807 }
808
809 i++;
810 }
811
812 /* destroying unused widgets in the Glade description */
813 #ifdef HAVE_LIBGLADE
814 if (form->priv->glade) {
815 GList *widgets, *list;
816
817 widgets = glade_xml_get_widget_prefix (form->priv->glade, "/");
818 for (list = widgets; list; list = list->next) {
819 const gchar *name;
820
821 name = glade_get_widget_name ((GtkWidget *) (list->data));
822 if (!gda_server_operation_get_node_info (form->priv->op, name)) {
823 GtkWidget *parent;
824
825 /* dirty hack to remove a notebook page */
826 parent = gtk_widget_get_parent ((GtkWidget *) (list->data));
827 if (GTK_IS_VIEWPORT (parent))
828 parent = gtk_widget_get_parent (parent);
829 if (GTK_IS_SCROLLED_WINDOW (parent))
830 parent = gtk_widget_get_parent (parent);
831 if (GTK_IS_NOTEBOOK (parent)) {
832 gint pageno;
833
834 pageno = gtk_notebook_page_num (GTK_NOTEBOOK (parent),
835 (GtkWidget *) (list->data));
836 gtk_notebook_remove_page (GTK_NOTEBOOK (parent), pageno);
837 }
838 else
839 gtk_widget_destroy ((GtkWidget *) (list->data));
840 }
841 }
842 g_list_free (widgets);
843 }
844 #endif
845
846 g_strfreev (topnodes);
847
848 }
849
850 /*
851 * For sequences: adding an item by clicking on the "+" button
852 */
853 static void
seq_add_item(GtkButton * button,GdauiServerOperation * form)854 seq_add_item (GtkButton *button, GdauiServerOperation *form)
855 {
856 gchar *path;
857
858 path = g_object_get_data (G_OBJECT (button), "_seq_path");
859 gda_server_operation_add_item_to_sequence (form->priv->op, path);
860 }
861
862 /*
863 * For sequences: removing an item by clicking on the "-" button
864 */
865 static void
seq_del_item(GtkButton * button,GdauiServerOperation * form)866 seq_del_item (GtkButton *button, GdauiServerOperation *form)
867 {
868 gchar *seq_path, *item_path;
869 gint index;
870
871 seq_path = g_object_get_data (G_OBJECT (button), "_seq_path");
872 index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "_index")) - 1;
873 g_assert (index >= 0);
874 item_path = g_strdup_printf ("%s/%d", seq_path, index);
875 gda_server_operation_del_item_from_sequence (form->priv->op, item_path);
876 g_free (item_path);
877 }
878
879 /*
880 * For sequences: treating the "sequence-item-added" signal
881 */
882 struct MoveChild {
883 GtkWidget *widget;
884 guint16 top_attach;
885 };
886
887 static void
sequence_item_added_cb(GdaServerOperation * op,const gchar * seq_path,gint item_index,GdauiServerOperation * form)888 sequence_item_added_cb (GdaServerOperation *op, const gchar *seq_path, gint item_index, GdauiServerOperation *form)
889 {
890 GtkWidget *grid;
891 GList *children, *list, *to_move = NULL;
892 GtkWidget *wid;
893 gchar *str;
894 WidgetData *wd;
895 guint max, min, size;
896
897 max = gda_server_operation_get_sequence_max_size (op, seq_path);
898 min = gda_server_operation_get_sequence_min_size (op, seq_path);
899 size = gda_server_operation_get_sequence_size (op, seq_path);
900
901 wd = widget_data_find (form, seq_path);
902 g_assert (wd);
903 grid = wd->widget;
904 g_assert (grid);
905
906 /* move children DOWN if necessary */
907 children = gtk_container_get_children (GTK_CONTAINER (grid));
908 for (list = children; list; list = list->next) {
909 GtkWidget *child = GTK_WIDGET (list->data);
910
911 if (child) {
912 guint top_attach, left_attach;
913 gtk_container_child_get (GTK_CONTAINER (grid), child,
914 "top-attach", &top_attach,
915 "left-attach", &left_attach, NULL);
916 /* ADD/REMOVE button sensitivity */
917 if (left_attach == 1) {
918 if (top_attach == size-1)
919 gtk_widget_set_sensitive (child, (size < max) ? TRUE : FALSE);
920 else
921 gtk_widget_set_sensitive (child, (size > min) ? TRUE : FALSE);
922 }
923
924 /* move children DOWN if necessary and change the "_index" property */
925 if (top_attach >= (guint)item_index) {
926 struct MoveChild *mc;
927 gint index;
928
929 mc = g_new (struct MoveChild, 1);
930 mc->widget = child;
931 mc->top_attach = top_attach + 1;
932 to_move = g_list_append (to_move, mc);
933
934 index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (child), "_index"));
935 if (index > 0)
936 g_object_set_data (G_OBJECT (child), "_index",
937 GINT_TO_POINTER (index + 1));
938 }
939 }
940 }
941 g_list_free (children);
942
943
944 for (list = to_move; list; list = list->next) {
945 struct MoveChild *mc;
946
947 mc = (struct MoveChild *) (list->data);
948 gtk_container_child_set (GTK_CONTAINER (grid), mc->widget,
949 "top-attach", mc->top_attach,
950 "height", 1, NULL);
951 g_free (list->data);
952 }
953 g_list_free (to_move);
954
955 /* add widget corresponding to the new sequence item */
956 str = g_strdup_printf ("%s/%d", seq_path, item_index);
957 wid = fill_create_widget (form, str, NULL, NULL);
958 sequence_grid_attach_widget (form, grid, wid, seq_path, item_index);
959 g_free (str);
960 }
961
962 /*
963 * For sequences: treating the "sequence-item-remove" signal
964 */
965 static void
sequence_item_remove_cb(GdaServerOperation * op,const gchar * seq_path,gint item_index,GdauiServerOperation * form)966 sequence_item_remove_cb (GdaServerOperation *op, const gchar *seq_path, gint item_index, GdauiServerOperation *form)
967 {
968 GtkWidget *grid;
969 GList *children, *list, *to_move = NULL;
970 gchar *str;
971 WidgetData *wds, *wdi;
972 guint min, size;
973
974 min = gda_server_operation_get_sequence_min_size (op, seq_path);
975 size = gda_server_operation_get_sequence_size (op, seq_path);
976 /* note: size is the size of the sequence _before_ the actual removal of the sequence item */
977
978 wds = widget_data_find (form, seq_path);
979 g_assert (wds);
980 grid = wds->widget;
981 g_assert (grid);
982
983 /* remove widget */
984 str = g_strdup_printf ("%s/%d", seq_path, item_index);
985 wdi = widget_data_find (form, str);
986 g_free (str);
987 g_assert (wdi);
988 gtk_widget_destroy (wdi->widget);
989 g_assert (wdi->parent == wds);
990 wds->children = g_slist_remove (wds->children, wdi);
991 widget_data_free (wdi);
992
993 /* remove the widget associated to the sequence item */
994 children = gtk_container_get_children (GTK_CONTAINER (grid));
995 for (list = children; list; ) {
996 GtkWidget *child = GTK_WIDGET (list->data);
997 if (child) {
998 guint top_attach;
999 gtk_container_child_get (GTK_CONTAINER (grid), child,
1000 "top-attach", &top_attach, NULL);
1001 if (top_attach == (guint)item_index) {
1002 gtk_widget_destroy (child);
1003 g_list_free (children);
1004 children = gtk_container_get_children (GTK_CONTAINER (grid));
1005 list = children;
1006 continue;
1007 }
1008 }
1009 list = list->next;
1010 }
1011 g_list_free (children);
1012
1013 /* move children UP if necessary */
1014 children = gtk_container_get_children (GTK_CONTAINER (grid));
1015 for (list = children; list; list = list->next) {
1016 GtkWidget *child = GTK_WIDGET (list->data);
1017 if (child) {
1018 guint top_attach, left_attach;
1019 gtk_container_child_get (GTK_CONTAINER (grid), child,
1020 "top-attach", &top_attach,
1021 "left-attach", &left_attach, NULL);
1022 /* ADD/REMOVE button sensitivity */
1023 if (left_attach == 1) {
1024 if (top_attach == size)
1025 gtk_widget_set_sensitive (child, TRUE);
1026 else
1027 gtk_widget_set_sensitive (child, (size-1 > min) ? TRUE : FALSE);
1028 }
1029
1030 /* move widgets UP if necessary and change the "_index" property */
1031 if (top_attach > (guint)item_index) {
1032 struct MoveChild *mc;
1033 gint index;
1034
1035 mc = g_new (struct MoveChild, 1);
1036 mc->widget = child;
1037 mc->top_attach = top_attach - 1;
1038 to_move = g_list_append (to_move, mc);
1039
1040 index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (child), "_index"));
1041 if (index > 0)
1042 g_object_set_data (G_OBJECT (child), "_index",
1043 GINT_TO_POINTER (index - 1));
1044 }
1045 }
1046 }
1047 g_list_free (children);
1048
1049 for (list = to_move; list; list = list->next) {
1050 struct MoveChild *mc;
1051
1052 mc = (struct MoveChild *) (list->data);
1053 gtk_container_child_set (GTK_CONTAINER (grid), mc->widget,
1054 "top-attach", mc->top_attach,
1055 "height", 1, NULL);
1056 g_free (list->data);
1057 }
1058 g_list_free (to_move);
1059 }
1060
1061
1062 /**
1063 * gdaui_server_operation_new_in_dialog:
1064 * @op: a #GdaServerOperation object
1065 * @parent: (allow-none): the parent window for the new dialog, or %NULL
1066 * @title: (allow-none): the title of the dialog window, or %NULL
1067 * @header: (allow-none): a helper text displayed at the top of the dialog, or %NULL
1068 *
1069 * Creates a new #GdauiServerOperation widget in the same way as gdaui_server_operation_new()
1070 * and puts it into a #GtkDialog widget. The returned dialog has the "Ok" and "Cancel" buttons
1071 * which respectively return GTK_RESPONSE_ACCEPT and GTK_RESPONSE_REJECT.
1072 *
1073 * The #GdauiServerOperation widget is attached to the dialog using the user property
1074 * "form".
1075 *
1076 * Returns: the new #GtkDialog widget
1077 *
1078 * Since: 4.2
1079 */
1080 GtkWidget *
gdaui_server_operation_new_in_dialog(GdaServerOperation * op,GtkWindow * parent,const gchar * title,const gchar * header)1081 gdaui_server_operation_new_in_dialog (GdaServerOperation *op, GtkWindow *parent,
1082 const gchar *title, const gchar *header)
1083 {
1084 GtkWidget *form;
1085 GtkWidget *dlg;
1086 GtkWidget *dcontents;
1087 const gchar *rtitle;
1088
1089 form = gdaui_server_operation_new (op);
1090
1091 rtitle = title;
1092 if (!rtitle)
1093 rtitle = _("Server operation specification");
1094
1095 dlg = gtk_dialog_new_with_buttons (rtitle, parent,
1096 GTK_DIALOG_MODAL,
1097 GTK_STOCK_OK,
1098 GTK_RESPONSE_ACCEPT,
1099 GTK_STOCK_CANCEL,
1100 GTK_RESPONSE_REJECT,
1101 NULL);
1102 dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dlg));
1103
1104 if (header && *header) {
1105 GtkWidget *label;
1106
1107 label = gtk_label_new (NULL);
1108 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1109 gtk_label_set_markup (GTK_LABEL (label), header);
1110 gtk_box_pack_start (GTK_BOX (dcontents), label, FALSE, FALSE, 5);
1111
1112 gtk_widget_show (label);
1113 }
1114 gtk_container_set_border_width (GTK_CONTAINER (dcontents), 4);
1115 gtk_box_pack_start (GTK_BOX (dcontents), form, TRUE, TRUE, 10);
1116
1117 gtk_widget_show_all (form);
1118
1119 return dlg;
1120 }
1121
1122
1123 /*
1124 * CREATE_TABLE "/FIELDS_A" Custom widgets rendering
1125 */
1126 static void create_table_grid_fields_iter_row_changed_cb (GdaDataModelIter *grid_iter, gint row,
1127 GdaDataModelIter *form_iter);
1128 static void create_table_proxy_row_inserted_cb (GdaDataProxy *proxy, gint row, GdauiServerOperation *form);
1129 static GtkWidget *
create_table_fields_array_create_widget(GdauiServerOperation * form,const gchar * path,G_GNUC_UNUSED gchar ** section_str,G_GNUC_UNUSED GSList ** label_widgets)1130 create_table_fields_array_create_widget (GdauiServerOperation *form, const gchar *path,
1131 G_GNUC_UNUSED gchar **section_str,
1132 G_GNUC_UNUSED GSList **label_widgets)
1133 {
1134 GdaServerOperationNode *info_node;
1135 GtkWidget *hlayout, *sw, *box, *label;
1136 GtkWidget *grid_fields, *form_props, *winfo;
1137 GdaDataProxy *proxy;
1138 gint name_col, col, nbcols;
1139 GdaDataModelIter *grid_iter, *form_iter;
1140
1141 info_node = gda_server_operation_get_node_info (form->priv->op, path);
1142 g_assert (info_node->type == GDA_SERVER_OPERATION_NODE_DATA_MODEL);
1143
1144 hlayout = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
1145
1146 /* form for field properties */
1147 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1148 gtk_paned_pack2 (GTK_PANED (hlayout), box, TRUE, TRUE);
1149
1150 label = gtk_label_new (_("<b>Field properties:</b>"));
1151 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1152 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
1153 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
1154
1155 form_props = gdaui_raw_form_new (GDA_DATA_MODEL (info_node->model));
1156 proxy = gdaui_data_proxy_get_proxy (GDAUI_DATA_PROXY (form_props));
1157 gdaui_data_proxy_set_write_mode (GDAUI_DATA_PROXY (form_props),
1158 GDAUI_DATA_PROXY_WRITE_ON_VALUE_CHANGE);
1159 gtk_box_pack_start (GTK_BOX (box), form_props, TRUE, TRUE, 0);
1160 g_signal_connect (proxy, "row-inserted",
1161 G_CALLBACK (create_table_proxy_row_inserted_cb), form);
1162
1163 gtk_widget_show_all (box);
1164
1165 /* grid for field names */
1166 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1167 gtk_paned_pack1 (GTK_PANED (hlayout), box, TRUE, TRUE);
1168
1169 label = gtk_label_new (_("<b>Fields:</b>"));
1170 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1171 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
1172 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
1173
1174 sw = gtk_scrolled_window_new (NULL, NULL);
1175 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
1176 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1177 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE);
1178
1179 grid_fields = gdaui_raw_grid_new (GDA_DATA_MODEL (proxy));
1180 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (grid_fields), FALSE);
1181 g_object_set (G_OBJECT (grid_fields), "info-cell-visible", FALSE, NULL);
1182
1183 name_col = 0;
1184 nbcols = gda_data_proxy_get_proxied_model_n_cols (proxy);
1185 g_assert (name_col < nbcols);
1186 for (col = 0; col < name_col; col++)
1187 gdaui_data_selector_set_column_visible (GDAUI_DATA_SELECTOR (grid_fields), col, FALSE);
1188 for (col = name_col + 1; col < nbcols; col++)
1189 gdaui_data_selector_set_column_visible (GDAUI_DATA_SELECTOR (grid_fields), col, FALSE);
1190
1191 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), grid_fields);
1192 gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (sw))),
1193 GTK_SHADOW_NONE);
1194 gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
1195
1196 /* buttons to add/remove fields */
1197 winfo = gdaui_data_proxy_info_new (GDAUI_DATA_PROXY (form_props),
1198 GDAUI_DATA_PROXY_INFO_ROW_MODIFY_BUTTONS);
1199 gtk_box_pack_start (GTK_BOX (box), winfo, FALSE, FALSE, 0);
1200
1201 gtk_widget_show_all (box);
1202
1203 /* keep the selections in sync */
1204 grid_iter = gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR (grid_fields));
1205 form_iter = gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR (form_props));
1206 g_signal_connect (grid_iter, "row-changed",
1207 G_CALLBACK (create_table_grid_fields_iter_row_changed_cb), form_iter);
1208 g_signal_connect (form_iter, "row-changed",
1209 G_CALLBACK (create_table_grid_fields_iter_row_changed_cb), grid_iter);
1210
1211 gtk_widget_set_vexpand (hlayout, TRUE);
1212
1213 {
1214 GtkActionGroup *group;
1215 GtkAction *action;
1216 group = gdaui_data_proxy_get_actions_group (GDAUI_DATA_PROXY (form_props));
1217 action = gtk_action_group_get_action (group, "ActionNew");
1218 g_object_set (G_OBJECT (action), "tooltip", _("Add a new field"), NULL);
1219 action = gtk_action_group_get_action (group, "ActionDelete");
1220 g_object_set (G_OBJECT (action), "tooltip", _("Remove selected field"), NULL);
1221 action = gtk_action_group_get_action (group, "ActionCommit");
1222 gtk_action_set_visible (action, FALSE);
1223 action = gtk_action_group_get_action (group, "ActionReset");
1224 gtk_action_set_visible (action, FALSE);
1225 }
1226
1227 return hlayout;
1228 }
1229
1230 static void
create_table_grid_fields_iter_row_changed_cb(GdaDataModelIter * iter1,gint row,GdaDataModelIter * iter2)1231 create_table_grid_fields_iter_row_changed_cb (GdaDataModelIter *iter1, gint row, GdaDataModelIter *iter2)
1232 {
1233 g_signal_handlers_block_by_func (G_OBJECT (iter2),
1234 G_CALLBACK (create_table_grid_fields_iter_row_changed_cb), iter1);
1235 gda_data_model_iter_move_to_row (iter2, row);
1236 g_signal_handlers_unblock_by_func (G_OBJECT (iter2),
1237 G_CALLBACK (create_table_grid_fields_iter_row_changed_cb), iter1);
1238 }
1239
1240 static void
create_table_proxy_row_inserted_cb(GdaDataProxy * proxy,gint row,GdauiServerOperation * form)1241 create_table_proxy_row_inserted_cb (GdaDataProxy *proxy, gint row, GdauiServerOperation *form)
1242 {
1243 GdaDataModelIter *iter;
1244 GdaHolder *holder;
1245 GdaServerProvider *prov;
1246 GdaConnection *cnc;
1247 const gchar *type = NULL;
1248
1249 iter = gda_data_model_create_iter (GDA_DATA_MODEL (proxy));
1250 gda_data_model_iter_move_to_row (iter, row);
1251 holder = gda_set_get_nth_holder (GDA_SET (iter), 0);
1252 gda_holder_set_value_str (holder, NULL, "fieldname", NULL);
1253
1254 g_object_get (form->priv->op, "connection", &cnc, "provider", &prov, NULL);
1255 if (prov)
1256 type = gda_server_provider_get_default_dbms_type (prov, cnc, G_TYPE_STRING);
1257 holder = gda_set_get_nth_holder (GDA_SET (iter), 1);
1258 gda_holder_set_value_str (holder, NULL, type ? type : "varchar", NULL);
1259 if (cnc)
1260 g_object_unref (cnc);
1261 if (prov)
1262 g_object_unref (prov);
1263 }
1264