~ubuntu-branches/ubuntu/karmic/mergeant/karmic

« back to all changes in this revision

Viewing changes to libmergeant/utility.c

  • Committer: Bazaar Package Importer
  • Author(s): Gustavo R. Montesino
  • Date: 2007-11-29 08:44:48 UTC
  • mfrom: (2.1.4 hardy)
  • Revision ID: james.westby@ubuntu.com-20071129084448-6aon73d22bv6hzfw
Tags: 0.67-3
* Re-enable installation of the mime files in mergeant.install
* mergeant.dirs: create usr/share/mime/packages to make dh_installmime add
  the update-mime-database code snippets

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* utility.c
2
 
 * Copyright (C) 2003 - 2004 Vivien Malerba <malerba@gnome-db.org>
3
 
 *
4
 
 * This library is free software; you can redistribute it and/or
5
 
 * modify it under the terms of the GNU Library General Public
6
 
 * License as published by the Free Software Foundation; either
7
 
 * version 2 of the License, or (at your option) any later version.
8
 
 *
9
 
 * This library is distributed in the hope that it will be useful,
10
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 
 * Library General Public License for more details.
13
 
 *
14
 
 * You should have received a copy of the GNU Library General Public
15
 
 * License along with this library; if not, write to the
16
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
 
 * Boston, MA 02111-1307, USA.
18
 
 */
19
 
 
20
 
#include "mg-defs.h"
21
 
#include "utility.h"
22
 
#include <libgda/libgda.h>
23
 
#include "mg-data-entry.h"
24
 
#include "mg-result-set.h"
25
 
#include "mg-parameter.h"
26
 
#include "mg-server-data-type.h"
27
 
#include "mg-server.h"
28
 
#include "mg-query.h"
29
 
#include "mg-renderer.h"
30
 
#include "mg-entity.h"
31
 
#include "mg-field.h"
32
 
#include "mg-qfield.h"
33
 
#include "mg-qf-field.h"
34
 
 
35
 
 
36
 
/**
37
 
 * utility_entry_build_actions_menu
38
 
 * @obj_data:
39
 
 * @attrs:
40
 
 * @function:
41
 
 *
42
 
 * Creates a GtkMenu widget which contains the possible actions on a data entry which 
43
 
 * attributes are @attrs. After the menu has been displayed, and when an action is selected,
44
 
 * the @function callback is called with the 'user_data' being @obj_data.
45
 
 *
46
 
 * The menu item which emits the signal has a "action" attribute which describes what action the
47
 
 * user has requested.
48
 
 *
49
 
 * Returns: the new menu
50
 
 */
51
 
GtkWidget *
52
 
utility_entry_build_actions_menu (GObject *obj_data, guint attrs, GCallback function)
53
 
{
54
 
        GtkWidget *menu, *mitem;
55
 
        gchar *str;
56
 
        gboolean nullact = FALSE;
57
 
        gboolean defact = FALSE;
58
 
        gboolean reset = FALSE;
59
 
 
60
 
        gboolean value_is_null;
61
 
        gboolean value_is_modified;
62
 
        gboolean value_is_default;
63
 
 
64
 
        menu = gtk_menu_new ();
65
 
 
66
 
        /* which menu items to make sensitive ? */
67
 
        value_is_null = attrs & MG_DATA_ENTRY_IS_NULL;
68
 
        value_is_modified = ! (attrs & MG_DATA_ENTRY_IS_UNCHANGED);
69
 
        value_is_default = attrs & MG_DATA_ENTRY_IS_DEFAULT;
70
 
 
71
 
        if ((attrs & MG_DATA_ENTRY_CAN_BE_NULL) && 
72
 
            !(attrs & MG_DATA_ENTRY_IS_NULL))
73
 
                nullact = TRUE;
74
 
        if ((attrs & MG_DATA_ENTRY_CAN_BE_DEFAULT) && 
75
 
            !(attrs & MG_DATA_ENTRY_IS_DEFAULT))
76
 
                defact = TRUE;
77
 
        if (!(attrs & MG_DATA_ENTRY_IS_UNCHANGED)) {
78
 
                if (attrs & MG_DATA_ENTRY_HAS_VALUE_ORIG) 
79
 
                        reset = TRUE;
80
 
        }
81
 
 
82
 
        /* set to NULL item */
83
 
        str = g_strdup (_("Unset"));
84
 
        mitem = gtk_check_menu_item_new_with_label (str);
85
 
        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mitem),
86
 
                                        value_is_null);
87
 
        gtk_widget_show (mitem);
88
 
        g_object_set_data (G_OBJECT (mitem), "action", GUINT_TO_POINTER (MG_DATA_ENTRY_IS_NULL));
89
 
        g_signal_connect (G_OBJECT (mitem), "activate",
90
 
                          G_CALLBACK (function), obj_data);
91
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), mitem);
92
 
        g_free (str);
93
 
        gtk_widget_set_sensitive (mitem, nullact);
94
 
 
95
 
        /* default value item */
96
 
        str = g_strdup (_("Set to default value"));
97
 
        mitem = gtk_check_menu_item_new_with_label (str);
98
 
        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mitem), 
99
 
                                        value_is_default);
100
 
        gtk_widget_show (mitem);
101
 
        g_object_set_data (G_OBJECT (mitem), "action", GUINT_TO_POINTER (MG_DATA_ENTRY_IS_DEFAULT));
102
 
        g_signal_connect (G_OBJECT (mitem), "activate",
103
 
                          G_CALLBACK (function), obj_data);
104
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), mitem);
105
 
        g_free (str);
106
 
        gtk_widget_set_sensitive (mitem, defact);
107
 
                
108
 
        /* reset to original value item */
