~ubuntu-branches/ubuntu/oneiric/libgda4/oneiric

1 by Christophe Sauthier
Import upstream version 3.99.11
1
/* gda-set.c
2
 *
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
3
 * Copyright (C) 2003 - 2010 Vivien Malerba
1 by Christophe Sauthier
Import upstream version 3.99.11
4
 *
5
 * This Library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Library 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.
9
 *
10
 * This Library 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 GNU
13
 * Library General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Library General Public
16
 * License along with this Library; see the file COPYING.LIB.  If not,
17
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
 * Boston, MA 02111-1307, USA.
19
 */
20
21
#include <stdarg.h>
22
#include <string.h>
23
#ifdef HAVE_SYS_TYPES_H
24
#include <sys/types.h>
25
#endif
26
#include <glib/gi18n-lib.h>
27
#ifdef HAVE_LOCALE_H
28
#include <locale.h>
29
#endif
30
#include "gda-set.h"
31
#include "gda-marshal.h"
32
#include "gda-data-model.h"
33
#include "gda-data-model-import.h"
34
#include "gda-holder.h"
35
#include "gda-connection.h"
36
#include "gda-server-provider.h"
37
#include "gda-util.h"
38
#include <libgda/gda-custom-marshal.h>
1.1.2 by Andreas Moog
Import upstream version 4.0.0
39
#include <libgda/gda-types.h>
1 by Christophe Sauthier
Import upstream version 3.99.11
40
41
extern xmlDtdPtr gda_paramlist_dtd;
42
extern gchar *gda_lang_locale;
43
44
/* 
45
 * Main static functions 
46
 */
47
static void gda_set_class_init (GdaSetClass *class);
48
static void gda_set_init (GdaSet *set);
49
static void gda_set_dispose (GObject *object);
50
static void gda_set_finalize (GObject *object);
51
52
static void set_remove_node (GdaSet *set, GdaSetNode *node);
53
static void set_remove_source (GdaSet *set, GdaSetSource *source);
54
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
55
1 by Christophe Sauthier
Import upstream version 3.99.11
56
static void changed_holder_cb (GdaHolder *holder, GdaSet *dataset);
57
static GError *validate_change_holder_cb (GdaHolder *holder, const GValue *value, GdaSet *dataset);
58
static void source_changed_holder_cb (GdaHolder *holder, GdaSet *dataset);
59
static void att_holder_changed_cb (GdaHolder *holder, const gchar *att_name, const GValue *att_value, GdaSet *dataset);
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
60
static void holder_notify_cb (GdaHolder *holder, GParamSpec *pspec, GdaSet *dataset);
61
1 by Christophe Sauthier
Import upstream version 3.99.11
62
63
static void compute_public_data (GdaSet *set);
64
static gboolean gda_set_real_add_holder (GdaSet *set, GdaHolder *holder);
65
66
/* get a pointer to the parents to be able to call their destructor */
67
static GObjectClass  *parent_class = NULL;
68
69
/* properties */
70
enum
71
{
72
	PROP_0,
73
	PROP_ID,
74
	PROP_NAME,
75
	PROP_DESCR,
76
	PROP_HOLDERS
77
};
78
79
/* signals */
80
enum
81
{
82
	HOLDER_CHANGED,
83
	PUBLIC_DATA_CHANGED,
84
	HOLDER_ATTR_CHANGED,
85
	VALIDATE_HOLDER_CHANGE,
86
	VALIDATE_SET,
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
87
	HOLDER_TYPE_SET,
88
	SOURCE_MODEL_CHANGED,
1 by Christophe Sauthier
Import upstream version 3.99.11
89
	LAST_SIGNAL
90
};
91
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
92
static gint gda_set_signals[LAST_SIGNAL] = { 0, 0, 0, 0, 0, 0 };
1 by Christophe Sauthier
Import upstream version 3.99.11
93
94
95
/* private structure */
96
struct _GdaSetPrivate
97
{
98
	gchar           *id;
99
	gchar           *name;
100
	gchar           *descr;
101
	GHashTable      *holders_hash; /* key = GdaHoler ID, value = GdaHolder */
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
102
	GArray          *holders_array;
103
	gboolean         read_only;
1 by Christophe Sauthier
Import upstream version 3.99.11
104
};
105
106
static void 
107
gda_set_set_property (GObject *object,
108
		      guint param_id,
109
		      const GValue *value,
110
		      GParamSpec *pspec)
111
{
112
	GdaSet* set;
113
	set = GDA_SET (object);
114
115
	switch (param_id) {
116
	case PROP_ID:
117
		g_free (set->priv->id);
118
		set->priv->id = g_value_dup_string (value);
119
		break;
120
	case PROP_NAME:
121
		g_free (set->priv->name);
122
		set->priv->name = g_value_dup_string (value);
123
		break;
124
	case PROP_DESCR:
125
		g_free (set->priv->descr);
126
		set->priv->descr = g_value_dup_string (value);
127
		break;
128
	case PROP_HOLDERS: {
129
		/* add the holders */
130
		GSList* holders;
131
		for (holders = (GSList*) g_value_get_pointer(value); holders; holders = holders->next) 
132
			gda_set_real_add_holder (set, GDA_HOLDER (holders->data));
133
		compute_public_data (set);	
134
		break;
135
	}
136
	default:
137
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
138
		break;
139
	}
140
}
141
142
static void
143
gda_set_get_property (GObject *object,
144
		      guint param_id,
145
		      GValue *value,
146
		      GParamSpec *pspec)
147
{
148
	GdaSet* set;
149
	set = GDA_SET (object);
150
151
	switch (param_id) {
152
	case PROP_ID:
153
		g_value_set_string (value, set->priv->id);
154
		break;
155
	case PROP_NAME:
156
		if (set->priv->name)
157
			g_value_set_string (value, set->priv->name);
158
		else
159
			g_value_set_string (value, set->priv->id);
160
		break;
161
	case PROP_DESCR:
162
		g_value_set_string (value, set->priv->descr);
163
		break;
164
	default:
165
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
166
		break;
167
	}
168
}
169
170
/* module error */
171
GQuark gda_set_error_quark (void)
172
{
173
	static GQuark quark;
174
	if (!quark)
175
		quark = g_quark_from_static_string ("gda_set_error");
176
	return quark;
177
}
178
179
180
GType
181
gda_set_get_type (void)
182
{
183
	static GType type = 0;
184
185
	if (G_UNLIKELY (type == 0)) {
186
		static GStaticMutex registering = G_STATIC_MUTEX_INIT;
187
		static const GTypeInfo info = {
188
			sizeof (GdaSetClass),
189
			(GBaseInitFunc) NULL,
190
			(GBaseFinalizeFunc) NULL,
191
			(GClassInitFunc) gda_set_class_init,
192
			NULL,
193
			NULL,
194
			sizeof (GdaSet),
195
			0,
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
196
			(GInstanceInitFunc) gda_set_init,
197
			0
1 by Christophe Sauthier
Import upstream version 3.99.11
198
		};
199
		
200
		g_static_mutex_lock (&registering);
201
		if (type == 0)
202
			type = g_type_register_static (G_TYPE_OBJECT, "GdaSet", &info, 0);
203
		g_static_mutex_unlock (&registering);
204
	}
205
206
	return type;
207
}
208
209
static gboolean
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
210
validate_accumulator (G_GNUC_UNUSED GSignalInvocationHint *ihint,
1 by Christophe Sauthier
Import upstream version 3.99.11
211
		      GValue *return_accu,
212
		      const GValue *handler_return,
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
213
		      G_GNUC_UNUSED gpointer data)
1 by Christophe Sauthier
Import upstream version 3.99.11
214
{
215
	GError *error;
216
217
	error = g_value_get_boxed (handler_return);
218
	g_value_set_boxed (return_accu, error);
219
220
	return error ? FALSE : TRUE; /* stop signal if an error has been set */
221
}
222
223
static GError *
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
224
m_validate_holder_change (G_GNUC_UNUSED GdaSet *set, G_GNUC_UNUSED GdaHolder *holder,
225
			  G_GNUC_UNUSED const GValue *new_value)
