1 /*
2  * go-data.c :
3  *
4  * Copyright (C) 2003-2005 Jody Goldberg (jody@gnome.org)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) version 3.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
19  * USA
20  */
21 
22 #include <goffice/goffice-config.h>
23 #include "go-data.h"
24 #include "go-data-impl.h"
25 #include <goffice/math/go-math.h>
26 #include <goffice/math/go-rangefunc.h>
27 
28 #include <gsf/gsf-impl-utils.h>
29 #include <glib/gi18n-lib.h>
30 #include <string.h>
31 
32 /**
33  * GODataFlags:
34  * @GO_DATA_CACHE_IS_VALID: data in cache are valid.
35  * @GO_DATA_IS_EDITABLE: data can be edited.
36  * @GO_DATA_SIZE_CACHED: cached size is valid.
37  * @GO_DATA_HAS_VALUE: object is not empty.
38  **/
39 
40 /**
41  * GODataClass:
42  * @base: base class.
43  * @dup: duplicates the #GOData.
44  * @eq: tests if the data are equal.
45  * @preferred_fmt: gets the preferred format.
46  * @date_conv: gets the #GODateConventions.
47  * @serialize: serializes.
48  * @unserialize: unserializes.
49  * @emit_changed: signals the data have changed.
50  * @get_n_dimensions: gets the dimensions number.
51  * @get_sizes: gets the sizes.
52  * @get_values: gets the values.
53  * @get_bounds: gets the bounds.
54  * @get_value: gets a value.
55  * @get_string: gets a string.
56  * @get_markup: gets the #PangoAttrList* for the string.
57  * @is_valid: checks if the data are valid.
58  **/
59 
60 /**
61  * GODataScalarClass:
62  * @base:  base class.
63  * @get_value: gets the value.
64  * @get_str: gets the string.
65  * @get_markup: gets the #PangoAttrList* for the string.
66  **/
67 
68 /**
69  * GODataVectorClass:
70  * @base: base class.
71  * @load_len: loads the vector length.
72  * @load_values: loads the values in the cache.
73  * @get_value: gets a value.
74  * @get_str: gets a string.
75  * @get_markup: gets the #PangoAttrList* for the string.
76  **/
77 
78 /**
79  * GODataMatrixClass:
80  * @base: base class.
81  * @load_size: loads the matrix length.
82  * @load_values: loads the values in the cache.
83  * @get_value: gets a value.
84  * @get_str: gets a string.
85  * @get_markup: gets the #PangoAttrList* for the string.
86  **/
87 
88 #define GO_DATA_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST ((k), GO_TYPE_DATA, GODataClass))
89 #define GO_IS_DATA_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GO_TYPE_DATA))
90 #define GO_DATA_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GO_TYPE_DATA, GODataClass))
91 
92 /**
93  * GODataMatrixSize:
94  * @rows: rows number, negative if dirty, includes missing values.
95  * @columns: columns number, negative if dirty, includes missing values.
96  **/
97 
98 enum {
99 	CHANGED,
100 	LAST_SIGNAL
101 };
102 
103 static gulong go_data_signals [LAST_SIGNAL] = { 0, };
104 
105 /* trivial fall back */
106 static GOData *
go_data_dup_real(GOData const * src)107 go_data_dup_real (GOData const *src)
108 {
109 	gpointer user = NULL;  /* FIXME? */
110 	char   *str = go_data_serialize (src, user);
111 	GOData *dst = g_object_new (G_OBJECT_TYPE (src), NULL);
112 	if (dst != NULL)
113 		go_data_unserialize (dst, str, user);
114 	g_free (str);
115 
116 	return dst;
117 }
118 
119 static void
go_data_init(GOData * data)120 go_data_init (GOData *data)
121 {
122 	data->flags = 0;
123 }
124 
125 #if 0
126 static GObjectClass *parent_klass;
127 static void
128 go_data_finalize (GOData *obj)
129 {
130 	g_warning ("finalize");
131 	(parent_klass->finalize) (obj);
132 }
133 #endif
134 
135 static void
go_data_class_init(GODataClass * klass)136 go_data_class_init (GODataClass *klass)
137 {
138 	go_data_signals [CHANGED] = g_signal_new ("changed",
139 		G_TYPE_FROM_CLASS (klass),
140 		G_SIGNAL_RUN_LAST,
141 		G_STRUCT_OFFSET (GODataClass, changed),
142 		NULL, NULL,
143 		g_cclosure_marshal_VOID__VOID,
144 		G_TYPE_NONE, 0);
145 	klass->dup = go_data_dup_real;
146 #if 0
147 	{
148 		GObjectClass *gobj_klass = (GObjectClass *)klass;
149 		gobj_klass->finalize = go_data_finalize;
150 		parent_klass = g_type_class_peek_parent (klass);
151 	}
152 #endif
153 }
154 
GSF_CLASS_ABSTRACT(GOData,go_data,go_data_class_init,go_data_init,G_TYPE_OBJECT)155 GSF_CLASS_ABSTRACT (GOData, go_data,
156 		    go_data_class_init, go_data_init,
157 		    G_TYPE_OBJECT)
158 
159 /**
160  * go_data_dup:
161  * @src: #GOData
162  *
163  * Returns: (transfer full): A deep copy of @src.
164  **/
165 GOData *
166 go_data_dup (GOData const *src)
167 {
168 	if (src != NULL) {
169 		GODataClass const *klass = GO_DATA_GET_CLASS (src);
170 		g_return_val_if_fail (klass != NULL, NULL);
171 		return (*klass->dup) (src);
172 	}
173 	return NULL;
174 }
175 
176 /**
177  * go_data_eq :
178  * @a: #GOData
179  * @b: #GOData
180  *
181  * Returns: TRUE if @a and @b are the same
182  **/
183 gboolean
go_data_eq(GOData const * a,GOData const * b)184 go_data_eq (GOData const *a, GOData const *b)
185 {
186 	if (a == b)
187 		return TRUE;
188 	else {
189 		GODataClass *a_klass = GO_DATA_GET_CLASS (a);
190 		GODataClass *b_klass = GO_DATA_GET_CLASS (b);
191 
192 		g_return_val_if_fail (a_klass != NULL, FALSE);
193 		g_return_val_if_fail (a_klass->eq != NULL, FALSE);
194 
195 		if (a_klass != b_klass)
196 			return FALSE;
197 
198 		return (*a_klass->eq) (a, b);
199 	}
200 }
201 
202 /**
203  * go_data_preferred_fmt :
204  * @dat: #GOData
205  *
206  * Caller is responsible for unrefing the result.
207  *
208  * Returns: the fmt preferred by the data
209  **/
210 GOFormat const *
go_data_preferred_fmt(GOData const * dat)211 go_data_preferred_fmt (GOData const *dat)
212 {
213 	GODataClass const *klass = GO_DATA_GET_CLASS (dat);
214 	g_return_val_if_fail (klass != NULL, NULL);
215 	if (klass->preferred_fmt)
216 		return klass->preferred_fmt (dat);
217 	return NULL;
218 }
219 
220 /**
221  * go_data_date_conv :
222  * @dat: #GOData
223  *
224  * Returns: the date conventions used by the data, or %NULL if not determined.
225  **/
226 GODateConventions const *
go_data_date_conv(GOData const * dat)227 go_data_date_conv (GOData const *dat)
228 {
229 	GODataClass const *klass = GO_DATA_GET_CLASS (dat);
230 	g_return_val_if_fail (klass != NULL, NULL);
231 	if (klass->date_conv)
232 		return klass->date_conv (dat);
233 	return NULL;
234 }
235 
236 
237 /**
238  * go_data_serialize :
239  * @dat: #GOData
240  * @user: a gpointer describing the context.
241  *
242  * NOTE : This is the _source_ not the content.  (I.e., this refers to the
243  * expression, not its current value.)
244  *
245  * Returns: a string representation of the data source that the caller is
246  * 	responsible for freeing
247  **/
248 char *
go_data_serialize(GOData const * dat,gpointer user)249 go_data_serialize (GOData const *dat, gpointer user)
250 {
251 	GODataClass const *klass = GO_DATA_GET_CLASS (dat);
252 	g_return_val_if_fail (klass != NULL, NULL);
253 	return (*klass->serialize) (dat, user);
254 }
255 
256 /**
257  * go_data_unserialize :
258  * @dat: #GOData
259  * @str: string to parse
260  * @user: a gpointer describing the context.
261  *
262  * De-serializes the source information returned from go_data_serialize.
263  *
264  * Returns: %FALSE on error.
265  **/
266 gboolean
go_data_unserialize(GOData * dat,char const * str,gpointer user)267 go_data_unserialize (GOData *dat, char const *str, gpointer user)
268 {
269 	GODataClass const *klass = GO_DATA_GET_CLASS (dat);
270 	g_return_val_if_fail (klass != NULL, FALSE);
271 	/* an empty string is not valid, see #46 */
272 	g_return_val_if_fail (str && *str, FALSE);
273 	return (*klass->unserialize) (dat, str, user);
274 }
275 
276 gboolean
go_data_is_valid(GOData const * data)277 go_data_is_valid (GOData const *data)
278 {
279 	GODataClass const *klass = GO_DATA_GET_CLASS (data);
280 	g_return_val_if_fail (klass != NULL, FALSE);
281 	return (klass->is_valid != NULL)? (*klass->is_valid) (data): FALSE;
282 }
283 
284 /**
285  * go_data_emit_changed :
286  * @dat: #GOData
287  *
288  * protected utility to emit a 'changed' signal
289  **/
290 void
go_data_emit_changed(GOData * dat)291 go_data_emit_changed (GOData *dat)
292 {
293 	GODataClass const *klass = GO_DATA_GET_CLASS (dat);
294 
295 	g_return_if_fail (klass != NULL);
296 
297 	if (klass->emit_changed)
298 		(*klass->emit_changed) (dat);
299 
300 	g_signal_emit (G_OBJECT (dat), go_data_signals [CHANGED], 0);
301 }
302 
303 typedef enum {
304 	GO_DATA_VARIATION_CHECK_INCREASING,
305 	GO_DATA_VARIATION_CHECK_DECREASING,
306 	GO_DATA_VARIATION_CHECK_UNIFORMLY
307 } GODataVariationCheck;
308 
309 static gboolean
go_data_check_variation(GOData * data,GODataVariationCheck check)310 go_data_check_variation (GOData *data, GODataVariationCheck check)
311 {
312 	double *values;
313 	unsigned int n_values;
314 
315 	g_return_val_if_fail (GO_IS_DATA (data), FALSE);
316 
317 	values = go_data_get_values (data);
318 	if (values == NULL)
319 		return FALSE;
320 
321 	n_values = go_data_get_n_values (data);
322 	if (n_values < 1)
323 		return FALSE;
324 
325 	switch (check) {
326 		case GO_DATA_VARIATION_CHECK_UNIFORMLY:
327 			return go_range_vary_uniformly (values, n_values);
328 		case GO_DATA_VARIATION_CHECK_INCREASING:
329 			return go_range_increasing (values, n_values);
330 		default:
331 			return go_range_decreasing (values, n_values);
332 	}
333 }
334 
335 gboolean
go_data_is_increasing(GOData * data)336 go_data_is_increasing (GOData *data)
337 {
338 	return go_data_check_variation (data, GO_DATA_VARIATION_CHECK_INCREASING);
339 }
340 
341 gboolean
go_data_is_decreasing(GOData * data)342 go_data_is_decreasing (GOData *data)
343 {
344 	return go_data_check_variation (data, GO_DATA_VARIATION_CHECK_DECREASING);
345 }
346 
347 gboolean
go_data_is_varying_uniformly(GOData * data)348 go_data_is_varying_uniformly (GOData *data)
349 {
350 	return go_data_check_variation (data, GO_DATA_VARIATION_CHECK_UNIFORMLY);
351 }
352 
353 gboolean
go_data_has_value(GOData const * data)354 go_data_has_value (GOData const *data)
355 {
356 	g_return_val_if_fail (GO_IS_DATA (data), FALSE);
357 	if (!(data->flags & GO_DATA_CACHE_IS_VALID))
358 		go_data_get_values (GO_DATA (data));
359 	return data->flags & GO_DATA_HAS_VALUE;
360 }
361 
362 unsigned int
go_data_get_n_dimensions(GOData * data)363 go_data_get_n_dimensions (GOData *data)
364 {
365 	GODataClass const *data_class;
366 
367 	g_return_val_if_fail (GO_IS_DATA (data), 0);
368 
369 	data_class = GO_DATA_GET_CLASS (data);
370 	g_return_val_if_fail (data_class->get_n_dimensions != NULL, 0);
371 
372 	return data_class->get_n_dimensions (data);
373 }
374 
375 unsigned int
go_data_get_n_values(GOData * data)376 go_data_get_n_values (GOData *data)
377 {
378 	GODataClass const *data_class;
379 	unsigned int n_values;
380 	unsigned int n_dimensions;
381 	unsigned int *sizes;
382 	unsigned int i;
383 
384 	g_return_val_if_fail (GO_IS_DATA (data), 0);
385 
386 	data_class = GO_DATA_GET_CLASS (data);
387 	g_return_val_if_fail (data_class->get_n_dimensions != NULL, 0);
388 
389 	n_dimensions = data_class->get_n_dimensions (data);
390 	if (n_dimensions < 1)
391 		return 1;
392 
393 	sizes = g_newa (unsigned int, n_dimensions);
394 
395 	g_return_val_if_fail (data_class->get_sizes != NULL, 0);
396 
397 	data_class->get_sizes (data, sizes);
398 
399 	n_values = 1;
400 	for (i = 0; i < n_dimensions; i++)
401 		n_values *= sizes[i];
402 
403 	return n_values;
404 }
405 
406 static void
go_data_get_sizes(GOData * data,unsigned int n_dimensions,unsigned int * sizes)407 go_data_get_sizes (GOData *data, unsigned int n_dimensions, unsigned int *sizes)
408 {
409 	GODataClass const *data_class;
410 	unsigned int actual_n_dimensions;
411 
412 	g_return_if_fail (n_dimensions > 0);
413 	g_return_if_fail (sizes != NULL);
414 
415 	data_class = GO_DATA_GET_CLASS (data);
416 
417 	g_return_if_fail (data_class->get_n_dimensions != NULL);
418 
419 	actual_n_dimensions = data_class->get_n_dimensions (data);
420 	if (actual_n_dimensions != n_dimensions) {
421 		unsigned int i;
422 
423 		g_warning ("[GOData::get_sizes] Number of dimension mismatch (requested %d - actual %d)",
424 			   n_dimensions, actual_n_dimensions);
425 
426 		for (i = 0; i < n_dimensions; i++)
427 			sizes[i] = 0;
428 
429 		return;
430 	}
431 
432 	data_class->get_sizes (data, sizes);
433 }
434 
435 unsigned int
go_data_get_vector_size(GOData * data)436 go_data_get_vector_size (GOData *data)
437 {
438 	unsigned int size;
439 
440 	g_return_val_if_fail (GO_IS_DATA (data), 0);
441 
442 	go_data_get_sizes (data, 1, &size);
443 
444 	return size;
445 }
446 
447 void
go_data_get_matrix_size(GOData * data,unsigned int * n_rows,unsigned int * n_columns)448 go_data_get_matrix_size (GOData *data, unsigned int *n_rows, unsigned int *n_columns)
449 {
450 	unsigned int sizes[2];
451 
452 	if (!GO_IS_DATA (data)) {
453 		if (n_columns != NULL)
454 			*n_columns = 0;
455 
456 		if (n_rows != NULL)
457 			*n_rows = 0;
458 
459 		g_return_if_fail (GO_IS_DATA (data));
460 	}
461 
462 	go_data_get_sizes (data, 2, sizes);
463 
464 	if (n_columns != NULL)
465 		*n_columns = sizes[0];
466 
467 	if (n_rows != NULL)
468 		*n_rows = sizes[1];
469 }
470 
471 double *
go_data_get_values(GOData * data)472 go_data_get_values (GOData *data)
473 {
474 	GODataClass const *data_class;
475 
476 	g_return_val_if_fail (GO_IS_DATA (data), NULL);
477 
478 	data_class = GO_DATA_GET_CLASS (data);
479 
480 	g_return_val_if_fail (data_class->get_values != NULL, NULL);
481 
482 	return data_class->get_values (data);
483 }
484 
485 void
go_data_get_bounds(GOData * data,double * minimum,double * maximum)486 go_data_get_bounds (GOData *data, double *minimum, double *maximum)
487 {
488 	GODataClass const *data_class;
489 	double dummy;
490 
491 	g_return_if_fail (GO_IS_DATA (data));
492 	g_return_if_fail (minimum != NULL && maximum != NULL);
493 
494 	if (maximum == NULL)
495 		maximum = &dummy;
496 	else if (minimum == NULL)
497 		minimum = &dummy;
498 
499 	data_class = GO_DATA_GET_CLASS (data);
500 
501 	g_return_if_fail (data_class->get_bounds != NULL);
502 
503 	data_class->get_bounds (data, minimum, maximum);
504 }
505 
506 static double
go_data_get_value(GOData * data,unsigned int n_coordinates,unsigned int * coordinates)507 go_data_get_value (GOData *data, unsigned int n_coordinates, unsigned int *coordinates)
508 {
509 	GODataClass const *data_class;
510 	unsigned int n_dimensions;
511 
512 	g_return_val_if_fail (GO_IS_DATA (data), go_nan);
513 
514 	data_class = GO_DATA_GET_CLASS (data);
515 
516 	n_dimensions = data_class->get_n_dimensions (data);
517 	if (n_dimensions != n_coordinates) {
518 		g_warning ("[GOData::get_value] Wrong number of coordinates (given %d - needed %d)",
519 			   n_coordinates, n_dimensions);
520 
521 		return go_nan;
522 	}
523 
524 	return data_class->get_value (data, coordinates);
525 }
526 
527 double
go_data_get_scalar_value(GOData * data)528 go_data_get_scalar_value (GOData *data)
529 {
530 	return go_data_get_value (data, 0, NULL);
531 }
532 
533 double
go_data_get_vector_value(GOData * data,unsigned int column)534 go_data_get_vector_value (GOData *data, unsigned int column)
535 {
536 	return go_data_get_value (data, 1, &column);
537 }
538 
539 double
go_data_get_matrix_value(GOData * data,unsigned int row,unsigned int column)540 go_data_get_matrix_value (GOData *data, unsigned int row, unsigned int column)
541 {
542 	unsigned int coordinates[2];
543 
544 	coordinates[0] = column;
545 	coordinates[1] = row;
546 
547 	return go_data_get_value (data, 2, coordinates);
548 }
549 
550 static char *
go_data_get_string(GOData * data,unsigned int n_coordinates,unsigned int * coordinates)551 go_data_get_string (GOData *data, unsigned int n_coordinates, unsigned int *coordinates)
552 {
553 	GODataClass const *data_class;
554 	unsigned int n_dimensions;
555 
556 	g_return_val_if_fail (GO_IS_DATA (data), NULL);
557 
558 	data_class = GO_DATA_GET_CLASS (data);
559 
560 	n_dimensions = data_class->get_n_dimensions (data);
561 	if (n_dimensions != n_coordinates) {
562 		g_warning ("[GOData::get_string] Wrong number of coordinates (given %d - needed %d)",
563 			   n_coordinates, n_dimensions);
564 
565 		return NULL;
566 	}
567 
568 	return data_class->get_string (data, coordinates);
569 }
570 
571 char *
go_data_get_scalar_string(GOData * data)572 go_data_get_scalar_string (GOData *data)
573 {
574 	return go_data_get_string (data, 0, NULL);
575 }
576 
577 char *
go_data_get_vector_string(GOData * data,unsigned int column)578 go_data_get_vector_string (GOData *data, unsigned int column)
579 {
580 	return go_data_get_string (data, 1, &column);
581 }
582 
583 char *
go_data_get_matrix_string(GOData * data,unsigned int row,unsigned int column)584 go_data_get_matrix_string (GOData *data, unsigned int row, unsigned int column)
585 {
586 	unsigned int coordinates[2];
587 
588 	coordinates[0] = column;
589 	coordinates[1] = row;
590 
591 	return go_data_get_string (data, 2, coordinates);
592 }
593 
594 static PangoAttrList *
go_data_get_markup(GOData * data,unsigned int n_coordinates,unsigned int * coordinates)595 go_data_get_markup (GOData *data, unsigned int n_coordinates, unsigned int *coordinates)
596 {
597 	GODataClass const *data_class;
598 	unsigned int n_dimensions;
599 
600 	g_return_val_if_fail (GO_IS_DATA (data), NULL);
601 
602 	data_class = GO_DATA_GET_CLASS (data);
603 
604 	n_dimensions = data_class->get_n_dimensions (data);
605 	if (n_dimensions != n_coordinates) {
606 		g_warning ("[GOData::get_markup] Wrong number of coordinates (given %d - needed %d)",
607 			   n_coordinates, n_dimensions);
608 
609 		return NULL;
610 	}
611 
612 	return (data_class->get_markup)? data_class->get_markup (data, coordinates): NULL;
613 }
614 
615 PangoAttrList *
go_data_get_scalar_markup(GOData * data)616 go_data_get_scalar_markup (GOData *data)
617 {
618 	return go_data_get_markup (data, 0, NULL);
619 }
620 
621 PangoAttrList *
go_data_get_vector_markup(GOData * data,unsigned int column)622 go_data_get_vector_markup (GOData *data, unsigned int column)
623 {
624 	return go_data_get_markup (data, 1, &column);
625 }
626 
627 PangoAttrList *
go_data_get_matrix_markup(GOData * data,unsigned int row,unsigned int column)628 go_data_get_matrix_markup (GOData *data, unsigned int row, unsigned int column)
629 {
630 	unsigned int coordinates[2];
631 
632 	coordinates[0] = column;
633 	coordinates[1] = row;
634 
635 	return go_data_get_markup (data, 2, coordinates);
636 }
637 
638 /*************************************************************************/
639 
640 #define GO_DATA_SCALAR_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST ((k), GO_TYPE_DATA_SCALAR, GODataScalarClass))
641 #define GO_IS_DATA_SCALAR_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GO_TYPE_DATA_SCALAR))
642 #define GO_DATA_SCALAR_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GO_TYPE_DATA_SCALAR, GODataScalarClass))
643 
644 static unsigned int
_data_scalar_get_n_dimensions(GOData * data)645 _data_scalar_get_n_dimensions (GOData *data)
646 {
647 	return 0;
648 }
649 
650 static double *
_data_scalar_get_values(GOData * data)651 _data_scalar_get_values (GOData *data)
652 {
653 	GODataScalar *scalar = (GODataScalar *) data;
654 
655 	go_data_scalar_get_value (scalar);
656 
657 	return &scalar->value;
658 }
659 
660 static void
_data_scalar_get_bounds(GOData * data,double * minimum,double * maximum)661 _data_scalar_get_bounds (GOData *data, double *minimum, double *maximum)
662 {
663 	GODataScalar *scalar = (GODataScalar *) data;
664 
665 	go_data_scalar_get_value (scalar);
666 
667 	*minimum = scalar->value;
668 	*maximum = scalar->value;
669 }
670 
671 static double
_data_scalar_get_value(GOData * data,unsigned int * coordinates)672 _data_scalar_get_value (GOData *data, unsigned int *coordinates)
673 {
674 	return go_data_scalar_get_value ((GODataScalar *) data);
675 }
676 
677 static char *
_data_scalar_get_string(GOData * data,unsigned int * coordinates)678 _data_scalar_get_string (GOData *data, unsigned int *coordinates)
679 {
680 	return g_strdup (go_data_scalar_get_str ((GODataScalar *) data));
681 }
682 
683 static PangoAttrList *
_data_scalar_get_markup(GOData * data,unsigned int * coordinates)684 _data_scalar_get_markup (GOData *data, unsigned int *coordinates)
685 {
686 	return pango_attr_list_copy ((PangoAttrList *) go_data_scalar_get_markup ((GODataScalar *) data));
687 }
688 
689 static void
go_data_scalar_class_init(GODataClass * data_class)690 go_data_scalar_class_init (GODataClass *data_class)
691 {
692 	data_class->get_n_dimensions = 	_data_scalar_get_n_dimensions;
693 	data_class->get_values =	_data_scalar_get_values;
694 	data_class->get_bounds =	_data_scalar_get_bounds;
695 	data_class->get_value =		_data_scalar_get_value;
696 	data_class->get_string =	_data_scalar_get_string;
697 	data_class->get_markup =	_data_scalar_get_markup;
698 }
699 
GSF_CLASS_ABSTRACT(GODataScalar,go_data_scalar,go_data_scalar_class_init,NULL,GO_TYPE_DATA)700 GSF_CLASS_ABSTRACT (GODataScalar, go_data_scalar,
701 		    go_data_scalar_class_init, NULL,
702 		    GO_TYPE_DATA)
703 
704 double
705 go_data_scalar_get_value (GODataScalar *scalar)
706 {
707 	GODataScalarClass const *klass = GO_DATA_SCALAR_GET_CLASS (scalar);
708 	g_return_val_if_fail (klass != NULL, 0.); /* TODO : make this a nan */
709 	scalar->value = (*klass->get_value) (scalar);
710 
711 	return scalar->value;
712 }
713 
714 char const *
go_data_scalar_get_str(GODataScalar * scalar)715 go_data_scalar_get_str (GODataScalar *scalar)
716 {
717 	GODataScalarClass const *klass = GO_DATA_SCALAR_GET_CLASS (scalar);
718 	g_return_val_if_fail (klass != NULL, "");
719 	return (*klass->get_str) (scalar);
720 }
721 
722 PangoAttrList const *
go_data_scalar_get_markup(GODataScalar * scalar)723 go_data_scalar_get_markup (GODataScalar *scalar)
724 {
725 	GODataScalarClass const *klass = GO_DATA_SCALAR_GET_CLASS (scalar);
726 	g_return_val_if_fail (klass != NULL, NULL);
727 	return (klass->get_markup)? (*klass->get_markup) (scalar): NULL;
728 }
729 
730 /*************************************************************************/
731 
732 #define GO_DATA_VECTOR_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST ((k), GO_TYPE_DATA_VECTOR, GODataVectorClass))
733 #define GO_IS_DATA_VECTOR_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GO_TYPE_DATA_VECTOR))
734 #define GO_DATA_VECTOR_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GO_TYPE_DATA_VECTOR, GODataVectorClass))
735 
736 static void
_data_vector_emit_changed(GOData * data)737 _data_vector_emit_changed (GOData *data)
738 {
739 	data->flags &= ~(GO_DATA_CACHE_IS_VALID | GO_DATA_VECTOR_LEN_CACHED | GO_DATA_HAS_VALUE);
740 }
741 
742 static unsigned int
_data_vector_get_n_dimensions(GOData * data)743 _data_vector_get_n_dimensions (GOData *data)
744 {
745 	return 1;
746 }
747 
748 static void
_data_vector_get_sizes(GOData * data,unsigned int * sizes)749 _data_vector_get_sizes (GOData *data, unsigned int *sizes)
750 {
751 	GODataVector *vector = (GODataVector *) data;
752 
753 	sizes[0] = go_data_vector_get_len (vector);
754 }
755 
756 static double *
_data_vector_get_values(GOData * data)757 _data_vector_get_values (GOData *data)
758 {
759 	return go_data_vector_get_values ((GODataVector *) data);
760 }
761 
762 static void
_data_vector_get_bounds(GOData * data,double * minimum,double * maximum)763 _data_vector_get_bounds (GOData *data, double *minimum, double *maximum)
764 {
765 	go_data_vector_get_minmax ((GODataVector *) data, minimum, maximum);
766 }
767 
768 static double
_data_vector_get_value(GOData * data,unsigned int * coordinates)769 _data_vector_get_value (GOData *data, unsigned int *coordinates)
770 {
771 	return go_data_vector_get_value ((GODataVector *) data, coordinates[0]);
772 }
773 
774 static char *
_data_vector_get_string(GOData * data,unsigned int * coordinates)775 _data_vector_get_string (GOData *data, unsigned int *coordinates)
776 {
777 	return go_data_vector_get_str ((GODataVector *) data, coordinates[0]);
778 }
779 
780 static PangoAttrList *
_data_vector_get_markup(GOData * data,unsigned int * coordinates)781 _data_vector_get_markup (GOData *data, unsigned int *coordinates)
782 {
783 	return go_data_vector_get_markup ((GODataVector *) data, coordinates[0]);
784 }
785 
786 static void
go_data_vector_class_init(GODataClass * data_class)787 go_data_vector_class_init (GODataClass *data_class)
788 {
789 	data_class->emit_changed = 	_data_vector_emit_changed;
790 	data_class->get_n_dimensions = 	_data_vector_get_n_dimensions;
791 	data_class->get_sizes =		_data_vector_get_sizes;
792 	data_class->get_values =	_data_vector_get_values;
793 	data_class->get_bounds =	_data_vector_get_bounds;
794 	data_class->get_value =		_data_vector_get_value;
795 	data_class->get_string =	_data_vector_get_string;
796 	data_class->get_markup =	_data_vector_get_markup;
797 }
798 
GSF_CLASS_ABSTRACT(GODataVector,go_data_vector,go_data_vector_class_init,NULL,GO_TYPE_DATA)799 GSF_CLASS_ABSTRACT (GODataVector, go_data_vector,
800 		    go_data_vector_class_init, NULL,
801 		    GO_TYPE_DATA)
802 
803 int
804 go_data_vector_get_len (GODataVector *vec)
805 {
806 	if (!vec)
807 		return 0;
808 	if (! (vec->base.flags & GO_DATA_VECTOR_LEN_CACHED)) {
809 		GODataVectorClass const *klass = GO_DATA_VECTOR_GET_CLASS (vec);
810 
811 		g_return_val_if_fail (klass != NULL, 0);
812 
813 		(*klass->load_len) (vec);
814 
815 		g_return_val_if_fail (vec->base.flags & GO_DATA_VECTOR_LEN_CACHED, 0);
816 	}
817 
818 	return vec->len;
819 }
820 
821 double *
go_data_vector_get_values(GODataVector * vec)822 go_data_vector_get_values (GODataVector *vec)
823 {
824 	if (! (vec->base.flags & GO_DATA_CACHE_IS_VALID)) {
825 		GODataVectorClass const *klass = GO_DATA_VECTOR_GET_CLASS (vec);
826 
827 		g_return_val_if_fail (klass != NULL, NULL);
828 
829 		(*klass->load_values) (vec);
830 
831 		{
832 			double min, max;
833 			go_data_get_bounds (&vec->base, &min, &max);
834 			if (go_finite (min) && go_finite (max) && min <= max)
835 				vec->base.flags |= GO_DATA_HAS_VALUE;
836 
837 		}
838 
839 		g_return_val_if_fail (vec->base.flags & GO_DATA_CACHE_IS_VALID, NULL);
840 	}
841 
842 	return vec->values;
843 }
844 
845 double
go_data_vector_get_value(GODataVector * vec,unsigned i)846 go_data_vector_get_value (GODataVector *vec, unsigned i)
847 {
848 	if (! (vec->base.flags & GO_DATA_CACHE_IS_VALID)) {
849 		GODataVectorClass const *klass = GO_DATA_VECTOR_GET_CLASS (vec);
850 		g_return_val_if_fail (klass != NULL, go_nan);
851 		return (*klass->get_value) (vec, i);
852 	}
853 
854 	g_return_val_if_fail ((int)i < vec->len, go_nan);
855 	return vec->values [i];
856 }
857 
858 char *
go_data_vector_get_str(GODataVector * vec,unsigned i)859 go_data_vector_get_str (GODataVector *vec, unsigned i)
860 {
861 	GODataVectorClass const *klass = GO_DATA_VECTOR_GET_CLASS (vec);
862 	char *res;
863 
864 	g_return_val_if_fail (klass != NULL, g_strdup (""));
865 	if (! (vec->base.flags & GO_DATA_VECTOR_LEN_CACHED)) {
866 		(*klass->load_len) (vec);
867 		g_return_val_if_fail (vec->base.flags & GO_DATA_VECTOR_LEN_CACHED, g_strdup (""));
868 	}
869 	g_return_val_if_fail ((int)i < vec->len, g_strdup (""));
870 
871 	res = (*klass->get_str) (vec, i);
872 	if (res == NULL)
873 		return g_strdup ("");
874 	return res;
875 }
876 
877 PangoAttrList *
go_data_vector_get_markup(GODataVector * vec,unsigned i)878 go_data_vector_get_markup (GODataVector *vec, unsigned i)
879 {
880 	GODataVectorClass const *klass = GO_DATA_VECTOR_GET_CLASS (vec);
881 
882 	g_return_val_if_fail (klass != NULL, NULL);
883 	if (! (vec->base.flags & GO_DATA_VECTOR_LEN_CACHED)) {
884 		(*klass->load_len) (vec);
885 		g_return_val_if_fail (vec->base.flags & GO_DATA_VECTOR_LEN_CACHED, NULL);
886 	}
887 	g_return_val_if_fail ((int)i < vec->len, NULL);
888 
889 	return (klass->get_markup)? (*klass->get_markup) (vec, i): NULL;
890 }
891 
892 void
go_data_vector_get_minmax(GODataVector * vec,double * min,double * max)893 go_data_vector_get_minmax (GODataVector *vec, double *min, double *max)
894 {
895 	if (! (vec->base.flags & GO_DATA_CACHE_IS_VALID)) {
896 		GODataVectorClass const *klass = GO_DATA_VECTOR_GET_CLASS (vec);
897 
898 		g_return_if_fail (klass != NULL);
899 
900 		(*klass->load_values) (vec);
901 
902 		g_return_if_fail (vec->base.flags & GO_DATA_CACHE_IS_VALID);
903 	}
904 
905 	if (min != NULL)
906 		*min = vec->minimum;
907 	if (max != NULL)
908 		*max = vec->maximum;
909 }
910 
911 gboolean
go_data_vector_increasing(GODataVector * vec)912 go_data_vector_increasing (GODataVector *vec)
913 {
914 	double *data = go_data_vector_get_values (vec);
915 	int length = go_data_vector_get_len (vec);
916 	return go_range_increasing (data, length);
917 }
918 
919 gboolean
go_data_vector_decreasing(GODataVector * vec)920 go_data_vector_decreasing (GODataVector *vec)
921 {
922 	double *data = go_data_vector_get_values (vec);
923 	int length = go_data_vector_get_len (vec);
924 	return go_range_decreasing (data, length);
925 }
926 
927 gboolean
go_data_vector_vary_uniformly(GODataVector * vec)928 go_data_vector_vary_uniformly (GODataVector *vec)
929 {
930 	double *data = go_data_vector_get_values (vec);
931 	int length = go_data_vector_get_len (vec);
932 	return go_range_vary_uniformly (data, length);
933 }
934 
935 /*************************************************************************/
936 
937 #define GO_DATA_MATRIX_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST ((k), GO_TYPE_DATA_MATRIX, GODataMatrixClass))
938 #define GO_IS_DATA_MATRIX_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GO_TYPE_DATA_MATRIX))
939 #define GO_DATA_MATRIX_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GO_TYPE_DATA_MATRIX, GODataMatrixClass))
940 
941 static void
_data_matrix_emit_changed(GOData * data)942 _data_matrix_emit_changed (GOData *data)
943 {
944 	data->flags &= ~(GO_DATA_CACHE_IS_VALID | GO_DATA_MATRIX_SIZE_CACHED | GO_DATA_HAS_VALUE);
945 }
946 
947 static unsigned int
_data_matrix_get_n_dimensions(GOData * data)948 _data_matrix_get_n_dimensions (GOData *data)
949 {
950 	return 2;
951 }
952 
953 static void
_data_matrix_get_sizes(GOData * data,unsigned int * sizes)954 _data_matrix_get_sizes (GOData *data, unsigned int *sizes)
955 {
956 	GODataMatrix *matrix = (GODataMatrix *) data;
957 	GODataMatrixSize size;
958 
959 	size = go_data_matrix_get_size (matrix);
960 
961 	sizes[0] = size.columns;
962 	sizes[1] = size.rows;
963 }
964 
965 static double *
_data_matrix_get_values(GOData * data)966 _data_matrix_get_values (GOData *data)
967 {
968 	return go_data_matrix_get_values ((GODataMatrix *) data);
969 }
970 
971 static void
_data_matrix_get_bounds(GOData * data,double * minimum,double * maximum)972 _data_matrix_get_bounds (GOData *data, double *minimum, double *maximum)
973 {
974 	go_data_matrix_get_minmax ((GODataMatrix *) data, minimum, maximum);
975 }
976 
977 static double
_data_matrix_get_value(GOData * data,unsigned int * coordinates)978 _data_matrix_get_value (GOData *data, unsigned int *coordinates)
979 {
980 	return go_data_matrix_get_value ((GODataMatrix *) data, coordinates[1], coordinates[0]);
981 }
982 
983 static char *
_data_matrix_get_string(GOData * data,unsigned int * coordinates)984 _data_matrix_get_string (GOData *data, unsigned int *coordinates)
985 {
986 	return go_data_matrix_get_str ((GODataMatrix *) data, coordinates[1], coordinates[0]);
987 }
988 
989 static PangoAttrList *
_data_matrix_get_markup(GOData * data,unsigned int * coordinates)990 _data_matrix_get_markup (GOData *data, unsigned int *coordinates)
991 {
992 	return go_data_matrix_get_markup ((GODataMatrix *) data, coordinates[1], coordinates[0]);
993 }
994 
995 static void
go_data_matrix_class_init(GODataClass * data_class)996 go_data_matrix_class_init (GODataClass *data_class)
997 {
998 	data_class->emit_changed = 	_data_matrix_emit_changed;
999 	data_class->get_n_dimensions = 	_data_matrix_get_n_dimensions;
1000 	data_class->get_sizes =		_data_matrix_get_sizes;
1001 	data_class->get_values =	_data_matrix_get_values;
1002 	data_class->get_bounds =	_data_matrix_get_bounds;
1003 	data_class->get_value =		_data_matrix_get_value;
1004 	data_class->get_string =	_data_matrix_get_string;
1005 	data_class->get_markup =	_data_matrix_get_markup;
1006 }
1007 
GSF_CLASS_ABSTRACT(GODataMatrix,go_data_matrix,go_data_matrix_class_init,NULL,GO_TYPE_DATA)1008 GSF_CLASS_ABSTRACT (GODataMatrix, go_data_matrix,
1009 		    go_data_matrix_class_init, NULL,
1010 		    GO_TYPE_DATA)
1011 
1012 /**
1013  * go_data_matrix_get_size: (skip)
1014  * @mat: #GODataMatrix
1015  *
1016  * Returns: the matrix size
1017  **/
1018 GODataMatrixSize
1019 go_data_matrix_get_size (GODataMatrix *mat)
1020 {
1021 	static GODataMatrixSize null_size = {0, 0};
1022 	if (!mat)
1023 		return null_size;
1024 	if (! (mat->base.flags & GO_DATA_MATRIX_SIZE_CACHED)) {
1025 		GODataMatrixClass const *klass = GO_DATA_MATRIX_GET_CLASS (mat);
1026 
1027 		g_return_val_if_fail (klass != NULL, null_size);
1028 
1029 		(*klass->load_size) (mat);
1030 
1031 		g_return_val_if_fail (mat->base.flags & GO_DATA_MATRIX_SIZE_CACHED, null_size);
1032 	}
1033 
1034 	return mat->size;
1035 }
1036 
1037 int
go_data_matrix_get_rows(GODataMatrix * mat)1038 go_data_matrix_get_rows (GODataMatrix *mat)
1039 {
1040 	if (!mat)
1041 		return 0;
1042 	if (! (mat->base.flags & GO_DATA_MATRIX_SIZE_CACHED)) {
1043 		GODataMatrixClass const *klass = GO_DATA_MATRIX_GET_CLASS (mat);
1044 
1045 		g_return_val_if_fail (klass != NULL, 0);
1046 
1047 		(*klass->load_size) (mat);
1048 
1049 		g_return_val_if_fail (mat->base.flags & GO_DATA_MATRIX_SIZE_CACHED, 0);
1050 	}
1051 
1052 	return mat->size.rows;
1053 }
1054 
1055 int
go_data_matrix_get_columns(GODataMatrix * mat)1056 go_data_matrix_get_columns (GODataMatrix *mat)
1057 {
1058 	if (!mat)
1059 		return 0;
1060 	if (! (mat->base.flags & GO_DATA_MATRIX_SIZE_CACHED)) {
1061 		GODataMatrixClass const *klass = GO_DATA_MATRIX_GET_CLASS (mat);
1062 
1063 		g_return_val_if_fail (klass != NULL, 0);
1064 
1065 		(*klass->load_size) (mat);
1066 
1067 		g_return_val_if_fail (mat->base.flags & GO_DATA_MATRIX_SIZE_CACHED, 0);
1068 	}
1069 
1070 	return mat->size.columns;
1071 }
1072 
1073 double *
go_data_matrix_get_values(GODataMatrix * mat)1074 go_data_matrix_get_values (GODataMatrix *mat)
1075 {
1076 	if (! (mat->base.flags & GO_DATA_CACHE_IS_VALID)) {
1077 		GODataMatrixClass const *klass = GO_DATA_MATRIX_GET_CLASS (mat);
1078 
1079 		g_return_val_if_fail (klass != NULL, NULL);
1080 
1081 		(*klass->load_values) (mat);
1082 
1083 		{
1084 			double min, max;
1085 			go_data_get_bounds (&mat->base, &min, &max);
1086 			if (go_finite (min) && go_finite (max) && min <= max)
1087 				mat->base.flags |= GO_DATA_HAS_VALUE;
1088 		}
1089 
1090 		g_return_val_if_fail (mat->base.flags & GO_DATA_CACHE_IS_VALID, NULL);
1091 	}
1092 
1093 	return mat->values;
1094 }
1095 
1096 double
go_data_matrix_get_value(GODataMatrix * mat,unsigned i,unsigned j)1097 go_data_matrix_get_value (GODataMatrix *mat, unsigned i, unsigned j)
1098 {
1099 	g_return_val_if_fail (((int)i < mat->size.rows) && ((int)j < mat->size.columns), go_nan);
1100 	if (! (mat->base.flags & GO_DATA_CACHE_IS_VALID)) {
1101 		GODataMatrixClass const *klass = GO_DATA_MATRIX_GET_CLASS (mat);
1102 		g_return_val_if_fail (klass != NULL, go_nan);
1103 		return (*klass->get_value) (mat, i, j);
1104 	}
1105 
1106 	return mat->values[i * mat->size.columns + j];
1107 }
1108 
1109 char *
go_data_matrix_get_str(GODataMatrix * mat,unsigned i,unsigned j)1110 go_data_matrix_get_str (GODataMatrix *mat, unsigned i, unsigned j)
1111 {
1112 	GODataMatrixClass const *klass = GO_DATA_MATRIX_GET_CLASS (mat);
1113 	char *res;
1114 
1115 	g_return_val_if_fail (klass != NULL, g_strdup (""));
1116 	if (! (mat->base.flags & GO_DATA_MATRIX_SIZE_CACHED)) {
1117 		(*klass->load_size) (mat);
1118 		g_return_val_if_fail (mat->base.flags & GO_DATA_MATRIX_SIZE_CACHED, g_strdup (""));
1119 	}
1120 	g_return_val_if_fail (((int)i < mat->size.rows) && ((int)j < mat->size.columns), g_strdup (""));
1121 
1122 	res = (*klass->get_str) (mat, i, j);
1123 	if (res == NULL)
1124 		return g_strdup ("");
1125 	return res;
1126 }
1127 
1128 PangoAttrList *
go_data_matrix_get_markup(GODataMatrix * mat,unsigned i,unsigned j)1129 go_data_matrix_get_markup (GODataMatrix *mat, unsigned i, unsigned j)
1130 {
1131 	GODataMatrixClass const *klass = GO_DATA_MATRIX_GET_CLASS (mat);
1132 
1133 	g_return_val_if_fail (klass != NULL, NULL);
1134 	if (! (mat->base.flags & GO_DATA_MATRIX_SIZE_CACHED)) {
1135 		(*klass->load_size) (mat);
1136 		g_return_val_if_fail (mat->base.flags & GO_DATA_MATRIX_SIZE_CACHED, NULL);
1137 	}
1138 	g_return_val_if_fail (((int)i < mat->size.rows) && ((int)j < mat->size.columns), NULL);
1139 
1140 	return (klass->get_markup)? (*klass->get_markup) (mat, i, j): NULL;
1141 }
1142 
1143 void
go_data_matrix_get_minmax(GODataMatrix * mat,double * min,double * max)1144 go_data_matrix_get_minmax (GODataMatrix *mat, double *min, double *max)
1145 {
1146 	if (! (mat->base.flags & GO_DATA_CACHE_IS_VALID)) {
1147 		GODataMatrixClass const *klass = GO_DATA_MATRIX_GET_CLASS (mat);
1148 
1149 		g_return_if_fail (klass != NULL);
1150 
1151 		(*klass->load_values) (mat);
1152 
1153 		g_return_if_fail (mat->base.flags & GO_DATA_CACHE_IS_VALID);
1154 	}
1155 
1156 	if (min != NULL)
1157 		*min = mat->minimum;
1158 	if (max != NULL)
1159 		*max = mat->maximum;
1160 }
1161