1 /*
2  * Copyright (C) 2009 - 2012 Vivien Malerba <malerba@gnome-db.org>
3  * Copyright (C) 2010 David King <davidk@openismus.com>
4  * Copyright (C) 2013 Daniel Espinosa <esodan@gmail.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA  02110-1301, USA.
20  */
21 
22 #include <string.h>
23 #include <glib/gi18n-lib.h>
24 #include <libgda/libgda.h>
25 #include "gdaui-set.h"
26 #include "marshallers/gdaui-marshal.h"
27 
28 #ifdef GSEAL_ENABLE
29 /**
30  * GdauiSetGroup:
31  * @group:
32  * @source:
33  *
34  * The <structname>GdauiSetGroup</structname>.
35  *
36  * To create a new #GdauiSetGroup use #gdaiu_set_group_new.
37  *
38  * To free a #GdauiSetGroup, created by #gdaui_set_group_new, use #gda_set_group_free.
39  *
40  * Since 5.2, you must consider this struct as opaque. Any access to its internal must use public API.
41  * Don't try to use #gdaui_set_group_free on a struct that was created manually.
42  */
43 struct _GdauiSetGroup {
44         GdaSetGroup      *group;
45         GdauiSetSource   *source; /* if NULL, then @group->nodes contains exactly one entry */
46 
47 	/*< private >*/
48         /* Padding for future expansion */
49         gpointer      _gda_reserved1;
50         gpointer      _gda_reserved2;
51 };
52 #else
53 #endif
54 
55 /*
56    Register GdauiSetGroup type
57 */
58 GType
gdaui_set_group_get_type(void)59 gdaui_set_group_get_type (void)
60 {
61 	static GType type = 0;
62 
63 	if (G_UNLIKELY (type == 0)) {
64         if (type == 0)
65 			type = g_boxed_type_register_static ("GdauiSetGroup",
66 							     (GBoxedCopyFunc) gdaui_set_group_copy,
67 							     (GBoxedFreeFunc) gdaui_set_group_free);
68 	}
69 
70 	return type;
71 }
72 
73 /**
74  * gdaui_set_group_new:
75  * @group: a #GdaSetGroup
76  *
77  * Creates a new #GdauiSetGroup struct.
78  *
79  * Return: (transfer full): a new #GdauiSetGroup struct.
80  *
81  * Since: 5.2
82  */
83 GdauiSetGroup*
gdaui_set_group_new(GdaSetGroup * group)84 gdaui_set_group_new (GdaSetGroup *group)
85 {
86 	g_return_val_if_fail (group, NULL);
87 	GdauiSetGroup *sg = g_new0 (GdauiSetGroup, 1);
88 	sg->source = NULL;
89 	sg->group = group;
90 	return sg;
91 }
92 
93 /**
94  * gdaui_set_group_copy:
95  * @sg: a #GdauiSetGroup
96  *
97  * Copy constructor.
98  *
99  * Returns: a new #GdauiSetGroup
100  *
101  * Since: 5.2
102  */
103 GdauiSetGroup *
gdaui_set_group_copy(GdauiSetGroup * sg)104 gdaui_set_group_copy (GdauiSetGroup *sg)
105 {
106 	g_return_val_if_fail (sg, NULL);
107 
108 	GdauiSetGroup *n;
109 	n = gdaui_set_group_new (gdaui_set_group_get_group (sg));
110 	gdaui_set_group_set_source (n, gdaui_set_group_get_source (sg));
111 	return n;
112 }
113 
114 /**
115  * gdaui_set_group_free:
116  * @sg: (allow-none): a #GdauiSetGroup struct to free
117  *
118  * Frees any resources taken by @sg struct. If @sg is %NULL, then nothing happens.
119  *
120  * Since: 5.2
121  */
122 void
gdaui_set_group_free(GdauiSetGroup * sg)123 gdaui_set_group_free (GdauiSetGroup *sg)
124 {
125 	g_return_if_fail(sg);
126 	g_free (sg);
127 }
128 
129 /**
130  * gdaui_set_group_set_source:
131  * @sg: a #GdauiSetGroup struct to free
132  * @source (allow-none): a #GdauiSetSource struct or NULL
133  *
134  * Set source to @source. if @source is #NULL, then @group nodes contains exactly one entry.
135  *
136  * Since: 5.2
137  */
138 void
gdaui_set_group_set_source(GdauiSetGroup * sg,GdauiSetSource * source)139 gdaui_set_group_set_source (GdauiSetGroup *sg, GdauiSetSource *source)
140 {
141 	g_return_if_fail (sg);
142 	sg->source = source;
143 }
144 
145 /**
146  * gdaui_set_group_get_source:
147  * @sg: a #GdauiSetGroup struct
148  *
149  * Get source used by @sg.
150  *
151  * Returns: used #GdaSetGroup
152  *
153  * Since: 5.2
154  */
155 GdauiSetSource*
gdaui_set_group_get_source(GdauiSetGroup * sg)156 gdaui_set_group_get_source (GdauiSetGroup *sg)
157 {
158 	g_return_val_if_fail (sg, NULL);
159 	return sg->source;
160 }
161 
162 /**
163  * gdaui_set_group_set_group:
164  * @sg: a #GdauiSetGroup struct to free
165  * @group: a #GdaSetGroup struct
166  *
167  * Set source to @source.
168  *
169  * Since: 5.2
170  */
171 void
gdaui_set_group_set_group(GdauiSetGroup * sg,GdaSetGroup * group)172 gdaui_set_group_set_group (GdauiSetGroup *sg, GdaSetGroup *group)
173 {
174 	g_return_if_fail (sg);
175 	g_warn_if_fail (group);
176 	sg->group = sg->group;
177 }
178 
179 /**
180  * gdaui_set_group_get_group:
181  * @sg: a #GdauiSetGroup struct to free
182  *
183  * Get group used by @sg.
184  *
185  * Returns: used #GdaSetGroup
186  *
187  * Since: 5.2
188  */
189 GdaSetGroup*
gdaui_set_group_get_group(GdauiSetGroup * sg)190 gdaui_set_group_get_group (GdauiSetGroup *sg)
191 {
192 	g_return_val_if_fail (sg, NULL);
193 	return sg->group;
194 }
195 
196 #ifdef GSEAL_ENABLE
197 /**
198  * GdauiSetSource:
199  * @source: a #GdaSetSource
200  * @shown_cols_index: (array length=shown_n_cols): Array with the column number to be shown from #GdaSetSource
201  * @shown_n_cols: number of elements of @shown_cols_index
202  * @ref_cols_index: (array length=ref_n_cols): Array with the number of columns as PRIMARY KEY in #GdaSetSource
203  * @ref_n_cols: number of elements of @ref_cols_index
204  *
205  * The <structname>GdauiSetSource</structname> is a ...
206  *
207  * To create a new #GdauiSetSource use #gdaui_set_source_new.
208  *
209  * To free a #GdauiSetSource, created by #gdaui_set_source_new, use #gdaui_set_source_free.
210  *
211  * Since 5.2, you must consider this struct as opaque. Any access to its internal must use public API.
212  * Don't try to use #gdaui_set_source_free on a struct that was created manually.
213  */
214 struct _GdauiSetSource {
215         GdaSetSource   *source;
216 
217 	/* displayed columns in 'source->data_model' */
218  	gint shown_n_cols;
219  	gint *shown_cols_index;
220 
221  	/* columns used as a reference (corresponding to PK values) in 'source->data_model' */
222  	gint ref_n_cols;
223  	gint *ref_cols_index;
224 
225 	/*< private >*/
226         /* Padding for future expansion */
227         gpointer        _gda_reserved1;
228         gpointer        _gda_reserved2;
229         gpointer        _gda_reserved3;
230         gpointer        _gda_reserved4;
231 };
232 #else
233 #endif
234 
235 /*
236    Register GdauiSetSource type
237 */
238 GType
gdaui_set_source_get_type(void)239 gdaui_set_source_get_type (void)
240 {
241 	static GType type = 0;
242 
243 	if (G_UNLIKELY (type == 0)) {
244         if (type == 0)
245 			type = g_boxed_type_register_static ("GdauiSetSource",
246 							     (GBoxedCopyFunc) gdaui_set_source_copy,
247 							     (GBoxedFreeFunc) gdaui_set_source_free);
248 	}
249 
250 	return type;
251 }
252 
253 /**
254  * gdaui_set_source_new:
255  *
256  * Creates a new #GdauiSetSource struct.
257  *
258  * Return: (transfer full): a new #GdauiSetSource struct.
259  *
260  * Since: 5.2
261  */
262 GdauiSetSource*
gdaui_set_source_new(GdaSetSource * source)263 gdaui_set_source_new (GdaSetSource *source)
264 {
265 	g_return_val_if_fail (source, NULL);
266 	GdauiSetSource *s = g_new0 (GdauiSetSource, 1);
267 	s->source = source;
268 	s->shown_n_cols = 0;
269 	s->shown_cols_index = NULL;
270 	s->ref_n_cols = 0;
271 	s->ref_cols_index = NULL;
272 
273 	return s;
274 }
275 
276 /**
277  * gdaui_set_source_copy:
278  * @s: a #GdauiSetGroup
279  *
280  * Copy constructor.
281  *
282  * Returns: a new #GdauiSetSource
283  *
284  * Since: 5.2
285  */
286 GdauiSetSource *
gdaui_set_source_copy(GdauiSetSource * s)287 gdaui_set_source_copy (GdauiSetSource *s)
288 {
289 	GdauiSetSource *n;
290 	g_return_val_if_fail (s, NULL);
291 	n = gdaui_set_source_new (gdaui_set_source_get_source (s));
292 	gdaui_set_source_set_ref_columns (n,
293 	                                  gdaui_set_source_get_ref_columns (s),
294 	                                  gdaui_set_source_get_ref_n_cols (s));
295 	gdaui_set_source_set_shown_columns (n,
296 	                                    gdaui_set_source_get_shown_columns (s),
297 	                                    gdaui_set_source_get_shown_n_cols (s));
298 	return n;
299 }
300 
301 /**
302  * gdaui_set_source_free:
303  * @s: (allow-none): a #GdauiSetSource struct to free
304  *
305  * Frees any resources taken by @s struct. If @s is %NULL, then nothing happens.
306  *
307  * Since: 5.2
308  */
309 void
gdaui_set_source_free(GdauiSetSource * s)310 gdaui_set_source_free (GdauiSetSource *s)
311 {
312 	g_return_if_fail(s);
313 	if(s->shown_cols_index)
314 		g_free(s->shown_cols_index);
315 	if (s->ref_cols_index)
316 		g_free(s->ref_cols_index);
317 	g_free (s);
318 }
319 
320 /**
321  * gdaui_set_source_set_source:
322  * @s: a #GdauiSetSource struct to free
323  * @source: a #GdaSetSource struct
324  *
325  * Set source to @source.
326  *
327  * Since: 5.2
328  */
329 void
gdaui_set_source_set_source(GdauiSetSource * s,GdaSetSource * source)330 gdaui_set_source_set_source (GdauiSetSource *s, GdaSetSource *source)
331 {
332 	g_return_if_fail (s);
333 	g_return_if_fail (source);
334 	s->source = s->source;
335 }
336 
337 /**
338  * gdaui_set_source_get_source:
339  * @s: a #GdauiSetGroup struct
340  *
341  * Get source used by @sg.
342  *
343  * Returns: used #GdaSetSource
344  *
345  * Since: 5.2
346  */
347 GdaSetSource*
gdaui_set_source_get_source(GdauiSetSource * s)348 gdaui_set_source_get_source (GdauiSetSource *s)
349 {
350 	g_return_val_if_fail (s, NULL);
351 	return s->source;
352 }
353 
354 /**
355  * gdaui_set_source_get_shown_n_cols:
356  * @s: a #GdauiSetSource
357  *
358  * Returns: number of columns to be shown.
359  *
360  * Since: 5.2
361  */
362 gint
gdaui_set_source_get_shown_n_cols(GdauiSetSource * s)363 gdaui_set_source_get_shown_n_cols   (GdauiSetSource *s)
364 {
365 	g_return_val_if_fail (s, -1);
366 	return s->shown_n_cols;
367 }
368 
369 /**
370  * gdaui_set_source_get_shown_columns:
371  * @s: a #GdauiSetSource
372  *
373  * Returns: (array zero-terminated=1) (transfer none): array of of columns to be shown.
374  *
375  * Since: 5.2
376  */
377 gint*
gdaui_set_source_get_shown_columns(GdauiSetSource * s)378 gdaui_set_source_get_shown_columns  (GdauiSetSource *s)
379 {
380 	g_return_val_if_fail (s, NULL);
381 	return s->shown_cols_index;
382 }
383 
384 /**
385  * gdaui_set_source_set_shown_columns:
386  * @s: a #GdauiSetSource
387  * @columns: (array length=n_columns): an array of with columns numbers to be shown from a #GdaSetSource
388  * @n_columns: number of columns of the array
389  *
390  * Set the columns to be shown.
391  *
392  * Since: 5.2
393  */
394 void
gdaui_set_source_set_shown_columns(GdauiSetSource * s,gint * columns,gint n_columns)395 gdaui_set_source_set_shown_columns (GdauiSetSource *s, gint *columns, gint n_columns)
396 {
397 	gint i;
398 	g_return_if_fail (s);
399 	g_return_if_fail (columns);
400 	if (s->shown_cols_index)
401 		g_free (s->shown_cols_index);
402 	s->shown_n_cols = n_columns;
403 	s->shown_cols_index = g_new0 (gint, s->shown_n_cols+1); /* This adds a null terminated array */
404 	for (i = 0; i < n_columns; i++) {
405 		s->shown_cols_index[i] = columns[i];
406 	}
407 }
408 
409 /**
410  * gdaui_set_source_get_ref_n_cols:
411  * @s: a #GdauiSetSource
412  *
413  * Returns: number of columns to referenced.
414  *
415  * Since: 5.2
416  */
417 gint
gdaui_set_source_get_ref_n_cols(GdauiSetSource * s)418 gdaui_set_source_get_ref_n_cols   (GdauiSetSource *s)
419 {
420 	g_return_val_if_fail (s, -1);
421 	return s->ref_n_cols;
422 }
423 
424 /**
425  * gdaui_set_source_get_ref_columns:
426  * @s: a #GdauiSetSource
427  *
428  * Returns: (array zero-terminated=1) (transfer none): array of of columns to be shown.
429  *
430  * Since: 5.2
431  */
432 gint*
gdaui_set_source_get_ref_columns(GdauiSetSource * s)433 gdaui_set_source_get_ref_columns  (GdauiSetSource *s)
434 {
435 	g_return_val_if_fail (s, NULL);
436 	return s->ref_cols_index;
437 }
438 
439 /**
440  * gdaui_set_source_set_ref_columns:
441  * @s: a #GdauiSetSource struct to free
442  * @columns: (array length=n_columns): an array of with columns numbers of referen (Primary Key) at #GdaSetSource
443  * @n_columns: number of columns of the array
444  *
445  * Set the columns to be shown.
446  *
447  * Since: 5.2
448  */
449 void
gdaui_set_source_set_ref_columns(GdauiSetSource * s,gint * columns,gint n_columns)450 gdaui_set_source_set_ref_columns (GdauiSetSource *s, gint *columns, gint n_columns)
451 {
452 	gint i;
453 	g_return_if_fail (s);
454 	g_return_if_fail (columns);
455 	if (s->ref_cols_index)
456 		g_free (s->ref_cols_index);
457 	s->ref_n_cols = n_columns;
458 	s->ref_cols_index = g_new0 (gint, s->ref_n_cols+1); /* This creates a null terminated array */
459 	for (i = 0; i < n_columns; i++) {
460 		s->ref_cols_index[i] = columns[i];
461 	}
462 }
463 
464 static void gdaui_set_class_init (GdauiSetClass * class);
465 static void gdaui_set_init (GdauiSet *wid);
466 static void gdaui_set_dispose (GObject *object);
467 
468 static void gdaui_set_set_property (GObject *object,
469 				    guint param_id,
470 				    const GValue *value,
471 				    GParamSpec *pspec);
472 static void gdaui_set_get_property (GObject *object,
473 				    guint param_id,
474 				    GValue *value,
475 				    GParamSpec *pspec);
476 
477 static void wrapped_set_public_data_changed_cb (GdaSet *wset, GdauiSet *set);
478 static void wrapped_set_source_model_changed_cb (GdaSet *wset, GdaSetSource *source, GdauiSet *set);
479 static void clean_public_data (GdauiSet *set);
480 static void compute_public_data (GdauiSet *set);
481 static void update_public_data (GdauiSet *set);
482 static void compute_shown_columns_index (GdauiSetSource *dsource);
483 static void compute_ref_columns_index (GdauiSetSource *dsource);
484 
485 struct _GdauiSetPriv
486 {
487 	GdaSet *set;
488 };
489 
490 /* get a pointer to the parents to be able to call their destructor */
491 static GObjectClass *parent_class = NULL;
492 
493 /* properties */
494 enum {
495 	PROP_0,
496 	PROP_SET
497 };
498 
499 /* signals */
500 enum {
501 	PUBLIC_DATA_CHANGED,
502 	SOURCE_MODEL_CHANGED,
503 	LAST_SIGNAL
504 };
505 
506 static gint gdaui_set_signals[LAST_SIGNAL] = { 0, 0 };
507 
508 GType
_gdaui_set_get_type(void)509 _gdaui_set_get_type (void) {
510 	return gdaui_set_get_type ();
511 }
512 
513 GType
gdaui_set_get_type(void)514 gdaui_set_get_type (void)
515 {
516 	static GType type = 0;
517 
518 	if (G_UNLIKELY (type == 0)) {
519 		static const GTypeInfo info = {
520 			sizeof (GdauiSetClass),
521 			(GBaseInitFunc) NULL,
522 			(GBaseFinalizeFunc) NULL,
523 			(GClassInitFunc) gdaui_set_class_init,
524 			NULL,
525 			NULL,
526 			sizeof (GdauiSet),
527 			0,
528 			(GInstanceInitFunc) gdaui_set_init,
529 			0
530 		};
531 
532 		type = g_type_register_static (G_TYPE_OBJECT, "GdauiSet", &info, 0);
533 	}
534 
535 	return type;
536 }
537 
538 static void
gdaui_set_class_init(GdauiSetClass * class)539 gdaui_set_class_init (GdauiSetClass *class)
540 {
541 	GObjectClass   *object_class = G_OBJECT_CLASS (class);
542 
543 	parent_class = g_type_class_peek_parent (class);
544 	object_class->dispose = gdaui_set_dispose;
545 
546 	/**
547          * GdauiSet::public-data-changed:
548          * @set: the #GdauiSet
549          *
550          * Gets emitted when @set's public data (#GdauiSetGroup or #GdauiSetSource values) have changed
551 	 *
552 	 * Since: 4.2
553          */
554         gdaui_set_signals[PUBLIC_DATA_CHANGED] =
555                 g_signal_new ("public-data-changed",
556                               G_TYPE_FROM_CLASS (object_class),
557                               G_SIGNAL_RUN_FIRST,
558                               G_STRUCT_OFFSET (GdauiSetClass, public_data_changed),
559                               NULL, NULL,
560                               _gdaui_marshal_VOID__VOID, G_TYPE_NONE, 0);
561 	/**
562          * GdauiSet::source-model-changed:
563          * @set: the #GdauiSet
564          *
565          * Gets emitted when the data model used in @set's #GdauiSetSource has changed
566 	 *
567 	 * Since: 4.2
568          */
569         gdaui_set_signals[SOURCE_MODEL_CHANGED] =
570                 g_signal_new ("source-model-changed",
571                               G_TYPE_FROM_CLASS (object_class),
572                               G_SIGNAL_RUN_FIRST,
573                               G_STRUCT_OFFSET (GdauiSetClass, public_data_changed),
574                               NULL, NULL,
575                               _gdaui_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
576 
577         class->public_data_changed = NULL;
578         class->source_model_changed = NULL;
579 
580 	/* Properties */
581         object_class->set_property = gdaui_set_set_property;
582         object_class->get_property = gdaui_set_get_property;
583 	g_object_class_install_property (object_class, PROP_SET,
584                                          g_param_spec_object ("set", NULL, NULL,
585 							      GDA_TYPE_SET,
586 							      G_PARAM_READABLE | G_PARAM_WRITABLE |
587 							      G_PARAM_CONSTRUCT_ONLY));
588 }
589 
590 static void
gdaui_set_init(GdauiSet * set)591 gdaui_set_init (GdauiSet *set)
592 {
593 	set->priv = g_new0 (GdauiSetPriv, 1);
594 	set->priv->set = NULL;
595 }
596 
597 /*
598  * _gdaui_set_new
599  * @set: a #GdaSet
600  *
601  * Creates a new #GdauiSet which wraps @set's properties
602  *
603  * Returns: the new widget
604  *
605  * Deprecated: Since 5.2
606  */
607 GdauiSet *
_gdaui_set_new(GdaSet * set)608 _gdaui_set_new (GdaSet *set)
609 {
610 	return gdaui_set_new (set);
611 }
612 
613 /**
614  * gdaui_set_new:
615  * @set: a #GdaSet
616  *
617  * Creates a new #GdauiSet which wraps @set's properties
618  *
619  * Returns: the new widget
620  * Since: 5.2
621  **/
622 GdauiSet *
gdaui_set_new(GdaSet * set)623 gdaui_set_new (GdaSet *set)
624 {
625 	g_return_val_if_fail (GDA_IS_SET (set), NULL);
626 
627 	return (GdauiSet *) g_object_new (GDAUI_TYPE_SET, "set", set, NULL);
628 }
629 
630 static void
gdaui_set_dispose(GObject * object)631 gdaui_set_dispose (GObject *object)
632 {
633         GdauiSet *set;
634 
635         g_return_if_fail (GDAUI_IS_SET (object));
636 
637         set = GDAUI_SET (object);
638 
639         if (set->priv) {
640                 if (set->priv->set) {
641                         g_signal_handlers_disconnect_by_func (G_OBJECT (set->priv->set),
642                                                               G_CALLBACK (wrapped_set_public_data_changed_cb), set);
643                         g_signal_handlers_disconnect_by_func (G_OBJECT (set->priv->set),
644                                                               G_CALLBACK (wrapped_set_source_model_changed_cb), set);
645 
646                         g_object_unref (set->priv->set);
647                         set->priv->set = NULL;
648                 }
649 
650 		clean_public_data (set);
651 
652                 g_free (set->priv);
653                 set->priv = NULL;
654         }
655 
656         /* for the parent class */
657         parent_class->dispose (object);
658 }
659 
660 static void
gdaui_set_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)661 gdaui_set_set_property (GObject *object,
662 			guint param_id,
663 			const GValue *value,
664 			GParamSpec *pspec)
665 {
666 	GdauiSet *set;
667 
668 	set = GDAUI_SET (object);
669 
670 	switch (param_id) {
671 	case PROP_SET:
672 		set->priv->set = g_value_get_object (value);
673 		if (set->priv->set) {
674 			g_object_ref (set->priv->set);
675 			compute_public_data (set);
676 			g_signal_connect (set->priv->set, "public-data-changed",
677 					  G_CALLBACK (wrapped_set_public_data_changed_cb), set);
678 			g_signal_connect (set->priv->set, "source-model-changed",
679 					  G_CALLBACK (wrapped_set_source_model_changed_cb), set);
680 		}
681 		break;
682 	default:
683 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
684 		break;
685 	}
686 }
687 
688 static void
wrapped_set_public_data_changed_cb(G_GNUC_UNUSED GdaSet * wset,GdauiSet * set)689 wrapped_set_public_data_changed_cb (G_GNUC_UNUSED GdaSet *wset, GdauiSet *set)
690 {
691 	update_public_data (set);
692 	g_signal_emit (set, gdaui_set_signals[PUBLIC_DATA_CHANGED], 0);
693 }
694 
695 static void
wrapped_set_source_model_changed_cb(G_GNUC_UNUSED GdaSet * wset,GdaSetSource * source,GdauiSet * set)696 wrapped_set_source_model_changed_cb (G_GNUC_UNUSED GdaSet *wset, GdaSetSource *source, GdauiSet *set)
697 {
698 	GdauiSetSource *uisource = NULL;
699 	GSList *list;
700 	for (list = set->sources_list; list; list = list->next) {
701 		if (((GdauiSetSource*) list->data)->source == source) {
702 			uisource = (GdauiSetSource*) list->data;
703 			break;
704 		}
705 	}
706 	if (uisource)
707 		g_signal_emit (set, gdaui_set_signals[SOURCE_MODEL_CHANGED], 0, uisource);
708 }
709 
710 static void
clean_public_data(GdauiSet * set)711 clean_public_data (GdauiSet *set)
712 {
713 	GSList *list;
714 
715 	for (list = set->sources_list; list; list = list->next) {
716 		GdauiSetSource *dsource = (GdauiSetSource*) list->data;
717 		gdaui_set_source_free (dsource);
718 	}
719 	g_slist_free (set->sources_list);
720 	set->sources_list = NULL;
721 
722 	for (list = set->groups_list; list; list = list->next) {
723 		GdauiSetGroup *dgroup = (GdauiSetGroup*) list->data;
724 		gdaui_set_group_free (dgroup);
725 	}
726 	g_slist_free (set->groups_list);
727 	set->groups_list = NULL;
728 }
729 
730 static void
compute_public_data(GdauiSet * set)731 compute_public_data (GdauiSet *set)
732 {
733 	GSList *list;
734 	GdaSet *aset = GDA_SET (set->priv->set);
735 	GHashTable *hash;
736 
737 	/* scan GdaSetSource list */
738 	hash = g_hash_table_new (NULL, NULL);
739 	for (list = aset->sources_list; list; list = list->next) {
740 		GdauiSetSource *dsource;
741 		dsource = gdaui_set_source_new (GDA_SET_SOURCE (list->data));
742 		set->sources_list = g_slist_prepend (set->sources_list, dsource);
743 		g_hash_table_insert (hash, list->data, dsource);
744 
745 		compute_shown_columns_index (dsource);
746 		compute_ref_columns_index (dsource);
747 	}
748 	set->sources_list = g_slist_reverse (set->sources_list);
749 
750 	/* scan GdaSetGroup list */
751 	for (list = aset->groups_list; list; list = list->next) {
752 		GdauiSetGroup *dgroup;
753 		g_assert (list->data);
754 		dgroup = gdaui_set_group_new (GDA_SET_GROUP (list->data));
755 		gdaui_set_group_set_source (dgroup,
756 		                            g_hash_table_lookup (hash,
757 		                                                 gda_set_group_get_source (GDA_SET_GROUP (list->data))));
758 		set->groups_list = g_slist_prepend (set->groups_list, dgroup);
759 	}
760 	set->groups_list = g_slist_reverse (set->groups_list);
761 
762 	g_hash_table_destroy (hash);
763 }
764 
765 static void
update_public_data(GdauiSet * set)766 update_public_data (GdauiSet *set)
767 {
768 	GSList *list, *elist = NULL;
769 	GdaSet *aset = GDA_SET (set->priv->set);
770 	GHashTable *shash; /* key = GdaSetSource, value = GdauiSetSource */
771 	GHashTable *ghash; /* key = GdaSetGroup, value = GdauiSetGroup */
772 
773 	/* build hash with existing sources in GdauiSet */
774 	shash = g_hash_table_new (NULL, NULL);
775 	for (list = set->sources_list; list; list = list->next) {
776 		GdauiSetSource *dsource = (GdauiSetSource*) list->data;
777 		g_hash_table_insert (shash, gdaui_set_source_get_source (dsource), dsource);
778 	}
779 
780 	/* scan GdaSetSource list */
781 	elist = set->sources_list;
782 	set->sources_list = NULL;
783 	for (list = aset->sources_list; list; list = list->next) {
784 		GdauiSetSource *dsource;
785 		dsource = g_hash_table_lookup (shash, list->data);
786 		if (dsource) {
787 			set->sources_list = g_slist_prepend (set->sources_list, dsource);
788 			continue;
789 		}
790 		dsource = gdaui_set_source_new (GDA_SET_SOURCE (list->data));
791 		set->sources_list = g_slist_prepend (set->sources_list, dsource);
792 		g_hash_table_insert (shash, list->data, dsource);
793 
794 		compute_shown_columns_index (dsource);
795 		compute_ref_columns_index (dsource);
796 	}
797 	set->sources_list = g_slist_reverse (set->sources_list);
798 
799 	if (elist) {
800 		for (list = elist; list; list = list->next) {
801 			if (!g_slist_find (set->sources_list, list->data)) {
802 				GdauiSetSource *dsource = (GdauiSetSource*) list->data;
803 				gdaui_set_source_free (dsource);
804 			}
805 		}
806 		g_slist_free (elist);
807 	}
808 
809 	/* build hash with existing groups */
810 	ghash = g_hash_table_new (NULL, NULL);
811 	for (list = set->groups_list; list; list = list->next) {
812 		GdauiSetGroup *dgroup = (GdauiSetGroup*) list->data;
813 		g_hash_table_insert (ghash, gdaui_set_group_get_group (dgroup), dgroup);
814 	}
815 
816 	/* scan GdaSetGroup list */
817 	elist = set->groups_list;
818 	set->groups_list = NULL;
819 	for (list = aset->groups_list; list; list = list->next) {
820 		GdauiSetGroup *dgroup;
821 		dgroup = g_hash_table_lookup (ghash, list->data);
822 		if (dgroup) {
823 			set->groups_list = g_slist_prepend (set->groups_list, dgroup);
824 			continue;
825 		}
826 		dgroup = gdaui_set_group_new (GDA_SET_GROUP (list->data));
827 		gdaui_set_group_set_source (dgroup, g_hash_table_lookup (shash,
828 		                                           gda_set_group_get_source (gdaui_set_group_get_group (dgroup))));
829 		set->groups_list = g_slist_prepend (set->groups_list, dgroup);
830 	}
831 	set->groups_list = g_slist_reverse (set->groups_list);
832 
833 	if (elist) {
834 		for (list = elist; list; list = list->next) {
835 			if (!g_slist_find (set->groups_list, list->data)) {
836 				GdauiSetGroup *dgroup = (GdauiSetGroup*) list->data;
837 				gdaui_set_group_free (dgroup);
838 			}
839 		}
840 		g_slist_free (elist);
841 	}
842 
843 	g_hash_table_destroy (shash);
844 	g_hash_table_destroy (ghash);
845 }
846 
847 static void
compute_shown_columns_index(GdauiSetSource * dsource)848 compute_shown_columns_index (GdauiSetSource *dsource)
849 {
850 	gint ncols, nholders;
851 	gint *mask = NULL, masksize = 0;
852 
853 	nholders = gda_set_source_get_n_nodes (gdaui_set_source_get_source (dsource));
854 	g_return_if_fail (nholders > 0);
855 	ncols = gda_data_model_get_n_columns (gda_set_source_get_data_model (gdaui_set_source_get_source (dsource)));
856 	g_return_if_fail (ncols > 0);
857 
858 	if (ncols > nholders) {
859 		/* we only want columns which are not holders */
860 		gint i, current = 0;
861 
862 		masksize = ncols - nholders;
863 		mask = g_new0 (gint, masksize);
864 		for (i = 0; i < ncols ; i++) {
865 			GSList *list = gda_set_source_get_nodes (gdaui_set_source_get_source (dsource));
866 			gboolean found = FALSE;
867 			while (list && !found) {
868 				if (gda_set_node_get_source_column (GDA_SET_NODE (list->data)) == i)
869 					found = TRUE;
870 				else
871 					list = g_slist_next (list);
872 			}
873 			if (!found) {
874 				mask[current] = i;
875 				current ++;
876 			}
877 		}
878 		masksize = current;
879 	}
880 	else {
881 		/* we want all the columns */
882 		gint i;
883 
884 		masksize = ncols;
885 		mask = g_new0 (gint, masksize);
886 		for (i=0; i<ncols; i++) {
887 			mask[i] = i;
888 		}
889 	}
890 	gdaui_set_source_set_shown_columns (dsource, mask, masksize);
891 }
892 
893 void
compute_ref_columns_index(GdauiSetSource * dsource)894 compute_ref_columns_index (GdauiSetSource *dsource)
895 {
896 	gint ncols, nholders;
897 	gint *mask = NULL, masksize = 0;
898 
899 	nholders = gda_set_source_get_n_nodes (gdaui_set_source_get_source (dsource));
900 	g_return_if_fail (nholders > 0);
901 	ncols = gda_data_model_get_n_columns (gda_set_source_get_data_model (gdaui_set_source_get_source (dsource)));
902 	g_return_if_fail (ncols > 0);
903 
904 	if (ncols > nholders) {
905 		/* we only want columns which are holders */
906 		gint i, current = 0;
907 
908 		masksize = ncols - nholders;
909 		mask = g_new0 (gint, masksize);
910 		for (i=0; i<ncols ; i++) {
911 			GSList *list = gda_set_source_get_nodes (gdaui_set_source_get_source (dsource));
912 			gboolean found = FALSE;
913 			while (list && !found) {
914 				if (gda_set_node_get_source_column (GDA_SET_NODE (list->data)) == i)
915 					found = TRUE;
916 				else
917 					list = g_slist_next (list);
918 			}
919 			if (found) {
920 				mask[current] = i;
921 				current ++;
922 			}
923 		}
924 		masksize = current;
925 	}
926 	else {
927 		/* we want all the columns */
928 		gint i;
929 
930 		masksize = ncols;
931 		mask = g_new0 (gint, masksize);
932 		for (i=0; i<ncols; i++) {
933 			mask[i] = i;
934 		}
935 	}
936 	gdaui_set_source_set_ref_columns (dsource, mask, masksize);
937 }
938 
939 
940 static void
gdaui_set_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)941 gdaui_set_get_property (GObject *object,
942 			guint param_id,
943 			GValue *value,
944 			GParamSpec *pspec)
945 {
946 	GdauiSet *set;
947 
948 	set = GDAUI_SET (object);
949 
950 	switch (param_id) {
951 	case PROP_SET:
952 		g_value_set_object (value, set->priv->set);
953 		break;
954 	default:
955 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
956 		break;
957 	}
958 }
959 
960 /**
961  * _gdaui_set_get_group:
962  * @dbset:
963  * @holder:
964  *
965  * Returns: A new #GdauiSetGroup struct
966  * Deprecated: Since 5.2
967  **/
968 GdauiSetGroup  *
_gdaui_set_get_group(GdauiSet * dbset,GdaHolder * holder)969 _gdaui_set_get_group (GdauiSet *dbset, GdaHolder *holder)
970 {
971 	return gdaui_set_get_group (dbset, holder);
972 }
973 
974 /**
975  * gdaui_set_get_group:
976  * @dbset:
977  * @holder:
978  *
979  * Returns: A new #GdauiSetGroup struct
980  * Since: 5.2
981  **/
982 GdauiSetGroup  *
gdaui_set_get_group(GdauiSet * dbset,GdaHolder * holder)983 gdaui_set_get_group (GdauiSet *dbset, GdaHolder *holder)
984 {
985 	GdaSetGroup *agroup;
986 	GSList *list;
987 	g_return_val_if_fail (GDAUI_IS_SET (dbset), NULL);
988 	g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL);
989 
990 	agroup = gda_set_get_group (dbset->priv->set, holder);
991 	if (!agroup)
992 		return NULL;
993 
994 	for (list = dbset->groups_list; list; list = list->next) {
995 		if (GDAUI_SET_GROUP (list->data)->group == agroup)
996 			return GDAUI_SET_GROUP (list->data);
997 	}
998 	return NULL;
999 }
1000 
1001 #ifdef GDA_DEBUG_NO
1002 static void _gda_set_node_dump (GdaSetNode *node);
1003 static void set_source_dump (GdauiSetSource *source);
1004 static void set_group_dump (GdauiSetGroup *group);
1005 
1006 static void
set_source_dump(GdauiSetSource * source)1007 set_source_dump (GdauiSetSource *source)
1008 {
1009 	g_print ("  GdauiSetSource %p\n", source);
1010 	if (source) {
1011 		gint i;
1012 		g_print ("    - GdaSetSource: %p\n", source->source);
1013 		for (i = 0; i < source->shown_n_cols; i++)
1014 			g_print ("    - shown_cols_index [%d]: %d\n", i, source->shown_cols_index[i]);
1015 		for (i = 0; i < source->ref_n_cols; i++)
1016 			g_print ("    - ref_cols_index [%d]: %d\n", i, source->ref_cols_index[i]);
1017 	}
1018 }
1019 
1020 static void
set_group_dump(GdauiSetGroup * group)1021 set_group_dump (GdauiSetGroup *group)
1022 {
1023 	g_print ("  GdauiSetGroup %p\n", group);
1024 	if (group) {
1025 		g_print ("    - GdaSetGroup: %p\n", group->group);
1026 		if (group->group->nodes)
1027 			g_slist_foreach (group->group->nodes, (GFunc) _gda_set_node_dump, NULL);
1028 		else
1029 			g_print ("                 ERROR: group has no node!\n");
1030 		g_print ("    - GdauiSetSource: %p\n", group->source);
1031 	}
1032 }
1033 
1034 static void
_gda_set_node_dump(GdaSetNode * node)1035 _gda_set_node_dump (GdaSetNode *node)
1036 {
1037 	g_print ("      - GdaSetNode: %p\n", node);
1038 	g_print ("        - holder: %p (%s)\n", node->holder, node->holder ? gda_holder_get_id (node->holder) : "ERROR : no GdaHolder!");
1039 	g_print ("        - source_model: %p\n", node->source_model);
1040 	g_print ("        - source_column: %d\n", node->source_column);
1041 }
1042 
1043 static void
_gdaui_set_dump(GdauiSet * set)1044 _gdaui_set_dump (GdauiSet *set)
1045 {
1046 	g_print ("=== GdauiSet %p ===\n", set);
1047 	gda_set_dump (set->priv->set);
1048 	g_slist_foreach (set->sources_list, (GFunc) set_source_dump, NULL);
1049 	g_slist_foreach (set->groups_list, (GFunc) set_group_dump, NULL);
1050 	g_print ("=== GdauiSet %p END ===\n", set);
1051 }
1052 #endif
1053