109
 
        str = g_strdup (_("Reset to original value"));
110
 
        mitem = gtk_check_menu_item_new_with_label (str);
111
 
        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mitem), 
112
 
                                        !value_is_modified);
113
 
        gtk_widget_show (mitem);
114
 
        g_object_set_data (G_OBJECT (mitem), "action", GUINT_TO_POINTER (MG_DATA_ENTRY_IS_UNCHANGED));
115
 
        g_signal_connect (G_OBJECT (mitem), "activate",
116
 
                          G_CALLBACK (function), obj_data);
117
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), mitem);
118
 
        g_free (str);
119
 
        gtk_widget_set_sensitive (mitem, reset);
120
 
 
121
 
        return menu;
122
 
}
123
 
 
124
 
 
125
 
/**
126
 
 * utility_entry_build_info_colors_array
127
 
 * 
128
 
 * Creates an array of colors for the different states of an entry:
129
 
 *    Valid   <-> No special color
130
 
 *    Null    <-> Green
131
 
 *    Default <-> Blue
132
 
 *    Invalid <-> Red
133
 
 * Each status (except Valid) is represented by two colors for GTK_STATE_NORMAL and
134
 
 * GTK_STATE_PRELIGHT.
135
 
 *
136
 
 * Returns: a new array of 6 colors
137
 
 */
138
 
GdkColor **utility_entry_build_info_colors_array ()
139
 
{
140
 
        GdkColor **colors;
141
 
        GdkColor *color;
142
 
        
143
 
        colors = g_new0 (GdkColor *, 6);
144
 
        
145
 
        /* Green color */
146
 
        color = g_new0 (GdkColor, 1);
147
 
        gdk_color_parse (MG_COLOR_NORMAL_NULL, color);
148
 
        if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
149
 
                g_free (color);
150
 
                color = NULL;
151
 
        }
152
 
        colors[0] = color;
153
 
        
154
 
        color = g_new0 (GdkColor, 1);
155
 
        gdk_color_parse (MG_COLOR_PRELIGHT_NULL, color);
156
 
        if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
157
 
                g_free (color);
158
 
                color = NULL;
159
 
        }
160
 
        colors[1] = color;
161
 
        
162
 
        
163
 
        /* Blue color */
164
 
        color = g_new0 (GdkColor, 1);
165
 
        gdk_color_parse (MG_COLOR_NORMAL_DEFAULT, color);
166
 
        if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
167
 
                g_free (color);
168
 
                color = NULL;
169
 
        }
170
 
        colors[2] = color;
171
 
        
172
 
        color = g_new0 (GdkColor, 1);
173
 
        gdk_color_parse (MG_COLOR_PRELIGHT_DEFAULT, color);
174
 
        if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
175
 
                g_free (color);
176
 
                color = NULL;
177
 
        }
178
 
        colors[3] = color;
179
 
        
180
 
        
181
 
        /* Red color */
182
 
        color = g_new0 (GdkColor, 1);
183
 
        gdk_color_parse (MG_COLOR_NORMAL_INVALID, color);
184
 
        if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
185
 
                g_free (color);
186
 
                color = NULL;
187
 
        }
188
 
        colors[4] = color;
189
 
        
190
 
        color = g_new0 (GdkColor, 1);
191
 
        gdk_color_parse (MG_COLOR_PRELIGHT_INVALID, color);
192
 
        if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
193
 
                g_free (color);
194
 
                color = NULL;
195
 
        }
196
 
        colors[5] = color;
197
 
 
198
 
        return colors;
199
 
}
200
 
 
201
 
 
202
 
static const GdaValue *get_value_from_recordset (GtkTreeModel *tree_model, GtkTreeIter *iter, 
203
 
                                                 MgWorkCore *core, MgParameter *context_param);
204
 
static ModelUserModifiedValue *get_user_modifs (GtkTreeModel *tree_model, GtkTreeIter *iter, MgContextNode *context_node);
205
 
 
206
 
/**
207
 
 * utility_grid_model_get_value
208
 
 * @tree_model:
209
 
 * @iter:
210
 
 * @core:
211
 
 * @context_node:
212
 
 * @pk_values_only:
213
 
 * @attributes:
214
 
 *
215
 
 * Fetch the GdaValue which is in @core's resultset corresponding to the @node column
216
 
 * and the row described through @iter in the @tree_model model.
217
 
 *
218
 
 * If @attributes is not %NULL, then after the call, it will contain the #MgDataEntry attributes
219
 
 * corresponding to the value.
220
 
 *
221
 
 * The returned value can be of type GDA_VALUE_TYPE_LIST if several values are to be stored.
222
 
 *
223
 
 * Returns: the GdaValue (a newly allocated one), never returns NULL.
224
 
 */
225
 
GdaValue*
226
 
utility_grid_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter,
227
 
                              MgWorkCore *core, MgContextNode *context_node,
228
 
                              gboolean pk_values_only, guint *attributes)
229
 