1 by Christophe Sauthier
Import upstream version 3.99.11
226
{
227
	return NULL;
228
}
229
230
static GError *
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
231
m_validate_set (G_GNUC_UNUSED GdaSet *set)
1 by Christophe Sauthier
Import upstream version 3.99.11
232
{
233
	return NULL;
234
}
235
236
static void
237
gda_set_class_init (GdaSetClass *class)
238
{
239
	GObjectClass   *object_class = G_OBJECT_CLASS (class);
240
241
	parent_class = g_type_class_peek_parent (class);
242
243
	gda_set_signals[HOLDER_CHANGED] =
244
		g_signal_new ("holder-changed",
245
			      G_TYPE_FROM_CLASS (object_class),
246
			      G_SIGNAL_RUN_FIRST,
247
			      G_STRUCT_OFFSET (GdaSetClass, holder_changed),
248
			      NULL, NULL,
249
			      _gda_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
250
			      GDA_TYPE_HOLDER);
251
252
	/**
253
	 * GdaSet::validate-holder-change
254
	 * @set: the #GdaSet
255
	 * @holder: the #GdaHolder which is going to change
256
	 * @new_value: the proposed new value for @holder
257
	 * 
258
	 * Gets emitted when a #GdaHolder's in @set is going to change its value. One can connect to
259
	 * this signal to control which values @holder can have (for example to implement some business rules)
260
	 *
261
	 * Return value: NULL if @holder is allowed to change its value to @new_value, or a #GError
262
	 * otherwise.
263
	 */
264
	gda_set_signals[VALIDATE_HOLDER_CHANGE] =
265
		g_signal_new ("validate-holder-change",
266
			      G_TYPE_FROM_CLASS (object_class),
267
			      G_SIGNAL_RUN_LAST,
268
			      G_STRUCT_OFFSET (GdaSetClass, validate_holder_change),
269
			      validate_accumulator, NULL,
270
			      _gda_marshal_ERROR__OBJECT_VALUE, GDA_TYPE_ERROR, 2,
271
			      GDA_TYPE_HOLDER, G_TYPE_VALUE);
272
	/**
273
	 * GdaSet::validate-set
274
	 * @set: the #GdaSet
275
	 * 
276
	 * Gets emitted when gda_set_is_valid() is called, use
277
	 * this signal to control which combination of values @set's holder can have (for example to implement some business rules)
278
	 *
279
	 * Return value: NULL if @set's contents has been validated, or a #GError
280
	 * otherwise.
281
	 */
282
	gda_set_signals[VALIDATE_SET] =
283
		g_signal_new ("validate-set",
284
			      G_TYPE_FROM_CLASS (object_class),
285
			      G_SIGNAL_RUN_LAST,
286
			      G_STRUCT_OFFSET (GdaSetClass, validate_set),
287
			      validate_accumulator, NULL,
288
			      _gda_marshal_ERROR__VOID, GDA_TYPE_ERROR, 0);
289
	/**
290
	 * GdaSet::holder-attr-changed
291
	 * @set: the #GdaSet
292
	 * @holder: the GdaHolder for which an attribute changed
293
	 * @attr_name: attribute's name
294
	 * @attr_value: attribute's value
295
	 * 
296
	 * Gets emitted when an attribute for any of the #GdaHolder objects managed by @set has changed
297
	 */
298
	gda_set_signals[HOLDER_ATTR_CHANGED] =
299
		g_signal_new ("holder-attr-changed",
300
			      G_TYPE_FROM_CLASS (object_class),
301
			      G_SIGNAL_RUN_FIRST,
302
			      G_STRUCT_OFFSET (GdaSetClass, holder_attr_changed),
303
			      NULL, NULL,
304
			      _gda_marshal_VOID__OBJECT_STRING_VALUE, G_TYPE_NONE, 3,
305
			      GDA_TYPE_HOLDER, G_TYPE_STRING, G_TYPE_VALUE);
306
	/**
307
	 * GdaSet::public-data-changed
308
	 * @set: the #GdaSet
309
	 * 
310
	 * Gets emitted when @set's public data (#GdaSetNode, #GdaSetGroup or #GdaSetSource values) have changed
311
	 */
312
	gda_set_signals[PUBLIC_DATA_CHANGED] =
313
		g_signal_new ("public-data-changed",
314
			      G_TYPE_FROM_CLASS (object_class),
315
			      G_SIGNAL_RUN_FIRST,
316
			      G_STRUCT_OFFSET (GdaSetClass, public_data_changed),
317
			      NULL, NULL,
318
			      _gda_marshal_VOID__VOID, G_TYPE_NONE, 0);
319
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
320
	/**
321
	 * GdaSet::holder-type-set
322
	 * @set: the #GdaSet
323
	 * @holder: the #GdaHolder for which the #GType has been set
324
	 *
325
	 * Gets emitted when @holder in @set has its type finally set, in case
326
	 * it was #GDA_TYPE_NULL
327
	 *
328
	 * Since: 4.2
329
	 */
330
	gda_set_signals[HOLDER_TYPE_SET] =
331
		g_signal_new ("holder-type-set",
332
			      G_TYPE_FROM_CLASS (object_class),
333
			      G_SIGNAL_RUN_FIRST,
334
			      G_STRUCT_OFFSET (GdaSetClass, holder_type_set),
335
			      NULL, NULL,
336
			      _gda_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
337
			      GDA_TYPE_HOLDER);
338
339
	/**
340
	 * GdaSet::source-model-changed
341
	 * @set: the #GdaSet
342
	 * @source: the #GdaSetSource for which the @data_model attribute has changed
343
	 *
344
	 * Gets emitted when the data model in @source has changed
345
	 *
346
	 * Since: 4.2
347
	 */
348
	gda_set_signals[SOURCE_MODEL_CHANGED] =
349
		g_signal_new ("source-model-changed",
350
			      G_TYPE_FROM_CLASS (object_class),
351
			      G_SIGNAL_RUN_FIRST,
352
			      G_STRUCT_OFFSET (GdaSetClass, source_model_changed),
353
			      NULL, NULL,
354
			      _gda_marshal_VOID__POINTER, G_TYPE_NONE, 1,
355
			      G_TYPE_POINTER);
356
357
1 by Christophe Sauthier
Import upstream version 3.99.11
358
	class->holder_changed = NULL;
359
	class->validate_holder_change = m_validate_holder_change;
360
	class->validate_set = m_validate_set;
361
	class->holder_attr_changed = NULL;
362
	class->public_data_changed = NULL;
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
363
	class->holder_type_set = NULL;
364
	class->source_model_changed = NULL;
1 by Christophe Sauthier
Import upstream version 3.99.11
365
366
	/* Properties */
367
	object_class->set_property = gda_set_set_property;
368
	object_class->get_property = gda_set_get_property;
369
	g_object_class_install_property (object_class, PROP_ID,
370
					 g_param_spec_string ("id", NULL, "Id", NULL, 
371
							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
372
	g_object_class_install_property (object_class, PROP_NAME,
373
					 g_param_spec_string ("name", NULL, "Name", NULL, 
374
							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
375
	g_object_class_install_property (object_class, PROP_DESCR,
376
					 g_param_spec_string ("description", NULL, "Description", NULL, 
377
							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
378
	g_object_class_install_property (object_class, PROP_HOLDERS,
379
					 g_param_spec_pointer ("holders", "GSList of GdaHolders", 
380
							       "GdaHolder objects the set should contain", (
381
								G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
382
  
383
	object_class->dispose = gda_set_dispose;
384
	object_class->finalize = gda_set_finalize;
385
}
386
387
static void
388
gda_set_init (GdaSet *set)
389
{
390
	set->priv = g_new0 (GdaSetPrivate, 1);
391
	set->holders = NULL;
392
	set->nodes_list = NULL;
393
	set->sources_list = NULL;
394
	set->groups_list = NULL;
395
	set->priv->holders_hash = g_hash_table_new (g_str_hash, g_str_equal);
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
396
	set->priv->holders_array = NULL;
397
	set->priv->read_only = FALSE;
1 by Christophe Sauthier
Import upstream version 3.99.11
398
}
399
400
401
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
402
 * gda_set_new:
403
 * @holders: (element-type GdaHolder) (transfer:none): a list of #GdaHolder objects
1 by Christophe Sauthier
Import upstream version 3.99.11
404
 *
405
 * Creates a new #GdaSet object, and populates it with the list given as argument.
406
 * The list can then be freed as it is copied. All the value holders in @holders are referenced counted
407
 * and modified, so they should not be used anymore afterwards.
408
 *
409
 * Returns: a new #GdaSet object
410
 */
411
GdaSet *
412
gda_set_new (GSList *holders)
413
{
414
	GObject *obj;
415
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
416
	obj = g_object_new (GDA_TYPE_SET, NULL);
417
	for (; holders; holders = holders->next) 
418
		gda_set_real_add_holder ((GdaSet*) obj, GDA_HOLDER (holders->data));
419
	compute_public_data ((GdaSet*) obj);
420
421
	return (GdaSet*) obj;
422
}
423
424
/**
425
 * gda_set_new_read_only:
426
 * @holders: (element-type GdaHolder) (transfer:none): a list of #GdaHolder objects
427
 *
428
 * Creates a new #GdaSet like gda_set_new(), but does not allow modifications to any of the #GdaHolder
429
 * object in @holders. This function is used for Libgda's database providers' implementation.
430
 *
431
 * Returns: a new #GdaSet object
432
 *
433
 * Since: 4.2
434
 */
435
GdaSet *
436
gda_set_new_read_only (GSList *holders)
437
{
438
	GObject *obj;
439
440
	obj = g_object_new (GDA_TYPE_SET, NULL);
441
	((GdaSet*) obj)->priv->read_only = TRUE;
442
	for (; holders; holders = holders->next) 
443
		gda_set_real_add_holder ((GdaSet*) obj, GDA_HOLDER (holders->data));
444
	compute_public_data ((GdaSet*) obj);
445
446
	return (GdaSet*) obj;
1 by Christophe Sauthier
Import upstream version 3.99.11
447
}
448
449
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
450
 * gda_set_copy:
1 by Christophe Sauthier
Import upstream version 3.99.11
451
 * @set: a #GdaSet object
452
 *
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
453
 * Creates a new #GdaSet object, copy of @set
1 by Christophe Sauthier
Import upstream version 3.99.11
454
 *
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
455
 * Returns: (transfer full): a new #GdaSet object
1 by Christophe Sauthier
Import upstream version 3.99.11
456
 */
457
GdaSet *
458
gda_set_copy (GdaSet *set)
459
{
460
	GdaSet *copy;
461
	GSList *list, *holders = NULL;
462
	g_return_val_if_fail (GDA_IS_SET (set), NULL);
463
	
464
	for (list = set->holders; list; list = list->next) 
465
		holders = g_slist_prepend (holders, gda_holder_copy (GDA_HOLDER (list->data)));
466
	holders = g_slist_reverse (holders);
467
468
	copy = g_object_new (GDA_TYPE_SET, "holders", holders, NULL);
469
	g_slist_foreach (holders, (GFunc) g_object_unref, NULL);
470
	g_slist_free (holders);
471
472
	return copy;
473
}
474
475
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
476
 * gda_set_new_inline:
1 by Christophe Sauthier
Import upstream version 3.99.11
477
 * @nb: the number of value holders which will be contained in the new #GdaSet
478
 * @...: a serie of a (const gchar*) id, (GType) type, and value
479
 *
480
 * Creates a new #GdaSet containing holders defined by each triplet in ...
481
 * For each triplet (id, Glib type and value), 
482
 * the value must be of the correct type (gchar * if type is G_STRING, ...)
483
 *
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
484
 * Note that this function is a utility function and that only a limited set of types are supported. Trying
1 by Christophe Sauthier
Import upstream version 3.99.11
485
 * to use an unsupported type will result in a warning, and the returned value holder holding a safe default
486
 * value.
487
 *
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
488
 * Returns: (transfer full): a new #GdaSet object
1 by Christophe Sauthier
Import upstream version 3.99.11
489
 */ 
490
GdaSet *
491
gda_set_new_inline (gint nb, ...)
492
{
493
	GdaSet *set = NULL;
494
	GSList *holders = NULL;
495
	va_list ap;
496
	gchar *id;
497
	gint i;
498
	gboolean allok = TRUE;
499
500
	/* build the list of holders */
501
	va_start (ap, nb);
502
	for (i = 0; i < nb; i++) {
503
		GType type;
504
		GdaHolder *holder;
505
		GValue *value;
506
		GError *lerror = NULL;
507
508
		id = va_arg (ap, char *);
509
		type = va_arg (ap, GType);
510
		holder = (GdaHolder *) g_object_new (GDA_TYPE_HOLDER, "g-type", type, "id", id, NULL);
511
512
		value = gda_value_new (type);
513
		if (type == G_TYPE_BOOLEAN) 
514
			g_value_set_boolean (value, va_arg (ap, int));
515
                else if (type == G_TYPE_STRING)
516
			g_value_set_string (value, va_arg (ap, gchar *));
517
                else if (type == G_TYPE_OBJECT)
518
			g_value_set_object (value, va_arg (ap, gpointer));
519
		else if (type == G_TYPE_INT)
520
			g_value_set_int (value, va_arg (ap, gint));
521
		else if (type == G_TYPE_UINT)
522
			g_value_set_uint (value, va_arg (ap, guint));
523
		else if (type == GDA_TYPE_BINARY)
524
			gda_value_set_binary (value, va_arg (ap, GdaBinary *));
525
		else if (type == G_TYPE_INT64)
526
			g_value_set_int64 (value, va_arg (ap, gint64));
527
		else if (type == G_TYPE_UINT64)
528
			g_value_set_uint64 (value, va_arg (ap, guint64));
529
		else if (type == GDA_TYPE_SHORT)
530
			gda_value_set_short (value, va_arg (ap, int));
531
		else if (type == GDA_TYPE_USHORT)
532
			gda_value_set_ushort (value, va_arg (ap, guint));
533
		else if (type == G_TYPE_CHAR)
534
			g_value_set_char (value, va_arg (ap, int));
535
		else if (type == G_TYPE_UCHAR)
536
			g_value_set_uchar (value, va_arg (ap, guint));
537
		else if (type == G_TYPE_FLOAT)
538
			g_value_set_float (value, va_arg (ap, double));
539
		else if (type == G_TYPE_DOUBLE)
540
			g_value_set_double (value, va_arg (ap, gdouble));
541
		else if (type == GDA_TYPE_NUMERIC)
542
			gda_value_set_numeric (value, va_arg (ap, GdaNumeric *));
543
		else if (type == G_TYPE_DATE)
544
			g_value_set_boxed (value, va_arg (ap, GDate *));
545
		else if (type == G_TYPE_LONG)
546
			g_value_set_long (value, va_arg (ap, glong));
547
		else if (type == G_TYPE_ULONG)
548
			g_value_set_ulong (value, va_arg (ap, gulong));
549
		else if (type == G_TYPE_GTYPE)
550
			g_value_set_gtype (value, va_arg(ap, GType));
551
		else {
552
			g_warning (_("%s() does not handle values of type '%s'."),
553
				   __FUNCTION__, g_type_name (type));
554
			g_object_unref (holder);
555
			allok = FALSE;
556
			break;
557
		}
558
559
		if (!gda_holder_take_value (holder, value, &lerror)) {
560
			g_warning (_("Unable to set holder's value: %s"),
561
				   lerror && lerror->message ? lerror->message : _("No detail"));
562
			if (lerror)
563
				g_error_free (lerror);
564
			g_object_unref (holder);
565
			allok = FALSE;
566
			break;
567
		}
568
		holders = g_slist_append (holders, holder);
569
        }
570
	va_end (ap);
571
572
	/* create the set */
573
	if (allok) 
574
		set = gda_set_new (holders);
575
	if (holders) {
576
		g_slist_foreach (holders, (GFunc) g_object_unref, NULL);
577
		g_slist_free (holders);
578
	}
579
	return set;
580
}
581
582
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
583
 * gda_set_set_holder_value:
1 by Christophe Sauthier
Import upstream version 3.99.11
584
 * @set: a #GdaSet object
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
585
 * @error: (allow-none): a place to store errors, or %NULL
1 by Christophe Sauthier
Import upstream version 3.99.11
586
 * @holder_id: the ID of the holder to set the value
587
 * @...: value, of the correct type, depending on the requested holder's type (not NULL)
588
 *
589
 * Set the value of the #GdaHolder which ID is @holder_id to a specified value
590
 *
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
591
 * Returns: %TRUE if no error occurred and the value was set correctly
1 by Christophe Sauthier
Import upstream version 3.99.11
592
 */
593
gboolean
594
gda_set_set_holder_value (GdaSet *set, GError **error, const gchar *holder_id, ...)
595
{
596
	GdaHolder *holder;
597
	va_list ap;
598
	GValue *value;
599
	GType type;
600
601
	g_return_val_if_fail (GDA_IS_SET (set), FALSE);
602
	g_return_val_if_fail (set->priv, FALSE);
603
604
	holder = gda_set_get_holder (set, holder_id);
605
	if (!holder) {
606
		g_set_error (error, GDA_SET_ERROR, GDA_SET_HOLDER_NOT_FOUND_ERROR,
607
			     _("GdaHolder with ID '%s' not found in set"), holder_id);
608
		return FALSE;
609
	}
610
	type = gda_holder_get_g_type (holder);
611
	va_start (ap, holder_id);
612
	value = gda_value_new (type);
613
	if (type == G_TYPE_BOOLEAN) 
614
		g_value_set_boolean (value, va_arg (ap, int));
615
	else if (type == G_TYPE_STRING)
616
		g_value_set_string (value, va_arg (ap, gchar *));
617
	else if (type == G_TYPE_OBJECT)
618
		g_value_set_object (value, va_arg (ap, gpointer));
619
	else if (type == G_TYPE_INT)
620
		g_value_set_int (value, va_arg (ap, gint));
621
	else if (type == G_TYPE_UINT)
622
		g_value_set_uint (value, va_arg (ap, guint));
623
	else if (type == GDA_TYPE_BINARY)
624
		gda_value_set_binary (value, va_arg (ap, GdaBinary *));
625
	else if (type == G_TYPE_INT64)
626
		g_value_set_int64 (value, va_arg (ap, gint64));
627
	else if (type == G_TYPE_UINT64)
628
		g_value_set_uint64 (value, va_arg (ap, guint64));
629
	else if (type == GDA_TYPE_SHORT)
630
		gda_value_set_short (value, va_arg (ap, int));
631
	else if (type == GDA_TYPE_USHORT)
632
		gda_value_set_ushort (value, va_arg (ap, guint));
633
	else if (type == G_TYPE_CHAR)
634
		g_value_set_char (value, va_arg (ap, int));
635
	else if (type == G_TYPE_UCHAR)
636
		g_value_set_uchar (value, va_arg (ap, guint));
637
	else if (type == G_TYPE_FLOAT)
638
		g_value_set_float (value, va_arg (ap, double));
639
	else if (type == G_TYPE_DOUBLE)
640
		g_value_set_double (value, va_arg (ap, gdouble));
641
	else if (type == GDA_TYPE_NUMERIC)
642
		gda_value_set_numeric (value, va_arg (ap, GdaNumeric *));
643
	else if (type == G_TYPE_DATE)
644
		g_value_set_boxed (value, va_arg (ap, GDate *));
645
	else if (type == G_TYPE_LONG)
646
		g_value_set_long (value, va_arg (ap, glong));
647
	else if (type == G_TYPE_ULONG)
648
		g_value_set_ulong (value, va_arg (ap, gulong));
649
	else if (type == G_TYPE_GTYPE)
650
		g_value_set_gtype (value, va_arg (ap, GType));	
651
	else {
652
		g_set_error (error, 0, 0,
653
			     _("%s() does not handle values of type '%s'."),
654
			     __FUNCTION__, g_type_name (type));
655
		va_end (ap);
656
		return FALSE;
657
	}
658
659
	va_end (ap);
660
	return gda_holder_take_value (holder, value, error);
661
}
662
663
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
664
 * gda_set_get_holder_value:
1 by Christophe Sauthier
Import upstream version 3.99.11
665
 * @set: a #GdaSet object
666
 * @holder_id: the ID of the holder to set the value
667
 *
668
 * Get the value of the #GdaHolder which ID is @holder_id
669
 *
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
670
 * Returns: (transfer none): the requested GValue, or %NULL (see gda_holder_get_value())
1 by Christophe Sauthier
Import upstream version 3.99.11
671
 */
672
const GValue *
673
gda_set_get_holder_value (GdaSet *set, const gchar *holder_id)
674
{
675
	GdaHolder *holder;
676
677
	g_return_val_if_fail (GDA_IS_SET (set), FALSE);
678
	g_return_val_if_fail (set->priv, FALSE);
679
680
	holder = gda_set_get_holder (set, holder_id);
681
	if (holder) 
682
		return gda_holder_get_value (holder);
683
	else
684
		return NULL;
685
}
686
687
static void
688
xml_validity_error_func (void *ctx, const char *msg, ...)
689
{
690
        va_list args;
691
        gchar *str, *str2, *newerr;
692
693
        va_start (args, msg);
694
        str = g_strdup_vprintf (msg, args);
695
        va_end (args);
696
697
	str2 = *((gchar **) ctx);
698
699
        if (str2) {
700
                newerr = g_strdup_printf ("%s\n%s", str2, str);
701
                g_free (str2);
702
        }
703
        else
704
                newerr = g_strdup (str);
705
        g_free (str);
706
707
	*((gchar **) ctx) = newerr;
708
}
709
710
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
711
 * gda_set_new_from_spec_string:
1 by Christophe Sauthier
Import upstream version 3.99.11
712
 * @xml_spec: a string
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
713
 * @error: (allow-none): a place to store the error, or %NULL
1 by Christophe Sauthier
Import upstream version 3.99.11
714
 *
715
 * Creates a new #GdaSet object from the @xml_spec
716
 * specifications
717
 *
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
718
 * Returns: (transfer full): a new object, or %NULL if an error occurred
1 by Christophe Sauthier
Import upstream version 3.99.11
719
 */
720
GdaSet *
721
gda_set_new_from_spec_string (const gchar *xml_spec, GError **error)
722
{
723
	xmlDocPtr doc;
724
	xmlNodePtr root;
725
	GdaSet *set;
726
727
	/* string parsing */
728
	doc = xmlParseMemory (xml_spec, strlen (xml_spec));
729
	if (!doc)
730
		return NULL;
731
732
	{
733
                /* doc validation */
734
                xmlValidCtxtPtr validc;
735
                int xmlcheck;
736
		gchar *err_str = NULL;
737
		xmlDtdPtr old_dtd = NULL;
738
739
                validc = g_new0 (xmlValidCtxt, 1);
740
                validc->userData = &err_str;
741
                validc->error = xml_validity_error_func;
742
                validc->warning = NULL;
743
744
                xmlcheck = xmlDoValidityCheckingDefaultValue;
745
                xmlDoValidityCheckingDefaultValue = 1;
746
747
                /* replace the DTD with ours */
748
		if (gda_paramlist_dtd) {
749
			old_dtd = doc->intSubset;
750
			doc->intSubset = gda_paramlist_dtd;
751
		}
752
753
#ifndef G_OS_WIN32
754
                if (doc->intSubset && !xmlValidateDocument (validc, doc)) {
755
			if (gda_paramlist_dtd)
756
				doc->intSubset = old_dtd;
757
                        xmlFreeDoc (doc);
758
                        g_free (validc);
759
			
760
                        if (err_str) {
761
                                g_set_error (error,
762
                                             GDA_SET_ERROR,
763
                                             GDA_SET_XML_SPEC_ERROR,
764
                                             "XML spec. does not conform to DTD:\n%s", err_str);
765
                                g_free (err_str);
766
                        }
767
                        else
768
                                g_set_error (error,
769
                                             GDA_SET_ERROR,
770
                                             GDA_SET_XML_SPEC_ERROR,
771
                                             "%s", "XML spec. does not conform to DTD");
772
773
                        xmlDoValidityCheckingDefaultValue = xmlcheck;
774
                        return NULL;
775
                }
776
#endif
777
		if (gda_paramlist_dtd)
778
			doc->intSubset = old_dtd;
779
                xmlDoValidityCheckingDefaultValue = xmlcheck;
780
                g_free (validc);
781
        }
782
783
	/* doc is now non NULL */
784
	root = xmlDocGetRootElement (doc);
785
	if (strcmp ((gchar*)root->name, "data-set-spec") != 0){
786
		g_set_error (error, GDA_SET_ERROR, GDA_SET_XML_SPEC_ERROR,
787
			     _("Spec's root node != 'data-set-spec': '%s'"), root->name);
788
		return NULL;
789
	}
790
791
	/* creating holders */
792
	root = root->xmlChildrenNode;
793
	while (xmlNodeIsText (root)) 
794
		root = root->next; 
795
796
	set = gda_set_new_from_spec_node (root, error);
797
	xmlFreeDoc(doc);
798
	return set;
799
}
800
801
802
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
803
 * gda_set_new_from_spec_node:
1 by Christophe Sauthier
Import upstream version 3.99.11
804
 * @xml_spec: a #xmlNodePtr for a &lt;holders&gt; tag
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
805
 * @error: (allow-none): a place to store the error, or %NULL
1 by Christophe Sauthier
Import upstream version 3.99.11
806
 *
807
 * Creates a new #GdaSet object from the @xml_spec
808
 * specifications
809
 *
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
810
 * Returns: (transfer full): a new object, or %NULL if an error occurred
1 by Christophe Sauthier
Import upstream version 3.99.11
811
 */
812
GdaSet *
813
gda_set_new_from_spec_node (xmlNodePtr xml_spec, GError **error)
814
{
815
	GdaSet *set = NULL;
816
	GSList *holders = NULL, *sources = NULL;
817
	GSList *list;
818
	const gchar *lang = gda_lang_locale;
819
820
	xmlNodePtr cur;
821
	gboolean allok = TRUE;
822
	gchar *str;
823
824
	if (strcmp ((gchar*)xml_spec->name, "parameters") != 0){
825
		g_set_error (error, GDA_SET_ERROR, GDA_SET_XML_SPEC_ERROR,
826
			     _("Missing node <parameters>: '%s'"), xml_spec->name);
827
		return NULL;
828
	}
829
830
	/* Holders' sources, not mandatory: makes the @sources list */
831
	cur = xml_spec->next;
832
	while (cur && (xmlNodeIsText (cur) || strcmp ((gchar*)cur->name, "sources"))) 
833
		cur = cur->next; 
834
	if (allok && cur && !strcmp ((gchar*)cur->name, "sources")){
835
		for (cur = cur->xmlChildrenNode; (cur != NULL) && allok; cur = cur->next) {
836
			if (xmlNodeIsText (cur)) 
837
				continue;
838
839
			if (!strcmp ((gchar*)cur->name, "gda_array")) {
840
				GdaDataModel *model;
841
				GSList *errors;
842
843
				model = gda_data_model_import_new_xml_node (cur);
844
				errors = gda_data_model_import_get_errors (GDA_DATA_MODEL_IMPORT (model));
845
				if (errors) {
846
					GError *err = (GError *) errors->data;
847
					g_set_error (error, 0, 0, "%s", err->message);
848
					g_object_unref (model);
849
					model = NULL;
850
					allok = FALSE;
851
				}
852
				else  {
853
					sources = g_slist_prepend (sources, model);
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
854
					str = (gchar*)xmlGetProp(cur, (xmlChar*) "name");
1 by Christophe Sauthier
Import upstream version 3.99.11
855
					if (str) 
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
856
						g_object_set_data_full (G_OBJECT (model), "name", str, xmlFree);
1 by Christophe Sauthier
Import upstream version 3.99.11
857
				}
858
			}
859
		}
860
	}	
861
862
	/* holders */
863
	for (cur = xml_spec->xmlChildrenNode; cur && allok; cur = cur->next) {
864
		if (xmlNodeIsText (cur)) 
865
			continue;
866
867
		if (!strcmp ((gchar*)cur->name, "parameter")) {
868
			GdaHolder *holder = NULL;
869
			gchar *str, *id;
870
			xmlChar *this_lang;
871
			xmlChar *gdatype;
872
873
			/* don't care about entries for the wrong locale */
874
			this_lang = xmlGetProp(cur, (xmlChar*)"lang");
875
			if (this_lang && strncmp ((gchar*)this_lang, lang, strlen ((gchar*)this_lang))) {
876
				g_free (this_lang);
877
				continue;
878
			}
879
880
			/* find if there is already a holder with the same ID */
881
			id = (gchar*)xmlGetProp(cur, (xmlChar*)"id");
882
			for (list = holders; list && !holder; list = list->next) {
883
				str = (gchar *) gda_holder_get_id ((GdaHolder *) list->data);
884
				if (str && id && !strcmp (str, id))
885
					holder = (GdaHolder *) list->data;
886
			}
887
			if (id) 
888
				xmlFree (id);
889
890
			if (holder && !this_lang) {
891
				xmlFree (this_lang);
892
				continue;
893
			}
894
			g_free (this_lang);
895
			
896
897
			/* find data type and create GdaHolder */
898
			gdatype = xmlGetProp (cur, BAD_CAST "gdatype");
899
900
			if (!holder) {
901
				holder = (GdaHolder*) (g_object_new (GDA_TYPE_HOLDER,
902
								     "g-type", 
903
								     gdatype ? gda_g_type_from_string ((gchar *) gdatype) : G_TYPE_STRING,
904
								     NULL));
905
				holders = g_slist_append (holders, holder);
906
			}
907
			if (gdatype)
908
				xmlFree (gdatype);
909
			
910
			/* set holder's attributes */
911
			if (! gda_utility_holder_load_attributes (holder, cur, sources, error))
912
				allok = FALSE;
913
		}
914
	}
915
916
	/* setting prepared new names from sources (models) */
917
	for (list = sources; list; list = list->next) {
918
		str = g_object_get_data (G_OBJECT (list->data), "newname");
919
		if (str) {
920
			g_object_set_data_full (G_OBJECT (list->data), "name", g_strdup (str), g_free);
921
			g_object_set_data (G_OBJECT (list->data), "newname", NULL);
922
		}
923
		str = g_object_get_data (G_OBJECT (list->data), "newdescr");
924
		if (str) {
925
			g_object_set_data_full (G_OBJECT (list->data), "descr", g_strdup (str), g_free);
926
			g_object_set_data (G_OBJECT (list->data), "newdescr", NULL);
927
		}
928
	}
929
930
	/* holders' values, constraints: TODO */
931
	
932
	/* GdaSet creation */
933
	if (allok) {
934
		xmlChar *prop;;
935
		set = gda_set_new (holders);
936
937
		prop = xmlGetProp(xml_spec, (xmlChar*)"id");
938
		if (prop) {
939
			set->priv->id = g_strdup ((gchar*)prop);
940
			xmlFree (prop);
941
		}
942
		prop = xmlGetProp(xml_spec, (xmlChar*)"name");
943
		if (prop) {
944
			set->priv->name = g_strdup ((gchar*)prop);
945
			xmlFree (prop);
946
		}
947
		prop = xmlGetProp(xml_spec, (xmlChar*)"descr");
948
		if (prop) {
949
			set->priv->descr = g_strdup ((gchar*)prop);
950
			xmlFree (prop);
951
		}
952
	}
953
954
	g_slist_foreach (holders, (GFunc) g_object_unref, NULL);
955
	g_slist_free (holders);
956
	g_slist_foreach (sources, (GFunc) g_object_unref, NULL);
957
	g_slist_free (sources);
958
959
	return set;
960
}
961
962
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
963
 * gda_set_remove_holder:
964
 * @set: a #GdaSet object
965
 * @holder: the #GdaHolder to remove from @set
966
 *
967
 * Removes a #GdaHolder from the list of holders managed by @set
1 by Christophe Sauthier
Import upstream version 3.99.11
968
 */
969
void
970
gda_set_remove_holder (GdaSet *set, GdaHolder *holder)
971
{
972
	GdaSetNode *node;
973
974
	g_return_if_fail (GDA_IS_SET (set));
975
	g_return_if_fail (set->priv);
976
	g_return_if_fail (g_slist_find (set->holders, holder));
977
978
	g_signal_handlers_disconnect_by_func (G_OBJECT (holder),
979
					      G_CALLBACK (validate_change_holder_cb), set);
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
980
	if (! set->priv->read_only) {
981
		g_signal_handlers_disconnect_by_func (G_OBJECT (holder),
982
						      G_CALLBACK (changed_holder_cb), set);
983
		g_signal_handlers_disconnect_by_func (G_OBJECT (holder),
984
						      G_CALLBACK (source_changed_holder_cb), set);
985
		g_signal_handlers_disconnect_by_func (G_OBJECT (holder),
986
						      G_CALLBACK (att_holder_changed_cb), set);
987
	}
988
	g_signal_handlers_disconnect_by_func (holder,
989
					      G_CALLBACK (holder_notify_cb), set);
1 by Christophe Sauthier
Import upstream version 3.99.11
990
991
	/* now destroy the GdaSetNode and the GdaSetSource if necessary */
992
	node = gda_set_get_node (set, holder);
993
	g_assert (node);
994
	if (node->source_model) {
995
		GdaSetSource *source;
996
997
		source = gda_set_get_source_for_model (set, node->source_model);
998
		g_assert (source);
999
		g_assert (source->nodes);
1000
		if (! source->nodes->next)
1001
			set_remove_source (set, source);
1002
	}
1003
	set_remove_node (set, node);
1004
1005
	set->holders = g_slist_remove (set->holders, holder);
1006
	g_hash_table_remove (set->priv->holders_hash, gda_holder_get_id (holder));
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1007
	if (set->priv->holders_array) {
1008
		g_array_free (set->priv->holders_array, TRUE);
1009
		set->priv->holders_array = NULL;
1010
	}
1 by Christophe Sauthier
Import upstream version 3.99.11
1011
	g_object_unref (G_OBJECT (holder));
1012
}
1013
1014
static void
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1015
source_changed_holder_cb (G_GNUC_UNUSED GdaHolder *holder, GdaSet *set)
1 by Christophe Sauthier
Import upstream version 3.99.11
1016
{
1017
	compute_public_data (set);
1018
}
1019
1020
static void
1021
att_holder_changed_cb (GdaHolder *holder, const gchar *att_name, const GValue *att_value, GdaSet *set)
1022
{
1023
#ifdef GDA_DEBUG_signal
1024
	g_print (">> 'HOLDER_ATTR_CHANGED' from %s\n", __FUNCTION__);
1025
#endif
1026
	g_signal_emit (G_OBJECT (set), gda_set_signals[HOLDER_ATTR_CHANGED], 0, holder, att_name, att_value);
1027
#ifdef GDA_DEBUG_signal
1028
	g_print ("<< 'HOLDER_ATTR_CHANGED' from %s\n", __FUNCTION__);
1029
#endif
1030
}
1031
1032
static GError *
1033
validate_change_holder_cb (GdaHolder *holder, const GValue *value, GdaSet *set)
1034
{
1035
	/* signal the holder validate-change */
1036
	GError *error = NULL;
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1037
	if (set->priv->read_only)
1038
		g_set_error (&error, GDA_SET_ERROR, GDA_SET_READ_ONLY_ERROR, _("Data set does not allow modifications"));
1039
	else {
1040
#ifdef GDA_DEBUG_signal
1041
		g_print (">> 'VALIDATE_HOLDER_CHANGE' from %s\n", __FUNCTION__);
1042
#endif
1043
		g_signal_emit (G_OBJECT (set), gda_set_signals[VALIDATE_HOLDER_CHANGE], 0, holder, value, &error);
1044
#ifdef GDA_DEBUG_signal
1045
		g_print ("<< 'VALIDATE_HOLDER_CHANGED' from %s\n", __FUNCTION__);
1046
#endif
1047
	}
1 by Christophe Sauthier
Import upstream version 3.99.11
1048
	return error;
1049
}
1050
1051
static void
1052
changed_holder_cb (GdaHolder *holder, GdaSet *set)
1053
{
1054
	/* signal the holder change */
1055
#ifdef GDA_DEBUG_signal
1056
	g_print (">> 'HOLDER_CHANGED' from %s\n", __FUNCTION__);
1057
#endif
1058
	g_signal_emit (G_OBJECT (set), gda_set_signals[HOLDER_CHANGED], 0, holder);
1059
#ifdef GDA_DEBUG_signal
1060
	g_print ("<< 'HOLDER_CHANGED' from %s\n", __FUNCTION__);
1061
#endif
1062
}
1063
1064
static void
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1065
group_free (GdaSetGroup *group, G_GNUC_UNUSED gpointer data)
1 by Christophe Sauthier
Import upstream version 3.99.11
1066
{
1067
	g_slist_free (group->nodes);
1068
	g_free (group);
1069
}
1070
1071
static void
1072
gda_set_dispose (GObject *object)
1073
{
1074
	GdaSet *set;
1075
	GSList *list;
1076
1077
	g_return_if_fail (object != NULL);
1078
	g_return_if_fail (GDA_IS_SET (object));
1079
1080
	set = GDA_SET (object);
1081
	/* free the holders list */
1082
	if (set->holders) {
1083
		for (list = set->holders; list; list = list->next) {
1084
			g_signal_handlers_disconnect_by_func (G_OBJECT (list->data),
1085
							      G_CALLBACK (validate_change_holder_cb), set);
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1086
			if (! set->priv->read_only) {
1087
				g_signal_handlers_disconnect_by_func (G_OBJECT (list->data),
1088
								      G_CALLBACK (changed_holder_cb), set);
1089
				g_signal_handlers_disconnect_by_func (G_OBJECT (list->data),
1090
								      G_CALLBACK (source_changed_holder_cb), set);
1091
				g_signal_handlers_disconnect_by_func (G_OBJECT (list->data),
1092
								      G_CALLBACK (att_holder_changed_cb), set);
1093
			}
1094
			g_object_unref (list->data);
1 by Christophe Sauthier
Import upstream version 3.99.11
1095
		}
1096
		g_slist_free (set->holders);
1097
	}
1098
	if (set->priv->holders_hash) {
1099
		g_hash_table_destroy (set->priv->holders_hash);
1100
		set->priv->holders_hash = NULL;
1101
	}
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1102
	if (set->priv->holders_array) {
1103
		g_array_free (set->priv->holders_array, TRUE);
1104
		set->priv->holders_array = NULL;
1105
	}
1 by Christophe Sauthier
Import upstream version 3.99.11
1106
1107
	/* free the nodes if there are some */
1108
	while (set->nodes_list)
1109
		set_remove_node (set, GDA_SET_NODE (set->nodes_list->data));
1110
	while (set->sources_list)
1111
		set_remove_source (set, GDA_SET_SOURCE (set->sources_list->data));
1112
1113
	g_slist_foreach (set->groups_list, (GFunc) group_free, NULL);
1114
	g_slist_free (set->groups_list);
1115
	set->groups_list = NULL;
1116
1117
	/* parent class */
1118
	parent_class->dispose (object);
1119
}
1120
1121
static void
1122
gda_set_finalize (GObject *object)
1123
{
1124
	GdaSet *set;
1125
1126
	g_return_if_fail (object != NULL);
1127
	g_return_if_fail (GDA_IS_SET (object));
1128
1129
	set = GDA_SET (object);
1130
	if (set->priv) {
1131
		g_free (set->priv->id);
1132
		g_free (set->priv->name);
1133
		g_free (set->priv->descr);
1134
		g_free (set->priv);
1135
		set->priv = NULL;
1136
	}
1137
1138
	/* parent class */
1139
	parent_class->finalize (object);
1140
}
1141
1142
/*
1143
 * Resets and computes set->nodes, and if some nodes already exist, they are previously discarded
1144
 */
1145
static void 
1146
compute_public_data (GdaSet *set)
1147
{
1148
	GSList *list;
1149
	GdaSetNode *node;
1150
	GdaSetSource *source;
1151
	GdaSetGroup *group;
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1152
	GHashTable *groups = NULL;
1 by Christophe Sauthier
Import upstream version 3.99.11
1153
1154
	/*
1155
	 * Get rid of all the previous structures
1156
	 */
1157
	while (set->nodes_list)
1158
		set_remove_node (set, GDA_SET_NODE (set->nodes_list->data));
1159
	while (set->sources_list)
1160
		set_remove_source (set, GDA_SET_SOURCE (set->sources_list->data));
1161
1162
	g_slist_foreach (set->groups_list, (GFunc) group_free, NULL);
1163
	g_slist_free (set->groups_list);
1164
	set->groups_list = NULL;
1165
1166
	/*
1167
	 * Creation of the GdaSetNode structures
1168
	 */
1169
	for (list = set->holders; list; list = list->next) {
1170
		node = g_new0 (GdaSetNode, 1);
1171
		node->holder = GDA_HOLDER (list->data);
1172
		node->source_model = gda_holder_get_source_model (node->holder,
1173
								  &(node->source_column));
1174
		if (node->source_model)
1175
			g_object_ref (node->source_model);
1176
		
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1177
		set->nodes_list = g_slist_prepend (set->nodes_list, node);
1 by Christophe Sauthier
Import upstream version 3.99.11
1178
	}
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1179
	set->nodes_list = g_slist_reverse (set->nodes_list);
1 by Christophe Sauthier
Import upstream version 3.99.11
1180
1181
	/*
1182
	 * Creation of the GdaSetSource and GdaSetGroup structures 
1183
	 */
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1184
	for (list = set->nodes_list; list;list = list->next) {
1 by Christophe Sauthier
Import upstream version 3.99.11
1185
		node = GDA_SET_NODE (list->data);
1186
		
1187
		/* source */
1188
		source = NULL;
1189
		if (node->source_model) {
1190
			source = gda_set_get_source_for_model (set, node->source_model);
1191
			if (source) 
1.1.6 by Josselin Mouette
Import upstream version 4.0.12
1192
				source->nodes = g_slist_append (source->nodes, node);
1 by Christophe Sauthier
Import upstream version 3.99.11
1193
			else {
1194
				source = g_new0 (GdaSetSource, 1);
1195
				source->data_model = node->source_model;
1.1.6 by Josselin Mouette
Import upstream version 4.0.12
1196
				source->nodes = g_slist_append (NULL, node);
1 by Christophe Sauthier
Import upstream version 3.99.11
1197
				set->sources_list = g_slist_prepend (set->sources_list, source);
1198
			}
1199
		}
1200
1201
		/* group */
1202
		group = NULL;
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1203
		if (node->source_model && groups)
1 by Christophe Sauthier
Import upstream version 3.99.11
1204
			group = g_hash_table_lookup (groups, node->source_model);
1205
		if (group) 
1206
			group->nodes = g_slist_append (group->nodes, node);
1207
		else {
1208
			group = g_new0 (GdaSetGroup, 1);
1209
			group->nodes = g_slist_append (NULL, node);
1210
			group->nodes_source = source;
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1211
			set->groups_list = g_slist_prepend (set->groups_list, group);
1212
			if (node->source_model) {
1213
				if (!groups)
1214
					groups = g_hash_table_new (NULL, NULL); /* key = source model, 
1215
										   value = GdaSetGroup */
1 by Christophe Sauthier
Import upstream version 3.99.11
1216
				g_hash_table_insert (groups, node->source_model, group);
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1217
			}
1 by Christophe Sauthier
Import upstream version 3.99.11
1218
		}		
1219
	}
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1220
	set->groups_list = g_slist_reverse (set->groups_list);
1221
	if (groups)
1222
		g_hash_table_destroy (groups);
1 by Christophe Sauthier
Import upstream version 3.99.11
1223
1224
#ifdef GDA_DEBUG_signal
1225
        g_print (">> 'PUBLIC_DATA_CHANGED' from %p\n", set);
1226
#endif
1227
	g_signal_emit (set, gda_set_signals[PUBLIC_DATA_CHANGED], 0);
1228
#ifdef GDA_DEBUG_signal
1229
        g_print ("<< 'PUBLIC_DATA_CHANGED' from %p\n", set);
1230
#endif
1231
}
1232
1233
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1234
 * gda_set_add_holder:
1 by Christophe Sauthier
Import upstream version 3.99.11
1235
 * @set: a #GdaSet object
1236
 * @holder: a #GdaHolder object
1237
 *
1238
 * Adds @holder to the list of holders managed within @set.
1239
 *
1240
 * NOTE: if @set already has a #GdaHolder with the same ID as @holder, then @holder
1241
 * will not be added to the set (even if @holder's type or value is not the same as the
1242
 * one already in @set).
1243
 *
1244
 * Returns: TRUE if @holder has been added to @set (and FALSE if it has not been added because there is another #GdaHolder
1245
 * with the same ID)
1246
 */
1247
gboolean
1248
gda_set_add_holder (GdaSet *set, GdaHolder *holder)
1249
{
1250
	gboolean added;
1251
	g_return_val_if_fail (GDA_IS_SET (set), FALSE);
1252
	g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE);
1253
1254
	added = gda_set_real_add_holder (set, holder);
1255
	if (added)
1256
		compute_public_data (set);
1257
	return added;
1258
}
1259
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1260
static void
1261
holder_notify_cb (GdaHolder *holder, GParamSpec *pspec, GdaSet *dataset)
1262
{
1263
	GType gtype;
1264
	gtype = gda_holder_get_g_type (holder);
1265
	if (!strcmp (pspec->name, "g-type")) {
1266
		g_assert (gtype != GDA_TYPE_NULL);
1267
		g_signal_emit (dataset, gda_set_signals[HOLDER_TYPE_SET], 0, holder);
1268
	}
1269
	else if (!strcmp (pspec->name, "name")) {
1270
#ifdef GDA_DEBUG_signal
1271
	g_print (">> 'HOLDER_ATTR_CHANGED' from %s\n", __FUNCTION__);
1272
#endif
1273
	g_signal_emit (G_OBJECT (dataset), gda_set_signals[HOLDER_ATTR_CHANGED], 0, holder,
1274
		       GDA_ATTRIBUTE_NAME, gda_holder_get_attribute (holder, GDA_ATTRIBUTE_NAME));
1275
#ifdef GDA_DEBUG_signal
1276
	g_print ("<< 'HOLDER_ATTR_CHANGED' from %s\n", __FUNCTION__);
1277
#endif
1278
	}
1279
	else if (!strcmp (pspec->name, "description")) {
1280
#ifdef GDA_DEBUG_signal
1281
	g_print (">> 'HOLDER_ATTR_CHANGED' from %s\n", __FUNCTION__);
1282
#endif
1283
	g_signal_emit (G_OBJECT (dataset), gda_set_signals[HOLDER_ATTR_CHANGED], 0, holder,
1284
		       GDA_ATTRIBUTE_DESCRIPTION, gda_holder_get_attribute (holder, GDA_ATTRIBUTE_DESCRIPTION));
1285
#ifdef GDA_DEBUG_signal
1286
	g_print ("<< 'HOLDER_ATTR_CHANGED' from %s\n", __FUNCTION__);
1287
#endif
1288
	}
1289
}
1290
1 by Christophe Sauthier
Import upstream version 3.99.11
1291
static gboolean
1292
gda_set_real_add_holder (GdaSet *set, GdaHolder *holder)
1293
{
1294
	GdaHolder *similar;
1295
	const gchar *hid;
1296
1297
	/* 
1298
	 * try to find a similar holder in the set->holders:
1299
	 * a holder B is similar to a holder A if it has the same ID
1300
	 */
1301
	hid = gda_holder_get_id (holder);
1302
	if (!hid) {
1303
		g_warning (_("GdaHolder needs to have an ID"));
1304
		return FALSE;
1305
	}
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1306
1 by Christophe Sauthier
Import upstream version 3.99.11
1307
	similar = (GdaHolder*) g_hash_table_lookup (set->priv->holders_hash, hid);
1308
	if (!similar) {
1309
		/* really add @holder to the set */
1310
		set->holders = g_slist_append (set->holders, holder);
1311
		g_hash_table_insert (set->priv->holders_hash, (gchar*) hid, holder);
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1312
		if (set->priv->holders_array) {
1313
			g_array_free (set->priv->holders_array, TRUE);
1314
			set->priv->holders_array = NULL;
1315
		}
1 by Christophe Sauthier
Import upstream version 3.99.11
1316
		g_object_ref (holder);
1317
		g_signal_connect (G_OBJECT (holder), "validate-change",
1318
				  G_CALLBACK (validate_change_holder_cb), set);
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1319
		if (! set->priv->read_only) {
1320
			g_signal_connect (G_OBJECT (holder), "changed",
1321
					  G_CALLBACK (changed_holder_cb), set);
1322
			g_signal_connect (G_OBJECT (holder), "source-changed",
1323
					  G_CALLBACK (source_changed_holder_cb), set);
1324
			g_signal_connect (G_OBJECT (holder), "attribute-changed",
1325
					  G_CALLBACK (att_holder_changed_cb), set);
1326
		}
1327
		if (gda_holder_get_g_type (holder) == GDA_TYPE_NULL)
1328
			g_signal_connect (G_OBJECT (holder), "notify::g-type",
1329
					  G_CALLBACK (holder_notify_cb), set);
1330
		g_signal_connect (G_OBJECT (holder), "notify::name",
1331
				  G_CALLBACK (holder_notify_cb), set);
1332
		g_signal_connect (G_OBJECT (holder), "notify::description",
1333
				  G_CALLBACK (holder_notify_cb), set);
1 by Christophe Sauthier
Import upstream version 3.99.11
1334
		return TRUE;
1335
	}
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1336
	else if (similar == holder)
1337
		return FALSE;
1 by Christophe Sauthier
Import upstream version 3.99.11
1338
	else {
1339
#ifdef GDA_DEBUG_NO
1340
		g_print ("In Set %p, Holder %p and %p are similar, keeping %p only\n", set, similar, holder, similar);
1341
#endif
1342
		return FALSE;
1343
	}
1344
}
1345
1346
1347
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1348
 * gda_set_merge_with_set:
1 by Christophe Sauthier
Import upstream version 3.99.11
1349
 * @set: a #GdaSet object
1350
 * @set_to_merge: a #GdaSet object
1351
 *
1352
 * Add to @set all the holders of @set_to_merge. 
1353
 * Note1: only the #GdaHolder of @set_to_merge for which no holder in @set has the same ID are merged
1354
 * Note2: all the #GdaHolder merged in @set are still used by @set_to_merge.
1355
 */
1356
void
1357
gda_set_merge_with_set (GdaSet *set, GdaSet *set_to_merge)
1358
{
1359
	GSList *holders;
1360
	g_return_if_fail (GDA_IS_SET (set));
1361
	g_return_if_fail (set_to_merge && GDA_IS_SET (set_to_merge));
1362
1363
	for (holders = set_to_merge->holders; holders; holders = holders->next)
1364
		gda_set_real_add_holder (set, GDA_HOLDER (holders->data));
1365
	compute_public_data (set);
1366
}
1367
1368
static void
1369
set_remove_node (GdaSet *set, GdaSetNode *node)
1370
{
1371
	g_return_if_fail (g_slist_find (set->nodes_list, node));
1372
1373
	if (node->source_model)
1374
		g_object_unref (G_OBJECT (node->source_model));
1375
1376
	set->nodes_list = g_slist_remove (set->nodes_list, node);
1377
	g_free (node);
1378
}
1379
1380
static void
1381
set_remove_source (GdaSet *set, GdaSetSource *source)
1382
{
1383
	g_return_if_fail (g_slist_find (set->sources_list, source));
1384
1385
	if (source->nodes)
1386
		g_slist_free (source->nodes);
1387
1388
	set->sources_list = g_slist_remove (set->sources_list, source);
1389
	g_free (source);
1390
}
1391
1392
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1393
 * gda_set_is_valid:
1 by Christophe Sauthier
Import upstream version 3.99.11
1394
 * @set: a #GdaSet object
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1395
 * @error: (allow-none): a place to store validation errors, or %NULL
1 by Christophe Sauthier
Import upstream version 3.99.11
1396
 *
1397
 * This method tells if all @set's #GdaHolder objects are valid, and if
1398
 * they represent a valid combination of values, as defined by rules
1399
 * external to Libgda: the "validate-set" signal is emitted and if none of the signal handlers return an
1400
 * error, then the returned value is TRUE, otherwise the return value is FALSE as soon as a signal handler
1401
 * returns an error.
1402
 *
1403
 * Returns: TRUE if the set is valid
1404
 */
1405
gboolean
1406
gda_set_is_valid (GdaSet *set, GError **error)
1407
{
1408
	GSList *holders;
1409
1410
	g_return_val_if_fail (GDA_IS_SET (set), FALSE);
1411
	g_return_val_if_fail (set->priv, FALSE);
1412
1413
	for (holders = set->holders; holders; holders = holders->next) {
1414
		if (!gda_holder_is_valid ((GdaHolder*) holders->data)) {
1415
			g_set_error (error, GDA_SET_ERROR, GDA_SET_INVALID_ERROR,
1416
				     "%s", _("One or more values are invalid"));
1417
			return FALSE;
1418
		}
1419
	}
1420
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1421
	return _gda_set_validate (set, error);
1422
}
1423
1424
gboolean
1425
_gda_set_validate (GdaSet *set, GError **error)
1426
{
1 by Christophe Sauthier
Import upstream version 3.99.11
1427
	/* signal the holder validate-set */
1428
	GError *lerror = NULL;
1429
#ifdef GDA_DEBUG_signal
1430
	g_print (">> 'VALIDATE_SET' from %s\n", __FUNCTION__);
1431
#endif
1432
	g_signal_emit (G_OBJECT (set), gda_set_signals[VALIDATE_SET], 0, &lerror);
1433
#ifdef GDA_DEBUG_signal
1434
	g_print ("<< 'VALIDATE_SET' from %s\n", __FUNCTION__);
1435
#endif
1436
	if (lerror) {
1437
		g_propagate_error (error, lerror);
1438
		return FALSE;
1439
	}
1440
	return TRUE;
1441
}
1442
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1443
1 by Christophe Sauthier
Import upstream version 3.99.11
1444
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1445
 * gda_set_get_holder:
1 by Christophe Sauthier
Import upstream version 3.99.11
1446
 * @set: a #GdaSet object
1447
 * @holder_id: the ID of the requested value holder
1448
 *
1449
 * Finds a #GdaHolder using its ID
1450
 *
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1451
 * Returns: (transfer none): the requested #GdaHolder or %NULL
1 by Christophe Sauthier
Import upstream version 3.99.11
1452
 */
1453
GdaHolder *
1454
gda_set_get_holder (GdaSet *set, const gchar *holder_id)
1455
{
1456
	g_return_val_if_fail (GDA_IS_SET (set), NULL);
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1457
	g_return_val_if_fail (holder_id, NULL);
1 by Christophe Sauthier
Import upstream version 3.99.11
1458
1459
	return (GdaHolder *) g_hash_table_lookup (set->priv->holders_hash, holder_id);
1460
}
1461
1462
/**
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1463
 * gda_set_get_nth_holder:
1464
 * @set: a #GdaSet object
1465
 * @pos: the position of the requested #GdaHolder, starting at %0
1466
 *
1467
 * Finds a #GdaHolder using its position
1468
 *
1469
 * Returns: (transfer none): the requested #GdaHolder or %NULL
1470
 *
1471
 * Since: 4.2
1472
 */
1473
GdaHolder *
1474
gda_set_get_nth_holder (GdaSet *set, gint pos)
1475
{
1476
	g_return_val_if_fail (GDA_IS_SET (set), NULL);
1477
	g_return_val_if_fail (pos >= 0, NULL);
1478
1479
	if (! set->priv->holders_array) {
1480
		GSList *list;
1481
		set->priv->holders_array = g_array_sized_new (FALSE, FALSE, sizeof (GdaHolder*),
1482
							      g_slist_length (set->holders));
1483
		for (list = set->holders; list; list = list->next)
1484
			g_array_append_val (set->priv->holders_array, list->data);
1485
	}
1486
	if ((guint)pos >= set->priv->holders_array->len)
1487
		return NULL;
1488
	else
1489
		return g_array_index (set->priv->holders_array, GdaHolder*, pos);
1490
}
1491
1492
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1493
 * gda_set_get_node:
1 by Christophe Sauthier
Import upstream version 3.99.11
1494
 * @set: a #GdaSet object
1495
 * @holder: a #GdaHolder object
1496
 *
1497
 * Finds a #GdaSetNode holding information for @holder, don't modify the returned structure
1498
 *
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1499
 * Returns: (transfer none): the requested #GdaSetNode or %NULL
1 by Christophe Sauthier
Import upstream version 3.99.11
1500
 */
1501
GdaSetNode *
1502
gda_set_get_node (GdaSet *set, GdaHolder *holder)
1503
{
1504
	GdaSetNode *retval = NULL;
1505
	GSList *list;
1506
1507
	g_return_val_if_fail (GDA_IS_SET (set), NULL);
1508
	g_return_val_if_fail (set->priv, NULL);
1509
	g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL);
1510
	g_return_val_if_fail (g_slist_find (set->holders, holder), NULL);
1511
1512
	for (list = set->nodes_list; list && !retval; list = list->next) {
1513
		if (GDA_SET_NODE (list->data)->holder == holder)
1514
			retval = GDA_SET_NODE (list->data);
1515
	}
1516
1517
	return retval;
1518
}
1519
1520
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1521
 * gda_set_get_source:
1 by Christophe Sauthier
Import upstream version 3.99.11
1522
 * @set: a #GdaSet object
1523
 * @holder: a #GdaHolder object
1524
 *
1525
 * Finds a #GdaSetSource which contains the #GdaDataModel restricting the possible values of
1526
 * @holder, don't modify the returned structure.
1527
 *
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1528
 * Returns: (transfer none): the requested #GdaSetSource or %NULL
1 by Christophe Sauthier
Import upstream version 3.99.11
1529
 */
1530
GdaSetSource *
1531
gda_set_get_source (GdaSet *set, GdaHolder *holder)
1532
{
1533
	GdaSetNode *node;
1534
	
1535
	node = gda_set_get_node (set, holder);
1536
	if (node && node->source_model)
1537
		return gda_set_get_source_for_model (set, node->source_model);
1538
	else
1539
		return NULL;
1540
}
1541
1542
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1543
 * gda_set_get_group:
1 by Christophe Sauthier
Import upstream version 3.99.11
1544
 * @set: a #GdaSet object
1545
 * @holder: a #GdaHolder object
1546
 *
1547
 * Finds a #GdaSetGroup which lists a  #GdaSetNode containing @holder,
1548
 * don't modify the returned structure.
1549
 *
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1550
 * Returns: (transfer none): the requested #GdaSetGroup or %NULL
1 by Christophe Sauthier
Import upstream version 3.99.11
1551
 */
1552
GdaSetGroup *
1553
gda_set_get_group (GdaSet *set, GdaHolder *holder)
1554
{
1555
	GdaSetGroup *retval = NULL;
1556
	GSList *list, *sublist;
1557
1558
	g_return_val_if_fail (GDA_IS_SET (set), NULL);
1559
	g_return_val_if_fail (set->priv, NULL);
1560
	g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL);
1561
	g_return_val_if_fail (g_slist_find (set->holders, holder), NULL);
1562
1563
	for (list = set->groups_list; list && !retval; list = list->next) {
1564
		sublist = GDA_SET_GROUP (list->data)->nodes;
1565
		while (sublist && !retval) {
1566
			if (GDA_SET_NODE (sublist->data)->holder == holder)
1567
				retval = GDA_SET_GROUP (list->data);
1568
			else
1569
				sublist = g_slist_next (sublist);	
1570
		}
1571
	}
1572
1573
	return retval;
1574
}
1575
1576
1577
/**
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1578
 * gda_set_get_source_for_model:
1 by Christophe Sauthier
Import upstream version 3.99.11
1579
 * @set: a #GdaSet object
1580
 * @model: a #GdaDataModel object
1581
 *
1582
 * Finds the #GdaSetSource structure used in @set for which @model is a
1.1.2 by Andreas Moog
Import upstream version 4.0.0
1583
 * the data model (the returned structure should not be modified).
1 by Christophe Sauthier
Import upstream version 3.99.11
1584
 *
1.1.5 by Emilio Pozuelo Monfort
Import upstream version 4.0.9
1585
 * Returns: (transfer none): the requested #GdaSetSource pointer or %NULL.
1 by Christophe Sauthier
Import upstream version 3.99.11
1586
 */
1587
GdaSetSource *
1588
gda_set_get_source_for_model (GdaSet *set, GdaDataModel *model)
1589
{
1590
	GdaSetSource *retval = NULL;
1591
	GSList *list;
1592
1593
	g_return_val_if_fail (GDA_IS_SET (set), NULL);
1594
	g_return_val_if_fail (set->priv, NULL);
1595
	g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL);
1596
1597
	list = set->sources_list;
1598
	while (list && !retval) {
1599
		if (GDA_SET_SOURCE (list->data)->data_model == model)
1600
			retval = GDA_SET_SOURCE (list->data);
1601
1602
		list = g_slist_next (list);
1603
	}
1604
1605
	return retval;
1606
}
1.1.7 by Emilio Pozuelo Monfort
Import upstream version 4.2.2
1607
1608
/**
1609
 * gda_set_replace_source_model
1610
 * @set: a #GdaSet object
1611
 * @source: a pointer to a #GdaSetSource in @set
1612
 * @model: a #GdaDataModel
1613
 *
1614
 * Replaces @source->data_model with @model, which must have the same
1615
 * characteristics as @source->data_model (same column types)
1616
 *
1617
 * Also for each #GdaHolder for which @source->data_model is a source model,
1618
 * this method calls gda_holder_set_source_model() with @model to replace
1619
 * the source by the new model
1620
 *
1621
 * Since: 4.2
1622
 */
1623
void
1624
gda_set_replace_source_model (GdaSet *set, GdaSetSource *source, GdaDataModel *model)
1625
{
1626
	g_return_if_fail (GDA_IS_SET (set));
1627
	g_return_if_fail (source);
1628
	g_return_if_fail (g_slist_find (set->sources_list, source));
1629
	g_return_if_fail (GDA_IS_DATA_MODEL (model));
1630
	
1631
	/* compare models */
1632
	gint ncols, i;
1633
	ncols = gda_data_model_get_n_columns (source->data_model);
1634
	if (ncols != gda_data_model_get_n_columns (model)) {
1635
		g_warning (_("Replacing data model must have the same characteristics as the "
1636
			     "data model it replaces"));
1637
		return;
1638
	}
1639
	for (i = 0; i < ncols; i++) {
1640
		GdaColumn *c1, *c2;
1641
		GType t1, t2;
1642
		c1 = gda_data_model_describe_column (source->data_model, i);
1643
		c2 = gda_data_model_describe_column (model, i);
1644
		t1 = gda_column_get_g_type (c1);
1645
		t2 = gda_column_get_g_type (c2);
1646
1647
		if ((t1 != GDA_TYPE_NULL) && (t2 != GDA_TYPE_NULL) && (t1 != t2)) {
1648
			g_warning (_("Replacing data model must have the same characteristics as the "
1649
				     "data model it replaces"));
1650
			return;
1651
		}
1652
	}
1653
1654
	/* actually swap the models */
1655
	GSList *list;
1656
	source->data_model = model;
1657
	for (list = source->nodes; list; list = list->next) {
1658
		GdaSetNode *node = (GdaSetNode*) list->data;
1659
		g_object_unref (node->source_model);
1660
		node->source_model = g_object_ref (model);
1661
		g_signal_handlers_block_by_func (G_OBJECT (node->holder),
1662
						 G_CALLBACK (source_changed_holder_cb), set);
1663
		gda_holder_set_source_model (GDA_HOLDER (node->holder), model, node->source_column,
1664
					     NULL);
1665
		g_signal_handlers_unblock_by_func (G_OBJECT (node->holder),
1666
						   G_CALLBACK (source_changed_holder_cb), set);
1667
1668
	}
1669
#ifdef GDA_DEBUG_signal
1670
	g_print (">> 'SOURCE_MODEL_CHANGED' from %s\n", __FUNCTION__);
1671
#endif
1672
	g_signal_emit (G_OBJECT (set), gda_set_signals[SOURCE_MODEL_CHANGED], 0, source);
1673
#ifdef GDA_DEBUG_signal
1674
	g_print ("<< 'SOURCE_MODEL_CHANGED' from %s\n", __FUNCTION__);
1675
#endif
1676
}