3
* Copyright (C) 2002 - 2004 Vivien Malerba
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of the
8
* License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23
#include <libgnomedb/libgnomedb.h>
26
#include "mg-server.h"
28
#include "mg-parameter.h"
29
#include "mg-data-handler.h"
30
#include "mg-data-entry.h"
31
#include "mg-server-data-type.h"
34
#include "mg-context.h"
35
#include <libmergeant/handlers/mg-entry-combo.h>
37
static void mg_form_class_init (MgFormClass * class);
38
static void mg_form_init (MgForm * wid);
39
static void mg_form_dispose (GObject * object);
41
static void entry_contents_modified (MgDataEntry *entry, MgForm *form);
42
static void parameter_changed_cb (MgParameter *param, MgDataEntry *entry);
44
static void mark_not_null_entry_labels (MgForm *form, gboolean show_mark);
55
MgContext *context;/* parameters, etc */
56
GSList *entries;/* list of MgDataEntry widgets */
57
GSList *not_null_labels;/* list of GtkLabel widgets corresponding to NOT NULL entries */
58
gulong *signal_ids; /* array of signal ids */
59
GtkWidget *entries_table;
60
GSList *hidden_entries;
62
gboolean forward_param_updates; /* forward them to the MgDataEntry widgets ? */
63
GtkTooltips *tooltips;
67
static gint mg_form_signals[LAST_SIGNAL] = { 0 };
69
/* get a pointer to the parents to be able to call their destructor */
70
static GObjectClass *parent_class = NULL;
73
mg_form_get_type (void)
75
static GType type = 0;
78
static const GTypeInfo info = {
81
(GBaseFinalizeFunc) NULL,
82
(GClassInitFunc) mg_form_class_init,
87
(GInstanceInitFunc) mg_form_init
90
type = g_type_register_static (GTK_TYPE_VBOX, "MgForm", &info, 0);
97
mg_form_class_init (MgFormClass * class)
99
GObjectClass *object_class = G_OBJECT_CLASS (class);
101
parent_class = g_type_class_peek_parent (class);
103
mg_form_signals[PARAM_CHANGED] =
104
g_signal_new ("param_changed",
105
G_TYPE_FROM_CLASS (object_class),
107
G_STRUCT_OFFSET (MgFormClass, param_changed),
109
marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2,
110
G_TYPE_OBJECT, G_TYPE_BOOLEAN);
112
class->param_changed = NULL;
113
object_class->dispose = mg_form_dispose;
117
mg_form_init (MgForm * wid)
119
wid->priv = g_new0 (MgFormPriv, 1);
120
wid->priv->conf = NULL;
121
wid->priv->context = NULL;
122
wid->priv->entries = NULL;
123
wid->priv->not_null_labels = NULL;
124
wid->priv->entries_table = NULL;
125
wid->priv->hidden_entries = NULL;
126
wid->priv->signal_ids = NULL;
128
wid->priv->forward_param_updates = TRUE;
129
wid->priv->tooltips = NULL;
132
static void mg_form_initialize (MgForm *form, MgConf *conf, GtkWidget *layout, GHashTable *box_widgets);
133
static void widget_shown_cb (GtkWidget *wid, MgForm *form);
134
static void mg_conf_weak_notify (MgForm *form, MgConf *conf);
137
* @conf: a #MgConf object
138
* @context: a #MgContext structure
140
* Creates a new #MgForm widget using all the parameters provided in @context.
141
* @context is copied in the process.
143
* The global layout is rendered using a table (a #GtkTable), and an entry is created for each
146
* Returns: the new widget
149
mg_form_new (MgConf *conf, MgContext *context)
151
return mg_form_new_in_layout (conf, context, NULL, NULL);
154
static void context_translate_boxes (gpointer key, gpointer value, GHashTable *data_hash);
156
* mg_form_new_in_layout
157
* @conf: a #MgConf object
158
* @context: a #MgContext structure
159
* @layout: a #GtkWidget container of all the widgets in @box_widgets
160
* @box_widgets: a #GHashTable of #GtkBox widgets
162
* Creates a new #MgForm widget using all the parameters provided in @context.
163
* @context is copied in the process.
165
* This function is identical to mg_form_new() except that the layout is not done using a table, but
166
* using the @layout widget; and each entry is packed into one of the #GtkBox widgets of @box_widgets
167
* (specifically each entry corresponds to a #MgContextNode of @context, and that context node
168
* is used a the key to @box_widgets to find the box to pack the entry in).
170
* If any of @layout or @box_widgets is %NULL, then this function is equivalent to mg_form_new().
172
* Returns: the new widget
175
mg_form_new_in_layout (MgConf *conf, MgContext *context, GtkWidget *layout, GHashTable *box_widgets)
179
GHashTable *repl = NULL;
181
g_return_val_if_fail (conf && IS_MG_CONF (conf), NULL);
183
g_return_val_if_fail (mg_context_is_coherent (context, NULL), NULL);
185
obj = g_object_new (MG_FORM_TYPE, NULL);
186
form = MG_FORM (obj);
188
form->priv->conf = conf;
190
/* context copy, parameters are not copied */
193
repl = g_hash_table_new (NULL, NULL);
194
form->priv->context = MG_CONTEXT (mg_context_new_copy (context, FALSE, repl));
195
g_hash_table_foreach (box_widgets, (GHFunc) context_translate_boxes, repl);
199
form->priv->context = MG_CONTEXT (mg_context_new_copy (context, FALSE, repl));
202
form->priv->context = MG_CONTEXT (mg_context_new (conf, NULL));
204
g_object_weak_ref (G_OBJECT (form->priv->conf),
205
(GWeakNotify) mg_conf_weak_notify, form);
207
mg_form_initialize (form, conf, layout, box_widgets);
209
g_hash_table_destroy (repl);
211
return GTK_WIDGET (obj);
215
context_translate_boxes (gpointer key, gpointer value, GHashTable *data_hash)
217
gpointer newkey = g_hash_table_lookup (data_hash, key);
218
g_hash_table_insert (data_hash, newkey, value);
222
widget_shown_cb (GtkWidget *wid, MgForm *form)
224
if (g_slist_find (form->priv->hidden_entries, wid)) {
225
if (form->priv->entries_table && g_slist_find (form->priv->entries, wid)) {
226
gint row = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (wid), "row_no"));
227
gtk_table_set_row_spacing (GTK_TABLE (form->priv->entries_table), row, 0);
230
gtk_widget_hide (wid);
235
mg_conf_weak_notify (MgForm *form, MgConf *conf)
239
/* render all the entries non sensitive */
240
list = form->priv->entries;
242
gtk_widget_set_sensitive (GTK_WIDGET (list->data), FALSE);
243
list = g_slist_next (list);
246
/* Tell that we don't need to weak unref the MgConf */
247
form->priv->conf = NULL;
251
mg_form_dispose (GObject *object)
255
g_return_if_fail (object != NULL);
256
g_return_if_fail (IS_MG_FORM (object));
257
form = MG_FORM (object);
263
if (form->priv->context) {
265
list = form->priv->context->parameters;;
267
g_signal_handler_disconnect (G_OBJECT (list->data), form->priv->signal_ids[i]);
269
list = g_slist_next (list);
273
g_object_unref (G_OBJECT (form->priv->context));
274
form->priv->context = NULL;
277
/* list of entries */
278
list = form->priv->hidden_entries;
281
g_signal_handlers_disconnect_by_func (G_OBJECT (list->data),
282
G_CALLBACK (widget_shown_cb), form);
283
list = g_slist_next (list);
285
g_slist_free (form->priv->hidden_entries);
286
form->priv->hidden_entries = NULL;
289
list = form->priv->entries;
292
g_object_set_data (G_OBJECT (list->data), "param", NULL);
293
list = g_slist_next (list);
295
g_slist_free (form->priv->entries);
296
form->priv->entries = NULL;
299
if (form->priv->not_null_labels)
300
g_slist_free (form->priv->not_null_labels);
302
/* Weak unref the MgConf is necessary */
303
if (form->priv->conf)
304
g_object_weak_unref (G_OBJECT (form->priv->conf),
305
(GWeakNotify) mg_conf_weak_notify, form);
308
if (form->priv->tooltips) {
309
gtk_object_destroy (GTK_OBJECT (form->priv->tooltips));
310
form->priv->tooltips = NULL;
314
/* the private area itself */
319
/* for the parent class */
320
parent_class->dispose (object);
326
* create the entries in the widget
329
mg_form_initialize (MgForm *form, MgConf *conf, GtkWidget *layout, GHashTable *box_widgets)
337
form->priv->tooltips = gtk_tooltips_new ();
339
/* context management */
340
if (form->priv->context && !form->priv->context->nodes) {
341
MgContext *ncontext = MG_CONTEXT (mg_context_new (conf, form->priv->context->parameters));
342
g_object_unref (G_OBJECT (form->priv->context));
343
form->priv->context = ncontext;
346
/* allocating space for the signal ids */
347
form->priv->signal_ids = g_new0 (gulong, g_slist_length (form->priv->context->parameters));
350
/* creating all the entries */
351
list = form->priv->context->nodes;
353
GtkWidget *entry = NULL;
355
node = MG_CONTEXT_NODE (list->data);
356
if ((param = node->param)) { /* single direct parameter */
357
MgServerDataType *type;
358
const GdaValue *val, *default_val, *value;
360
MgDataHandler *dh = NULL;
361
gchar *plugin = NULL;
363
type = mg_parameter_get_data_type (param);
366
g_object_get (G_OBJECT (param), "handler_plugin", &plugin, NULL);
368
dh = mg_server_get_handler_by_name (mg_conf_get_server (conf), plugin);
370
/* test if plugin can handle the parameter's data type */
371
if (!mg_data_handler_accepts_gda_type (dh, mg_server_data_type_get_gda_type (type)))
375
dh = mg_server_data_type_get_handler (type);
376
val = mg_parameter_get_value (param);
377
default_val = mg_parameter_get_default_value (param);
378
nnul = mg_parameter_get_not_null (param);
380
/* determine initial value */
382
if (!value && default_val &&
383
(gda_value_get_type (default_val) == mg_server_data_type_get_gda_type (type)))
387
entry = GTK_WIDGET (mg_data_handler_get_entry_from_value (dh, value,
388
mg_server_data_type_get_gda_type (type)));
390
/* set current value */
391
mg_data_entry_set_value (MG_DATA_ENTRY (entry), val);
394
(nnul && value && (gda_value_get_type (value) != GDA_VALUE_TYPE_NULL)))
395
mg_data_entry_set_value_orig (MG_DATA_ENTRY (entry), value);
398
mg_data_entry_set_value_default (MG_DATA_ENTRY (entry), default_val);
399
mg_data_entry_set_attributes (MG_DATA_ENTRY (entry),
400
MG_DATA_ENTRY_CAN_BE_DEFAULT,
401
MG_DATA_ENTRY_CAN_BE_DEFAULT);
404
mg_data_entry_set_attributes (MG_DATA_ENTRY (entry),
405
nnul ? 0 : MG_DATA_ENTRY_CAN_BE_NULL,
406
MG_DATA_ENTRY_CAN_BE_NULL);
408
g_object_set_data (G_OBJECT (entry), "param", param);
409
g_object_set_data (G_OBJECT (entry), "form", form);
410
form->priv->entries = g_slist_append (form->priv->entries, entry);
412
/* connect to the parameter's changes */
413
form->priv->signal_ids[i] = g_signal_connect (G_OBJECT (param), "changed",
414
G_CALLBACK (parameter_changed_cb), entry);
417
else { /* parameter depending on a sub query */
419
gboolean nnul = TRUE;
421
entry = mg_entry_combo_new (conf, form->priv->context, node);
422
g_object_set_data (G_OBJECT (entry), "node", node);
423
g_object_set_data (G_OBJECT (entry), "form", form);
424
form->priv->entries = g_slist_append (form->priv->entries, entry);
426
/* connect to the parameter's changes */
427
plist = node->params;
429
if (!mg_parameter_get_not_null (plist->data))
431
form->priv->signal_ids[i] = g_signal_connect (G_OBJECT (plist->data), "changed",
432
G_CALLBACK (parameter_changed_cb), entry);
434
plist = g_slist_next (plist);
436
mg_data_entry_set_attributes (MG_DATA_ENTRY (entry),
437
nnul ? 0 : MG_DATA_ENTRY_CAN_BE_NULL,
438
MG_DATA_ENTRY_CAN_BE_NULL);
441
/* connect the entry's changes */
442
g_signal_connect (G_OBJECT (entry), "contents_modified",
443
G_CALLBACK (entry_contents_modified), form);
444
list = g_slist_next (list);
448
/* there is actually a layout, test it */
449
/* tests: GtkWindow? already parented widget? */
450
/* set layout to NULL on error */
457
GtkWidget *table, *label;
459
/* creating a table for all the entries */
460
table = gtk_table_new (g_slist_length (form->priv->entries), 2, FALSE);
461
gtk_table_set_row_spacings (GTK_TABLE (table), 5);
462
gtk_table_set_col_spacings (GTK_TABLE (table), 5);
463
form->priv->entries_table = table;
464
gtk_box_pack_start (GTK_BOX (form), table, FALSE, TRUE, 0);
465
list = form->priv->entries;
469
GtkWidget *entry_label;
471
/* label for the entry */
472
param = g_object_get_data (G_OBJECT (list->data), "param");
478
str = mg_base_get_name (MG_BASE (param));
481
str2 = g_strdup_printf ("%s:", str);
482
evbox = gtk_event_box_new ();
483
label = gtk_label_new (str2);
484
if (mg_parameter_get_not_null (param))
485
form->priv->not_null_labels = g_slist_append (form->priv->not_null_labels, label);
487
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
489
gtk_container_add (GTK_CONTAINER (evbox), label);
491
gtk_table_attach (GTK_TABLE (table), evbox, 0, 1, i, i+1,
492
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
493
gtk_widget_show (evbox);
494
gtk_widget_show (label);
497
str = mg_base_get_description (MG_BASE (param));
499
gtk_tooltips_set_tip (form->priv->tooltips, evbox, str, NULL);
502
/* FIXME: find a better label and tooltip and improve data entry attributes */
503
const gchar *str = NULL;
506
gboolean nullok = TRUE;
509
node = g_object_get_data (G_OBJECT (list->data), "node");
510
params = node->params;
511
while (params && nullok) {
512
if (mg_parameter_get_not_null (MG_PARAMETER (params->data)))
514
params = g_slist_next (params);
517
str = mg_base_get_name (MG_BASE (node->query));
520
str2 = g_strdup_printf ("%s:", str);
521
evbox = gtk_event_box_new ();
522
label = gtk_label_new (str2);
524
form->priv->not_null_labels = g_slist_append (form->priv->not_null_labels, label);
525
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
527
gtk_container_add (GTK_CONTAINER (evbox), label);
529
gtk_table_attach (GTK_TABLE (table), evbox, 0, 1, i, i+1,
530
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
531
gtk_widget_show (evbox);
532
gtk_widget_show (label);
535
str = mg_base_get_description (MG_BASE (node->query));
537
gtk_tooltips_set_tip (form->priv->tooltips, evbox, str, NULL);
540
/* add the entry itself to the table */
541
expand = mg_data_entry_expand_in_layout (MG_DATA_ENTRY (list->data));
542
gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (list->data), 1, 2, i, i+1,
543
GTK_FILL | GTK_SHRINK | GTK_EXPAND,
544
GTK_FILL | GTK_SHRINK | expand? GTK_EXPAND : 0, 0, 0);
545
gtk_widget_show (GTK_WIDGET (list->data));
546
g_object_set_data (G_OBJECT (list->data), "entry_label", entry_label);
547
g_object_set_data (G_OBJECT (list->data), "row_no", GINT_TO_POINTER (i));
549
list = g_slist_next (list);
552
mark_not_null_entry_labels (form, TRUE);
553
gtk_widget_show (table);
556
/* really use the provided layout */
560
gtk_box_pack_start (GTK_BOX (form), layout, FALSE, TRUE, 0);
561
list = form->priv->entries;
562
nodes = form->priv->context->nodes;
563
while (nodes && list) {
564
box = g_hash_table_lookup (box_widgets, nodes->data);
566
gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (list->data),
567
mg_data_entry_expand_in_layout (MG_DATA_ENTRY (list->data)),
569
gtk_widget_show (GTK_WIDGET (list->data));
570
if (! g_object_get_data (G_OBJECT (box), "show_actions"))
571
mg_data_entry_set_attributes (MG_DATA_ENTRY (list->data),
572
0, MG_DATA_ENTRY_ACTIONS_SHOWN);
574
list = g_slist_next (list);
575
nodes = g_slist_next (nodes);
577
g_assert (!nodes && !list);
578
gtk_widget_show (layout);
583
* if @show_mark is TRUE, display the label as bold */
585
mark_not_null_entry_labels (MgForm *form, gboolean show_mark)
587
PangoAttrList *attrs = NULL;
591
attrs = pango_attr_list_new ();
592
att = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
593
att->start_index = 0;
594
att->end_index = G_MAXUINT;
595
pango_attr_list_insert (attrs, att);
598
GSList *list = form->priv->not_null_labels;
600
gtk_label_set_attributes (GTK_LABEL (list->data), attrs);
601
list = g_slist_next (list);
605
pango_attr_list_unref (attrs);
609
entry_contents_modified (MgDataEntry *entry, MgForm *form)
615
attr = mg_data_entry_get_attributes (entry);
616
param = g_object_get_data (G_OBJECT (entry), "param");
617
if (param) { /* single parameter */
620
form->priv->forward_param_updates = FALSE;
622
/* parameter's value */
623
value = mg_data_entry_get_value (entry);
624
if ((!value || gda_value_is_null (value)) &&
625
(attr & MG_DATA_ENTRY_IS_DEFAULT))
626
g_object_set (G_OBJECT (param), "use_default_value", TRUE, NULL);
628
g_object_set (G_OBJECT (param), "use_default_value", FALSE, NULL);
629
mg_parameter_set_value (param, value);
631
g_print (">> 'PARAM_CHANGED' from %s\n", __FUNCTION__);
633
g_signal_emit (G_OBJECT (form), mg_form_signals[PARAM_CHANGED], 0, param, TRUE);
635
g_print ("<< 'PARAM_CHANGED' from %s\n", __FUNCTION__);
637
form->priv->forward_param_updates = TRUE;
638
gda_value_free (value);
640
else { /* multiple parameters */
642
GList *values, *list;
643
node = g_object_get_data (G_OBJECT (entry), "node");
644
params = node->params;
645
values = mg_entry_combo_get_values (MG_ENTRY_COMBO (entry));
646
g_assert (g_slist_length (params) == g_list_length (values));
650
/* REM: if there is more than one value in 'params', then a signal is emitted for each
651
param that is changed, and there is no way for the listener of that signal to know if it
652
the end of the "param_changed" sequence. What could be done is:
653
- adding another boolean to tell if that signal is the last one in the "param_changed" sequence, or
654
- modify the signal to add a list of parameters which are changed and emit only one signal.
656
form->priv->forward_param_updates = FALSE;
658
/* parameter's value */
659
mg_parameter_set_value (MG_PARAMETER (params->data), (GdaValue *)(list->data));
661
g_print (">> 'PARAM_CHANGED' from %s\n", __FUNCTION__);
663
g_signal_emit (G_OBJECT (form), mg_form_signals[PARAM_CHANGED], 0, param, TRUE);
665
g_print ("<< 'PARAM_CHANGED' from %s\n", __FUNCTION__);
667
form->priv->forward_param_updates = TRUE;;
668
gda_value_free (list->data);
670
list = g_list_next (list);
671
params = g_slist_next (params);
673
g_list_free (values);
679
* Called when a parameter changes
680
* We emit a "param_changed" signal only if the 'form->priv->forward_param_updates' is TRUE, which means
681
* the param change does not come from a MgDataEntry change.
684
parameter_changed_cb (MgParameter *param, MgDataEntry *entry)
686
MgForm *form = g_object_get_data (G_OBJECT (entry), "form");
687
MgContextNode *node = g_object_get_data (G_OBJECT (entry), "node");
688
const GdaValue *value = mg_parameter_get_value (param);
690
if (form->priv->forward_param_updates) {
691
gboolean param_valid;
692
gboolean default_if_invalid = FALSE;
694
/* There can be a feedback from the entry if the param is invalid and "set_default_if_invalid"
695
exists and is TRUE */
696
param_valid = mg_parameter_is_valid (param);
698
if (g_object_class_find_property (G_OBJECT_GET_CLASS (entry), "set_default_if_invalid"))
699
g_object_get (G_OBJECT (entry), "set_default_if_invalid", &default_if_invalid, NULL);
701
/* updating the corresponding entry */
702
if (! default_if_invalid)
703
g_signal_handlers_block_by_func (G_OBJECT (entry),
704
G_CALLBACK (entry_contents_modified), form);
706
GList *values = NULL;
707
GSList *list = node->params;
708
gboolean allnull = TRUE;
711
const GdaValue *pvalue = mg_parameter_get_value (MG_PARAMETER (list->data));
712
values = g_list_append (values, pvalue);
713
if (allnull && pvalue && (gda_value_get_type (pvalue) != GDA_VALUE_TYPE_NULL))
716
list = g_slist_next (list);
720
mg_entry_combo_set_values_orig (MG_ENTRY_COMBO (entry), values);
722
mg_entry_combo_set_values_orig (MG_ENTRY_COMBO (entry), NULL);
724
g_list_free (values);
727
mg_data_entry_set_value_orig (entry, value);
729
if (! default_if_invalid)
730
g_signal_handlers_unblock_by_func (G_OBJECT (entry),
731
G_CALLBACK (entry_contents_modified), form);
734
g_print (">> 'PARAM_CHANGED' from %s\n", __FUNCTION__);
736
g_signal_emit (G_OBJECT (form), mg_form_signals[PARAM_CHANGED], 0, param, FALSE);
738
g_print ("<< 'PARAM_CHANGED' from %s\n", __FUNCTION__);
744
* mg_form_set_current_as_orig
745
* @form: a #MgForm widget
747
* Tells @form that the current values in the different entries are
748
* to be considered as the original values for all the entries; the immediate
749
* consequence is that any sub-sequent call to mg_form_has_been_changed()
750
* will return FALSE (of course until any entry is changed).
753
mg_form_set_current_as_orig (MgForm *form)
758
g_return_if_fail (form && IS_MG_FORM (form));
759
g_return_if_fail (form->priv);
761
list = form->priv->entries;
763
MgContextNode *node = g_object_get_data (G_OBJECT (list->data), "node");
767
GList *values = NULL;
768
GSList *params = node->params;
769
gboolean allnull = TRUE;
772
const GdaValue *pvalue = mg_parameter_get_value (MG_PARAMETER (params->data));
773
values = g_list_append (values, pvalue);
774
if (allnull && pvalue && (gda_value_get_type (pvalue) != GDA_VALUE_TYPE_NULL))
777
params = g_slist_next (params);
781
mg_entry_combo_set_values_orig (MG_ENTRY_COMBO (list->data), values);
783
mg_entry_combo_set_values_orig (MG_ENTRY_COMBO (list->data), NULL);
785
g_list_free (values);
788
/* non combo entry */
789
param = g_object_get_data (G_OBJECT (list->data), "param");
790
mg_data_entry_set_value_orig (MG_DATA_ENTRY (list->data), mg_parameter_get_value (param));
792
list = g_slist_next (list);
798
* @form: a #MgForm widget
800
* Tells if the form can be used as-is (if all the parameters do have some valid values)
802
* Returns: TRUE if the form is valid
805
mg_form_is_valid (MgForm *form)
807
g_return_val_if_fail (form && IS_MG_FORM (form), FALSE);
808
g_return_val_if_fail (form->priv, FALSE);
810
return mg_context_is_valid (form->priv->context);
814
* mg_form_has_been_changed
815
* @form: a #MgForm widget
817
* Tells if the form has had at least on entry changed, or not
822
mg_form_has_been_changed (MgForm *form)
824
gboolean changed = FALSE;
827
g_return_val_if_fail (form && IS_MG_FORM (form), FALSE);
828
g_return_val_if_fail (form->priv, FALSE);
830
list = form->priv->entries;
831
while (list && !changed) {
832
if (! (mg_data_entry_get_attributes (MG_DATA_ENTRY (list->data)) & MG_DATA_ENTRY_IS_UNCHANGED))
834
list = g_slist_next (list);
841
* mg_form_show_entries_actions
842
* @form: a #MgForm widget
843
* @show_actions: a boolean
845
* Show or hide the actions button available at the end of each data entry
849
mg_form_show_entries_actions (MgForm *form, gboolean show_actions)
854
g_return_if_fail (form && IS_MG_FORM (form));
855
g_return_if_fail (form->priv);
857
show = show_actions ? MG_DATA_ENTRY_ACTIONS_SHOWN : 0;
859
entries = form->priv->entries;
861
mg_data_entry_set_attributes (MG_DATA_ENTRY (entries->data), show, MG_DATA_ENTRY_ACTIONS_SHOWN);
862
entries = g_slist_next (entries);
865
mark_not_null_entry_labels (form, show_actions);
870
* @form: a #MgForm widget
872
* Resets all the entries in the form to their
876
mg_form_reset (MgForm *form)
880
g_return_if_fail (form && IS_MG_FORM (form));
881
g_return_if_fail (form->priv);
883
list = form->priv->entries;
885
MgContextNode *node = g_object_get_data (G_OBJECT (list->data), "node");
889
GList *values = NULL;
891
values = mg_entry_combo_get_values_orig (MG_ENTRY_COMBO (list->data));
892
mg_entry_combo_set_values (MG_ENTRY_COMBO (list->data), values);
893
g_list_free (values);
896
/* non combo entry */
897
const GdaValue *value;
899
value = mg_data_entry_get_value_orig (MG_DATA_ENTRY (list->data));
900
mg_data_entry_set_value (MG_DATA_ENTRY (list->data), value);
902
list = g_slist_next (list);
909
* @form: a #MgForm widget
910
* @param: a #MgParameter object
913
* Shows or hides the #MgDataEntry in @form which corresponds to the
917
mg_form_entry_show (MgForm *form, MgParameter *param, gboolean show)
921
g_return_if_fail (form && IS_MG_FORM (form));
922
g_return_if_fail (form->priv);
924
entries = form->priv->entries;
926
GtkWidget *entry = NULL;
927
MgParameter *thisparam = g_object_get_data (G_OBJECT (entries->data), "param");
930
if (thisparam == param)
931
entry = GTK_WIDGET (entries->data);
934
/* multiple parameters */
938
node = g_object_get_data (G_OBJECT (entries->data), "node");
939
params = node->params;
940
while (params && !entry) {
941
if (params->data == (gpointer) param)
942
entry = GTK_WIDGET (entries->data);
943
params = g_slist_next (params);
949
GtkWidget *entry_label = g_object_get_data (G_OBJECT (entry), "entry_label");
951
if (form->priv->entries_table)
952
row = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (entry), "row_no"));
955
if (g_slist_find (form->priv->hidden_entries, entry)) {
956
form->priv->hidden_entries = g_slist_remove (form->priv->hidden_entries, entry);
957
g_signal_handlers_disconnect_by_func (G_OBJECT (entry),
958
G_CALLBACK (widget_shown_cb), form);
960
gtk_widget_show (entry);
963
if (g_slist_find (form->priv->hidden_entries, entry_label)) {
964
form->priv->hidden_entries = g_slist_remove (form->priv->hidden_entries,
966
g_signal_handlers_disconnect_by_func (G_OBJECT (entry_label),
967
G_CALLBACK (widget_shown_cb), form);
969
gtk_widget_show (entry_label);
972
gtk_table_set_row_spacing (GTK_TABLE (form->priv->entries_table), row, 5);
975
if (!g_slist_find (form->priv->hidden_entries, entry)) {
976
form->priv->hidden_entries = g_slist_append (form->priv->hidden_entries, entry);
977
g_signal_connect_after (G_OBJECT (entry), "show",
978
G_CALLBACK (widget_shown_cb), form);
980
gtk_widget_hide (entry);
983
if (!g_slist_find (form->priv->hidden_entries, entry_label)) {
984
form->priv->hidden_entries = g_slist_append (form->priv->hidden_entries,
986
g_signal_connect_after (G_OBJECT (entry_label), "show",
987
G_CALLBACK (widget_shown_cb), form);
989
gtk_widget_hide (entry_label);
992
gtk_table_set_row_spacing (GTK_TABLE (form->priv->entries_table), row, 0);
996
entries = g_slist_next (entries);
1001
* mg_form_entry_set_sensitive
1002
* @form: a #MgForm widget
1003
* @param: a #MgParameter object
1006
* Shows or hides the #MgDataEntry in @form which corresponds to the
1010
mg_form_entry_set_sensitive (MgForm *form, MgParameter *param, gboolean sensitive)
1014
g_return_if_fail (form && IS_MG_FORM (form));
1015
g_return_if_fail (form->priv);
1017
entries = form->priv->entries;
1019
GtkWidget *entry = NULL;
1020
MgParameter *thisparam = g_object_get_data (G_OBJECT (entries->data), "param");
1023
if (thisparam == param)
1024
entry = GTK_WIDGET (entries->data);
1027
/* multiple parameters */
1029
MgContextNode *node;
1031
node = g_object_get_data (G_OBJECT (entries->data), "node");
1032
params = node->params;
1033
while (params && !entry) {
1034
if (params->data == (gpointer) param)
1035
entry = GTK_WIDGET (entries->data);
1036
params = g_slist_next (params);
1041
GtkWidget *entry_label = g_object_get_data (G_OBJECT (entry), "entry_label");
1043
gtk_widget_set_sensitive (entry, sensitive);
1045
gtk_widget_set_sensitive (entry_label, sensitive);
1048
entries = g_slist_next (entries);
1054
* mg_form_set_entries_auto_default
1055
* @form: a #MgForm widget
1058
* Sets weather all the #MgDataEntry entries in the form must default
1059
* to a default value if they are assigned a non valid value.
1060
* Depending on the real type of entry, it will provide a default value
1061
* which the user does not need to modify if it is OK.
1063
* For example a date entry can by default display the current date.
1066
mg_form_set_entries_auto_default (MgForm *form, gboolean auto_default)
1070
g_return_if_fail (form && IS_MG_FORM (form));
1071
g_return_if_fail (form->priv);
1073
entries = form->priv->entries;
1075
if (g_object_class_find_property (G_OBJECT_GET_CLASS (entries->data), "set_default_if_invalid"))
1076
g_object_set (G_OBJECT (entries->data), "set_default_if_invalid", auto_default, NULL);
1077
entries = g_slist_next (entries);
1082
* mg_form_set_entries_default
1083
* @form: a #MgForm widget
1085
* For each entry in the form, sets it to a default value if it is possible to do so.
1088
mg_form_set_entries_default (MgForm *form)
1093
g_return_if_fail (form && IS_MG_FORM (form));
1094
g_return_if_fail (form->priv);
1096
entries = form->priv->entries;
1098
attrs = mg_data_entry_get_attributes (MG_DATA_ENTRY (entries->data));
1099
if (attrs & MG_DATA_ENTRY_CAN_BE_DEFAULT)
1100
mg_data_entry_set_attributes (MG_DATA_ENTRY (entries->data),
1101
MG_DATA_ENTRY_IS_DEFAULT, MG_DATA_ENTRY_IS_DEFAULT);
1102
entries = g_slist_next (entries);
1106
static void form_param_changed (MgForm *form, MgParameter *param, gboolean is_user_modif, GtkDialog *dlg);
1109
* mg_form_new_in_dialog
1110
* @conf: a #MgConf object
1111
* @context: a #MgContext structure
1112
* @parent: the parent window for the new dialog, or %NULL
1113
* @title: the title of the dialog window, or %NULL
1114
* @header: a helper text displayed at the top of the dialog, or %NULL
1116
* Creates a new #MgForm widget in the same way as mg_form_new()
1117
* and puts it into a #GtkDialog widget.
1119
* The #MgForm widget is attached to the dialog using the user property
1122
* Returns: the new #GtkDialog widget
1125
mg_form_new_in_dialog (MgConf *conf, MgContext *context, GtkWindow *parent,
1126
const gchar *title, const gchar *header)
1130
const gchar *rtitle;
1132
form = mg_form_new (conf, context);
1136
rtitle = _("Values to be filled");
1138
dlg = gtk_dialog_new_with_buttons (rtitle, parent,
1141
GTK_RESPONSE_ACCEPT,
1143
GTK_RESPONSE_REJECT,
1145
if (header && *header) {
1148
label = gtk_label_new (NULL);
1149
gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1150
gtk_label_set_markup (GTK_LABEL (label), header);
1151
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), label, FALSE, FALSE, 5);
1152
gtk_widget_show (label);
1155
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dlg)->vbox), 4);
1156
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), form, TRUE, TRUE, 10);
1158
g_signal_connect (G_OBJECT (form), "param_changed",
1159
G_CALLBACK (form_param_changed), dlg);
1160
g_object_set_data (G_OBJECT (dlg), "form", form);
1162
gtk_widget_show_all (form);
1163
form_param_changed (MG_FORM (form), NULL, FALSE, GTK_DIALOG (dlg));
1169
form_param_changed (MgForm *form, MgParameter *param, gboolean is_user_modif, GtkDialog *dlg)
1173
valid = mg_form_is_valid (form);
1175
gtk_dialog_set_response_sensitive (dlg, GTK_RESPONSE_ACCEPT, valid);