{
230
 
        guint attrs = 0;
231
 
        GdaValue *retval = NULL;
232
 
        
233
 
        /* signle direct parameter */
234
 
        if (context_node->param) {
235
 
                const GdaValue *value = NULL;
236
 
                ModelUserModifiedValue *user_modif;
237
 
                gboolean is_default = FALSE;
238
 
                gboolean is_unchanged = TRUE;
239
 
                gint row;       
240
 
                const GdaValue *default_val;
241
 
 
242
 
                /* if (row >= 0) then the data row originally exists into the resultset, and
243
 
                 * otherwise it is a new row, to be inserted */
244
 
                gtk_tree_model_get (tree_model, iter, COLUMN_ROW_NUM, &row, -1);
245
 
 
246
 
                default_val = mg_parameter_get_default_value (context_node->param);
247
 
                user_modif = get_user_modifs (tree_model, iter, context_node);
248
 
                if (user_modif) {
249
 
                        value = user_modif->value;
250
 
                        attrs = user_modif->attributes;
251
 
                        is_default = attrs & MG_DATA_ENTRY_IS_DEFAULT;
252
 
                        if (row >= 0) {
253
 
                                const GdaValue *orig_value;
254
 
 
255
 
                                orig_value = get_value_from_recordset (tree_model, iter, core, context_node->param);
256
 
                                is_unchanged = FALSE;
257
 
                                if (((!value || gda_value_is_null (value)) && 
258
 
                                     (!orig_value || gda_value_is_null (orig_value))) ||
259
 
                                    (value && orig_value && 
260
 
                                     (gda_value_get_type (value) == gda_value_get_type (orig_value)) &&
261
 
                                     !gda_value_compare (value, orig_value)))
262
 
                                        is_unchanged = TRUE;
263
 
                        }
264
 
                        else
265
 
                                is_unchanged = FALSE;
266
 
                }
267
 
                else {
268
 
                        if (!g_slist_find (core->params_in_data_rs, context_node->param)) 
269
 
                                value = mg_parameter_get_value (context_node->param);
270
 
                        else {
271
 
                                if (row >= 0)
272
 
                                        value = get_value_from_recordset (tree_model, iter, core, context_node->param);
273
 
                                else
274
 
                                        value = NULL;
275
 
                        }
276
 
                }
277
 
                
278
 
                
279
 
                /* Same attributes setting as for mg-form.c mg_form_initialize() around line 296 */
280
 
                attrs = attrs | ((!value || gda_value_is_null (value)) ? MG_DATA_ENTRY_IS_NULL : 0);
281
 
                attrs = attrs | (mg_parameter_get_not_null (context_node->param) ? 0 : MG_DATA_ENTRY_CAN_BE_NULL);
282
 
                attrs = attrs | (default_val ? MG_DATA_ENTRY_CAN_BE_DEFAULT : 0);
283
 
                attrs = attrs | (is_unchanged ? MG_DATA_ENTRY_IS_UNCHANGED : 0);
284
 
                
285
 
                /* Validity calculation: the same as for mg-entry-wrapper mg_entry_wrapper_get_attributes() */
286
 
                if (! (is_default && (attrs & MG_DATA_ENTRY_CAN_BE_DEFAULT))) {
287
 
                        if (/*(gda_value_is_null (value) && !null_forced) ||*/
288
 
                            ((!value || gda_value_is_null (value)) && !(attrs & MG_DATA_ENTRY_CAN_BE_NULL)))
289
 
                                attrs = attrs | MG_DATA_ENTRY_DATA_NON_VALID;
290
 
                }
291
 
                
292
 
                /* if we are not inserting a new row, then we consider that we have an original value */
293
 
                if (row > -1)
294
 
                        attrs = attrs | MG_DATA_ENTRY_HAS_VALUE_ORIG;
295
 
                
296
 
                if (!value)
297
 
                        retval = gda_value_new_null ();
298
 
                else
299
 
                        retval = gda_value_copy (value);
300
 
 
301
 
                if (attributes)
302
 
                        *attributes = attrs;
303
 
 
304
 
                return retval;
305
 
        }
306
 
 
307
 
 
308
 
 
309
 
        /* Parameter(s) constrained by a query, we only want the PK fields for the query */
310
 
        if (pk_values_only) {
311
 
                GList *values = NULL;
312
 
                ModelUserModifiedValue *user_modif;
313
 
                gboolean is_default = TRUE;
314
 
                gboolean is_unchanged = TRUE;
315
 
                gboolean is_null = TRUE;
316
 
                gboolean can_be_default = TRUE;
317
 
                gboolean can_be_null = TRUE;
318
 
                gint row;       
319
 
                GSList *params;
320
 
                GList *list = NULL;
321
 
                
322
 
                /* if (row >= 0) then the data row originally exists into the resultset, and
323
 
                 * otherwise it is a new row, to be inserted */
324
 
                gtk_tree_model_get (tree_model, iter, COLUMN_ROW_NUM, &row, -1);
325
 
 
326
 
                user_modif = get_user_modifs (tree_model, iter, context_node);
327
 
                
328
 
                /* building the 'values' list */
329
 
                if (user_modif) {
330
 
                        if (user_modif->value && !gda_value_is_null (user_modif->value)) {
331
 
                                GList *tmplist = (GList *) gda_value_get_list (user_modif->value);
332
 
                                g_assert (gda_value_isa (user_modif->value, GDA_VALUE_TYPE_LIST));
333
 
 
334
 
                                params = context_node->params;
335
 
                                while (params) {
336
 
                                        gint pos;
337
 
 
338
 
                                        pos = GPOINTER_TO_INT (g_hash_table_lookup (context_node->params_pos_in_query, 
339
 
                                                                                    params->data));
340
 
                                        values = g_list_append (values, g_list_nth_data (tmplist, pos));
341
 
                                        params = g_slist_next (params);
342
 
                                }
343
 
                        }
344
 
 
345
 
                        attrs = user_modif->attributes;
346
 
                }
347
 
                else {
348
 
                        if (row >= 0) {
349
 
                                params = context_node->params;
350
 
                                while (params) {
351
 
                                        values = g_list_append (values, 
352
 
                                                                get_value_from_recordset (tree_model, iter, core, 
353
 
                                                                                          MG_PARAMETER (params->data)));
354
 
                                        params = g_slist_next (params);
355
 
                                }
356
 
                        }
357
 
                }
358
 
                list = values;
359
 
 
360
 
                /* computing the attributes if necessary */
361
 
                if (attributes) {
362
 
                        if (row < 0)
363
 
                                is_unchanged = FALSE;
364
 
 
365
 
                        params = context_node->params;
366
 
                        while (params) {
367
 
                                const GdaValue *value = NULL;
368
 
                                
369
 
                                if (values) {
370
 
                                        g_assert (list);
371
 
                                        value = (GdaValue *) (list->data);
372
 
                                        list = g_list_next (list);
373
 
                                }
374
 
                                
375
 
                                if (can_be_default)
376
 
                                        can_be_default = mg_parameter_get_default_value (MG_PARAMETER (params->data)) ? TRUE : FALSE;
377
 
                                
378
 
                                if (can_be_null)
379
 
                                        can_be_null = mg_parameter_get_not_null (MG_PARAMETER (params->data)) ? FALSE : TRUE;
380
 
                                
381
 
                                if (is_unchanged) {
382
 
                                        const GdaValue *orig_value;
383
 
                                        
384
 
                                        orig_value = get_value_from_recordset (tree_model, iter, core, 
385
 
                                                                               MG_PARAMETER (params->data));
386
 
                                        is_unchanged = FALSE;
387
 
                                        if (((!value || gda_value_is_null (value)) && (!orig_value || gda_value_is_null (orig_value))) ||
388
 
                                            (value && orig_value && 
389
 
                                             (gda_value_get_type (value) == gda_value_get_type (orig_value)) &&
390
 
                                             !gda_value_compare (value, orig_value)))
391
 
                                                is_unchanged = TRUE;
392
 
                                }
393
 
                                
394
 
                                if (is_null)
395
 
                                        is_null = (!value || gda_value_is_null (value)) ? TRUE : 0;
396
 
                                
397
 
                                params = g_slist_next (params);
398
 
                        }
399
 
                        
400
 
                        /* Same attributes setting as for mg-form.c mg_form_initialize() around line 296 */
401
 
                        attrs = attrs | (is_null ? MG_DATA_ENTRY_IS_NULL : 0);
402
 
                        attrs = attrs | (can_be_null ? MG_DATA_ENTRY_CAN_BE_NULL : 0);
403
 
                        attrs = attrs | (can_be_default ? MG_DATA_ENTRY_CAN_BE_DEFAULT : 0);
404
 
                        attrs = attrs | (is_unchanged ? MG_DATA_ENTRY_IS_UNCHANGED : 0);
405
 
                        
406
 
                        /* Validity calculation: the same as for mg-entry-wrapper mg_entry_wrapper_get_attributes() */
407
 
                        if (! (is_default && (attrs & MG_DATA_ENTRY_CAN_BE_DEFAULT))) {
408
 
                                if (is_null && !can_be_null)
409
 
                                        attrs = attrs | MG_DATA_ENTRY_DATA_NON_VALID;
410
 
                        }
411
 
                        
412
 
                        /* if we are not inserting a new row, then we consider that we have an original value */
413
 
                        if (row > -1)
414
 
                                attrs = attrs | MG_DATA_ENTRY_HAS_VALUE_ORIG;
415
 
                }
416
 
 
417
 
                if (values) {
418
 
                        retval = gda_value_new_list ((GdaValueList *) values);
419
 
                        g_list_free (values);
420
 
                }
421
 
                else
422
 
                        retval = gda_value_new_null ();
423
 
 
424
 
                if (attributes)
425
 
                        *attributes = attrs;
426
 
                
427
 
                return retval;
428
 
        }
429
 
 
430
 
 
431
 
        /* Parameter(s) constrained by a query, we want all the fields for the query */
432
 
        if (!pk_values_only) {
433
 
                const GdaValue *value = NULL;
434
 
                GList *values = NULL;
435
 
                ModelUserModifiedValue *user_modif;
436
 
                gboolean is_default = TRUE;
437
 
                gboolean is_unchanged = TRUE;
438
 
                gboolean is_null = TRUE;
439
 
                gboolean can_be_default = TRUE;
440
 
                gboolean can_be_null = TRUE;
441
 
                gint row;       
442
 
                GSList *params;
443
 
                GList *list = NULL;
444
 
                
445
 
                /* if (row >= 0) then the data row originally exists into the resultset, and
446
 
                 * otherwise it is a new row, to be inserted */
447
 
                gtk_tree_model_get (tree_model, iter, COLUMN_ROW_NUM, &row, -1);
448
 
 
449
 
                user_modif = get_user_modifs (tree_model, iter, context_node);
450
 
                
451
 
                /* building the 'values' list, and set 'value' if user_modif does exist */
452
 
                if (user_modif) {
453
 
                        if (user_modif->value && !gda_value_is_null (user_modif->value)) {
454
 
                                g_assert (gda_value_isa (user_modif->value, GDA_VALUE_TYPE_LIST));
455
 
 
456
 
                                value = user_modif->value;
457
 
                                values = (GList *) gda_value_get_list (user_modif->value);
458
 
                        }
459
 
 
460
 
                        attrs = user_modif->attributes;
461
 
                }
462
 
                else {
463
 
                        if (row >= 0) {
464
 
                                GSList *fields = mg_entity_get_visible_fields (MG_ENTITY (context_node->query));
465
 
                                GSList *list;
466
 
                                gint pos;
467
 
                                
468
 
                                list = fields;
469
 
                                while (list) {
470
 
                                        if (IS_MG_QF_FIELD (list->data)) {
471
 
                                                pos = GPOINTER_TO_INT (g_hash_table_lookup (core->work_context_qf_position, 
472
 
                                                                                            list->data));
473
 
                                                g_assert (pos >= 0);
474
 
                                                values = g_list_append (values, mg_resultset_get_gdavalue (core->data_rs, row, pos));
475
 
                                        }
476
 
                                        list = g_slist_next (list);
477
 
                                }
478
 
                                g_slist_free (fields);
479
 
                        }
480
 
                }
481
 
                list = values;
482
 
 
483
 
                /* computing the attributes if necessary */
484
 
                if (attributes) {
485
 
                        if (row < 0)
486
 
                                is_unchanged = FALSE;
487
 
 
488
 
                        params = context_node->params;
489
 
                        while (params) {
490
 
                                const GdaValue *value = NULL;
491
 
                                
492
 
                                if (values) {
493
 
                                        g_assert (list);
494
 
                                        value = (GdaValue *) (list->data);
495
 
                                        list = g_list_next (list);
496
 
                                }
497
 
                                
498
 
                                if (can_be_default)
499
 
                                        can_be_default = mg_parameter_get_default_value (MG_PARAMETER (params->data)) ? TRUE : FALSE;
500
 
                                
501
 
                                if (can_be_null)
502
 
                                        can_be_null = mg_parameter_get_not_null (MG_PARAMETER (params->data)) ? FALSE : TRUE;
503
 
                                
504
 
                                if (is_unchanged) {
505
 
                                        const GdaValue *orig_value;
506
 
                                        
507
 
                                        orig_value = get_value_from_recordset (tree_model, iter, core, MG_PARAMETER (params->data));
508
 
                                        is_unchanged = FALSE;
509
 
                                        if (((!value || gda_value_is_null (value)) && (!orig_value || gda_value_is_null (orig_value))) ||
510
 
                                            (value && orig_value && 
511
 
                                             (gda_value_get_type (value) == gda_value_get_type (orig_value)) &&
512
 
                                             !gda_value_compare (value, orig_value)))
513
 
                                                is_unchanged = TRUE;
514
 
                                }
515
 
                                
516
 
                                if (is_null)
517
 
                                        is_null = (!value || gda_value_is_null (value)) ? TRUE : 0;
518
 
                                
519
 
                                params = g_slist_next (params);
520
 
                        }
521
 
                        
522
 
                        /* Same attributes setting as for mg-form.c mg_form_initialize() around line 296 */
523
 
                        attrs = attrs | (is_null ? MG_DATA_ENTRY_IS_NULL : 0);
524
 
                        attrs = attrs | (can_be_null ? MG_DATA_ENTRY_CAN_BE_NULL : 0);
525
 
                        attrs = attrs | (can_be_default ? MG_DATA_ENTRY_CAN_BE_DEFAULT : 0);
526
 
                        attrs = attrs | (is_unchanged ? MG_DATA_ENTRY_IS_UNCHANGED : 0);
527
 
                        
528
 
                        /* Validity calculation: the same as for mg-entry-wrapper mg_entry_wrapper_get_attributes() */
529
 
                        if (! (is_default && (attrs & MG_DATA_ENTRY_CAN_BE_DEFAULT))) {
530
 
                                if (is_null && !can_be_null)
531
 
                                        attrs = attrs | MG_DATA_ENTRY_DATA_NON_VALID;
532
 
                        }
533
 
                        
534
 
                        /* if we are not inserting a new row, then we consider that we have an original value */
535
 
                        if (row > -1)
536
 
                                attrs = attrs | MG_DATA_ENTRY_HAS_VALUE_ORIG;
537
 
                }
538
 
 
539
 
                if (value)
540
 
                        retval = gda_value_copy (value);
541
 
                else {
542
 
                        if (values) {
543
 
                                retval = gda_value_new_list ((GdaValueList *) values);
544
 
                                g_list_free (values);
545
 
                        }
546
 
                        else
547
 
                                retval = gda_value_new_null ();
548
 
                }
549
 
                if (attributes)
550
 
                        *attributes = attrs;
551
 
                
552
 
                return retval;
553
 
        }
554
 
 
555
 
        /* not reached */
556
 
        return NULL;
557
 
}
558
 
 
559
 
static const GdaValue *
560
 
get_value_from_recordset (GtkTreeModel *tree_model, GtkTreeIter *iter, MgWorkCore *core, MgParameter *context_param)
561
 
{
562
 
        gint col;
563
 
        MgWorkCoreNode *cnode;
564
 
        gint row;
565
 
        
566
 
        g_return_val_if_fail (context_param, NULL);
567
 
 
568
 
        gtk_tree_model_get (tree_model, iter, COLUMN_ROW_NUM, &row, -1);
569
 
        cnode = mg_work_core_find_core_node (core, context_param);
570
 
        g_assert (cnode);
571
 
 
572
 
        col = cnode->position;
573
 
        g_assert (col >= 0);
574
 
                
575
 
        return mg_resultset_get_gdavalue (core->data_rs, row, col);     
576
 
}
577
 
 
578
 
static ModelUserModifiedValue *
579
 
get_user_modifs (GtkTreeModel *tree_model, GtkTreeIter *iter, MgContextNode *context_node)
580
 
{
581
 
        ModelUserModifiedRow *user_modifs;
582
 
        ModelUserModifiedValue *user_value = NULL;
583
 
        
584
 
        gtk_tree_model_get (tree_model, iter, COLUMN_USER_MODIFS_ROW, &user_modifs, -1);
585
 
        if (user_modifs) {
586
 
                GSList *list;
587
 
                list = user_modifs->user_values;
588
 
                while (list && !user_value) {
589
 
                        if (MODEL_USER_MODIFIED_VALUE (list->data)->context_node == context_node)
590
 
                                user_value = MODEL_USER_MODIFIED_VALUE (list->data);
591
 
                        list = g_slist_next (list);
592
 
                }               
593
 
        }
594
 
 
595
 
        return user_value;
596
 
}
597
 
 
598
 
 
599
 
 
600
 
 
601
 
 
602
 
static void combo_core_nullified_query_cb (MgQuery *query, ComboCore *ccore);
603
 
static void combo_core_nullified_param_cb (MgParameter *param, ComboCore *ccore);
604
 
static gint *utility_combo_compute_choice_columns_mask (ComboCore *core, gint *mask_size);
605
 
/**
606
 
 * utility_combo_initialize_core
607
 
 * @conf:
608
 
 * @context:
609
 
 * @node:
610
 
 * @dependency_param_callback:
611
 
 * @data:
612
 
 *
613
 
 * Returns: a new ComboCore
614
 
 */
615
 
ComboCore *
616
 
utility_combo_initialize_core (MgConf *conf, MgContext *context, MgContextNode *node,
617
 
                               GCallback dependency_param_callback, gpointer data)
618
 
{
619
 
        ComboCore *ccore;
620
 
        GSList *list;
621
 
 
622
 
        g_return_val_if_fail (node && node->query, NULL);
623
 
 
624
 
        ccore = g_new0 (ComboCore, 1);
625
 
 
626
 
        /* main fields */
627
 
        ccore->conf = conf;
628
 
        g_object_add_weak_pointer (G_OBJECT (ccore->conf), (gpointer) &(ccore->conf));
629
 
 
630
 
        ccore->context = context;
631
 
        g_object_add_weak_pointer (G_OBJECT (ccore->context), (gpointer) &(ccore->context));
632
 
 
633
 
        ccore->query = node->query;
634
 
        g_object_ref (G_OBJECT (ccore->query));
635
 
        g_signal_connect (G_OBJECT (ccore->query), "nullified",
636
 
                          G_CALLBACK (combo_core_nullified_query_cb), ccore);
637
 
        list = mg_entity_get_visible_fields (MG_ENTITY (ccore->query));
638
 
        ccore->nb_visible_cols = g_slist_length (list);
639
 
        g_slist_free (list);
640
 
        ccore->dependency_param_callback = dependency_param_callback;
641
 
        ccore->dependency_data = data;
642
 
 
643
 
        /* parameters */
644
 
        list = node->params;
645
 
        while (list) {
646
 
                MgField *source_field;
647
 
                ComboNode *cnode = g_new0 (ComboNode, 1);
648
 
 
649
 
                source_field = MG_FIELD (mg_parameter_get_source_field (MG_PARAMETER (list->data)));
650
 
                cnode->param = MG_PARAMETER (list->data);
651
 
                cnode->position = mg_entity_get_field_index (MG_ENTITY (ccore->query), source_field);
652
 
                cnode->value_orig = NULL;
653
 
                cnode->value_default = NULL;
654
 
                ccore->nodes = g_slist_append (ccore->nodes, cnode);
655
 
                g_object_ref (G_OBJECT (list->data));
656
 
                g_signal_connect (G_OBJECT (list->data), "nullified",
657
 
                                  G_CALLBACK (combo_core_nullified_param_cb), ccore);
658
 
 
659
 
                list = g_slist_next (list);
660
 
        }
661
 
 
662
 
        /* connect the parameters dependencies */
663
 
        list = ccore->nodes;
664
 
        while (list) {
665
 
                /* FIXME: make sure we don't connect several times to the changes of one single param */
666
 
                GSList *depend = mg_parameter_get_dependencies (COMBO_NODE (list->data)->param);
667
 
                while (depend) {
668
 
                        g_signal_connect (G_OBJECT (depend->data), "changed",
669
 
                                          G_CALLBACK (dependency_param_callback), data);
670
 
                        depend = g_slist_next (depend);
671
 
                }
672
 
                list = g_slist_next (list);
673
 
        }
674
 
 
675
 
        /* compute the mask and its size */
676
 
        ccore->mask = utility_combo_compute_choice_columns_mask (ccore, &(ccore->masksize));
677
 
 
678
 
        return ccore;
679
 
}
680
 
 
681
 
static void
682
 
combo_core_nullified_query_cb (MgQuery *query, ComboCore *ccore)
683
 
{
684
 
        g_assert (ccore->query == query);
685
 
        g_signal_handlers_disconnect_by_func (G_OBJECT (query),
686
 
                                              G_CALLBACK (combo_core_nullified_query_cb), ccore);
687
 
        g_object_unref (G_OBJECT (query));
688
 
        ccore->query = NULL;
689
 
}
690
 
 
691
 
static void
692
 
combo_core_nullified_param_cb (MgParameter *param, ComboCore *ccore)
693
 
{
694
 
        /* remove the associated ComboNode */
695
 
        GSList *list;
696
 
        ComboNode *node = NULL;
697
 
 
698
 
        list = ccore->nodes;
699
 
        while (list) {
700
 
                if (COMBO_NODE (list->data)->param == param)
701
 
                        node = COMBO_NODE (list->data);
702
 
                list = g_slist_next (list);
703
 
        }
704
 
 
705
 
        g_assert (node);
706
 
        ccore->nodes = g_slist_remove (ccore->nodes, node);
707
 
        g_signal_handlers_disconnect_by_func (G_OBJECT (param),
708
 
                                              G_CALLBACK (combo_core_nullified_param_cb), ccore);
709
 
        list = mg_parameter_get_dependencies (node->param);
710
 
        while (list) {
711
 
                g_signal_handlers_disconnect_by_func (G_OBJECT (list->data),
712
 
                                                      G_CALLBACK (ccore->dependency_param_callback), ccore->dependency_data);
713
 
                list = g_slist_next (list);
714
 
        }
715
 
 
716
 
        g_object_unref (G_OBJECT (param));
717
 
        if (node->value)
718
 
                node->value = NULL; /* don't free that value since we have not copied it */
719
 
        if (node->value_orig)
720
 
                gda_value_free (node->value_orig);
721
 
        if (node->value_default)
722
 
                gda_value_free (node->value_default);
723
 
        g_free (node);
724
 
}
725
 
 
726
 
 
727
 
/**
728
 
 * utility_combo_free_core
729
 
 *
730
 
 * Free @core and cleans the associated memory allocations made when utility_combo_initialize_core()
731
 
 * was called.
732
 
 */
733
 
void
734
 
utility_combo_free_core (ComboCore *ccore)
735
 
{
736
 
        while (ccore->nodes) {
737
 
                ComboNode *node = COMBO_NODE (ccore->nodes->data);
738
 
                g_assert (node->param);
739
 
                combo_core_nullified_param_cb (node->param, ccore);
740
 
        }
741
 
 
742
 
        if (ccore->mask)
743
 
                g_free (ccore->mask);
744
 
 
745
 
        if (ccore->query)
746
 
                combo_core_nullified_query_cb (ccore->query, ccore);
747
 
 
748
 
        if (ccore->conf)
749
 
                g_object_remove_weak_pointer (G_OBJECT (ccore->conf), 
750
 
                                              (gpointer) &(ccore->conf));
751
 
        
752
 
        if (ccore->context)
753
 
                g_object_remove_weak_pointer (G_OBJECT (ccore->context),
754
 
                                              (gpointer) &(ccore->context));
755
 
        
756
 
        utility_combo_destroy_model (ccore);
757
 
 
758
 
        g_free (ccore);
759
 
}
760
 
 
761
 
static GdaDataModel *make_single_line_model (const gchar *line);
762
 
 
763
 
/**
764
 
 * utility_combo_compute_model
765
 
 * @core:
766
 
 *
767
 
 * Computes a new GdaDataModel model (eventualy re-runs 'core->query') if necessary.
768
 
 * Some special 1 line models are created in case of errors.
769
 
 */
770
 
void
771
 
utility_combo_compute_model (ComboCore *core)
772
 
{
773
 
        MgServer *srv;
774
 
        gboolean valid_data;
775
 
        GdaDataModel *data_model = NULL;
776
 
 
777
 
        srv = mg_conf_get_server (core->conf);
778
 
        utility_combo_destroy_model (core);
779
 
 
780
 
        if (mg_server_conn_is_opened (srv)) {
781
 
                MgResultSet *rs = NULL;
782
 
                gchar *sql;
783
 
                GError *error = NULL;
784
 
                
785
 
                sql = mg_renderer_render_as_sql (MG_RENDERER (core->query), core->context, 0, &error);
786
 
                if (!sql) {
787
 
                        valid_data = FALSE;
788
 
                        data_model = make_single_line_model (_("No value available"));
789
 
                        if (error) {
790
 
                                g_warning ("COMBO Model update SQL execution error: %s", error->message);
791
 
                                g_error_free (error);
792
 
                        }
793
 
                }
794
 
                else {
795
 
                        rs = mg_server_do_query (srv, sql, MG_SERVER_QUERY_SQL, &error);
796
 
                        if (!rs) {
797
 
                                valid_data = FALSE;
798
 
                                data_model = make_single_line_model (error->message);
799
 
                                g_error_free (error);
800
 
                        }
801
 
                        else {
802
 
                                if (mg_resultset_get_nbtuples (rs) == 0) {
803
 
                                        valid_data = FALSE;
804
 
                                        data_model = make_single_line_model (_("No value available"));
805
 
                                }
806
 
                                else {
807
 
                                        valid_data = TRUE;
808
 
                                        core->resultset = rs;
809
 
                                        data_model = mg_resultset_get_data_model (rs);
810
 
 
811
 
                                        /* keep our own reference on the data model */
812
 
                                        g_object_ref (G_OBJECT (data_model));
813
 
                                }
814
 
                        }
815
 
                }
816
 
        }
817
 
        else {
818
 
                valid_data = FALSE;
819
 
                data_model = make_single_line_model (_("Connection not opened"));
820
 
        }
821
 
 
822
 
        /* setting the new model */
823
 
        core->data_model = data_model;
824
 
        core->data_model_valid = valid_data;
825
 
}
826
 
 
827
 
/*
828
 
 * Creates a MgDataModel object with a single line and column
829
 
 * containing the provided message
830
 
 */
831
 
static GdaDataModel *
832
 
make_single_line_model (const gchar *line)
833
 
{
834
 
        GdaValue *value;
835
 
        GdaDataModel *data_model;
836
 
        GList *rowvalues;
837
 
        
838
 
        data_model = gda_data_model_array_new (1);
839
 
        value = gda_value_new_string (line);
840
 
        rowvalues = g_list_append (NULL, value);
841
 
        gda_data_model_append_row (GDA_DATA_MODEL (data_model), rowvalues);
842
 
        g_list_free (rowvalues);
843
 
        gda_value_free (value);
844
 
 
845
 
        return data_model;
846
 
}
847
 
 
848
 
/**
849
 
 * utility_combo_destroy_model
850
 
 * @core:
851
 
 *
852
 
 * Free the memory associated with @core's model
853
 
 */
854
 
void
855
 
utility_combo_destroy_model (ComboCore *core)
856
 
{
857
 
        if (core->data_model) {
858
 
                g_object_unref (core->data_model);
859
 
                core->data_model = NULL;
860
 
                core->data_model_valid = FALSE;
861
 
        }
862
 
 
863
 
        if (core->resultset) {
864
 
                g_object_unref (G_OBJECT (core->resultset));
865
 
                core->resultset = NULL;
866
 
        }
867
 
}
868
 
 
869
 
 
870
 
/**
871
 
 * utility_combo_compute_choice_strings
872
 
 * @core:
873
 
 *
874
 
 * Creates a list of (allocated strings), one for each row of the data model stored within @core
875
 
 * ('core->data_model')
876
 
 *
877
 
 * Returns: a new list of strings
878
 
 */
879
 
GList *
880
 
utility_combo_compute_choice_strings (ComboCore *core)
881
 
{
882
 
        GList *strings = NULL;
883
 
        const GdaValue *value;
884
 
        gint nrows, i, j;
885
 
        GString *str;
886
 
        gchar *tmpstr;
887
 
        GdaDataModel *model = core->data_model;
888
 
        
889
 
        /* actual string rendering */
890
 
        nrows = gda_data_model_get_n_rows (model);
891
 
        for (i=0; i<nrows; i++) {
892
 
                str = g_string_new ("");
893
 
                if (core->mask) {
894
 
                        for (j=0; j<core->masksize; j++) {
895
 
                                value = gda_data_model_get_value_at (model, core->mask[j], i);
896
 
                                if (value && !gda_value_is_null (value))
897
 
                                        tmpstr = gda_value_stringify (value);
898
 
                                else
899
 
                                        tmpstr = g_strdup ("---");
900
 
 
901
 
                                if (j>0)
902
 
                                        g_string_append (str, " / " );
903
 
                                g_string_append (str, tmpstr);
904
 
                                g_free (tmpstr);
905
 
                        }
906
 
                }
907
 
 
908
 
                strings = g_list_append (strings, str->str);
909
 
                g_string_free (str, FALSE);
910
 
        }
911
 
        
912
 
        return strings;
913
 
}
914
 
 
915
 
/**
916
 
 * utility_combo_compute_display_string
917
 
 * @core:
918
 
 *
919
 
 * Creates a new string for @core (no query is run and no value is searched for 
920
 
 * in any resultset)
921
 
 *
922
 
 * Returns: a new string to display
923
 
 */
924
 
gchar *
925
 
utility_combo_compute_display_string (ComboCore *core, GList *values)
926
 
{
927
 
        gchar *retval = NULL;
928
 
        const GdaValue *value;
929
 
        gint j;
930
 
        GString *str;
931
 
        gchar *tmpstr;
932
 
        
933
 
        g_return_val_if_fail (values && (g_list_length (values) == core->nb_visible_cols), NULL);
934
 
 
935
 
        /* actual string rendering */
936
 
        str = g_string_new ("");
937
 
        if (core->mask) {
938
 
                for (j=0; j<core->masksize; j++) {
939
 
                        value = (GdaValue*) g_list_nth_data (values, core->mask[j]);
940
 
                        if (value && !gda_value_is_null (value))
941
 
                                tmpstr = gda_value_stringify (value);
942
 
                        else
943
 
                                tmpstr = g_strdup ("---");
944
 
                        if (j>0)
945
 
                                g_string_append (str, " / " );
946
 
                        if (tmpstr) {
947
 
                                g_string_append (str, tmpstr);
948
 
                                g_free (tmpstr);
949
 
                        }
950
 
                }
951
 
        }
952
 
 
953
 
        retval = str->str;
954
 
        g_string_free (str, FALSE);
955
 
        
956
 
        return retval;
957
 
}
958
 
 
959
 
 
960
 
/**
961
 
 * utility_combo_compute_choice_columns_mask
962
 
 * @core:
963
 
 * @mask_size:
964
 
 *
965
 
 * Create a mask of which column of the resultset needs to be displayed in a combo box.
966
 
 * The mask is an array of the column numbers to be displayed, and must be de-allocated after usage.
967
 
 *
968
 
 * Returns: a new array of columns to display
969
 
 */
970
 
static gint *
971
 
utility_combo_compute_choice_columns_mask (ComboCore *core, gint *mask_size)
972
 
{
973
 
        gint ncols;
974
 
        gint *mask = NULL, masksize = 0;
975
 
        
976
 
        /* mask making: we only want columns which are not parameter values and if not internal MgQField */
977
 
        ncols = core->nb_visible_cols;
978
 
        if (ncols - g_slist_length (core->nodes) > 0) {
979
 
                gint i, current = 0;
980
 
                
981
 
                masksize = ncols - g_slist_length (core->nodes);
982
 
                mask = g_new0 (gint, masksize);
983
 
                for (i=0; i<ncols ; i++) {
984
 
                        GSList *list = core->nodes;
985
 
                        gboolean found = FALSE;
986
 
                        while (list && !found) {
987
 
                                if (COMBO_NODE (list->data)->position == i)
988
 
                                        found = TRUE;
989
 
                                else
990
 
                                        list = g_slist_next (list);
991
 
                        }
992
 
                        if (!found) {
993
 
                                MgField *field = mg_entity_get_field_by_index (MG_ENTITY (core->query), i);
994
 
 
995
 
                                if (!mg_qfield_is_internal (MG_QFIELD (field))) {
996
 
                                        mask[current] = i;
997
 
                                        current ++;
998
 
                                }
999
 
                        }
1000
 
                }
1001
 
                masksize = current;
1002
 
        }
1003
 
        else {
1004
 
                gint i;
1005
 
 
1006
 
                masksize = ncols;
1007
 
                mask = g_new0 (gint, masksize);
1008
 
                for (i=0; i<ncols; i++) {
1009
 
                        mask[i] = i;
1010
 
                }
1011
 
        }
1012
 
 
1013
 
        if (mask_size)
1014
 
                *mask_size = masksize;
1015
 
 
1016
 
        return mask;
1017
 
}