1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * graph.c: The gnumeric specific data wrappers for GOffice
5 * Copyright (C) 2003-2005 Jody Goldberg (jody@gnome.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) version 3.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 #include <gnumeric-config.h>
24 #include "dependent.h"
28 #include "number-match.h"
33 #include "gnm-format.h"
34 #include "auto-format.h"
36 #include "parse-util.h"
37 #include "expr-impl.h"
38 #include <goffice/goffice.h>
40 #include <gsf/gsf-impl-utils.h>
43 /* ------------------------------------------------------------------------- */
46 get_pending_str (const GOData
*data
)
48 return g_object_get_data (G_OBJECT (data
), "unserialize");
51 static GnmConventions
*
52 get_pending_convs (const GOData
*data
)
54 return g_object_get_data (G_OBJECT (data
), "unserialize-convs");
58 set_pending_str (const GOData
*data
, const char *str
)
60 g_object_set_data_full (G_OBJECT (data
),
61 "unserialize", g_strdup (str
),
66 set_pending_convs (GOData
*data
, const GnmConventions
*convs
)
68 g_object_set_data_full (G_OBJECT (data
),
70 gnm_conventions_ref ((gpointer
)convs
),
71 (GDestroyNotify
)gnm_conventions_unref
);
74 /* ------------------------------------------------------------------------- */
77 render_val (GnmValue
const *v
, int i
, int j
,
78 GOFormat
const *fmt
, GnmEvalPos
const *ep
)
80 GODateConventions
const *date_conv
;
85 date_conv
= ep
->sheet
? workbook_date_conv (ep
->sheet
->workbook
) : NULL
;
88 g_printerr ("Rendering %s with fmt=%s\n",
89 value_peek_string (v
),
90 fmt
? go_format_as_XL (fmt
) : "-");
93 if (VALUE_IS_CELLRANGE (v
)) {
94 Sheet
*start_sheet
, *end_sheet
;
98 gnm_rangeref_normalize (&v
->v_range
.cell
, ep
,
99 &start_sheet
, &end_sheet
, &r
);
102 cell
= sheet_cell_get (start_sheet
, r
.start
.col
, r
.start
.row
);
105 gnm_cell_eval (cell
);
109 fmt
= gnm_cell_get_format (cell
);
110 } else if (VALUE_IS_ARRAY (v
))
111 v
= value_area_get_x_y (v
, i
, j
, ep
);
113 return format_value (fmt
, v
, -1, date_conv
);
116 /* ------------------------------------------------------------------------- */
118 static GnmDependent
*gnm_go_data_get_dep (GOData
const *obj
);
121 gnm_go_data_dup (GOData
const *src
)
123 GOData
*dst
= g_object_new (G_OBJECT_TYPE (src
), NULL
);
124 GnmDependent
const *src_dep
= gnm_go_data_get_dep (src
);
125 GnmDependent
*dst_dep
= gnm_go_data_get_dep (dst
);
127 dst_dep
->texpr
= src_dep
->texpr
;
129 gnm_expr_top_ref (dst_dep
->texpr
);
132 dependent_set_sheet (dst_dep
, src_dep
->sheet
);
134 if (dst_dep
->texpr
== NULL
) {
135 set_pending_str (dst
, get_pending_str (src
));
136 set_pending_convs (dst
, get_pending_convs (src
));
139 return GO_DATA (dst
);
143 gnm_go_data_eq (GOData
const *data_a
, GOData
const *data_b
)
145 GnmDependent
const *a
= gnm_go_data_get_dep (data_a
);
146 GnmDependent
const *b
= gnm_go_data_get_dep (data_b
);
148 if (a
->texpr
== NULL
&& b
->texpr
== NULL
) {
149 if (go_str_compare (get_pending_str (data_a
),
150 get_pending_str (data_b
)))
152 if (get_pending_convs (data_a
) != get_pending_convs (data_b
))
157 return a
->texpr
&& b
->texpr
&& gnm_expr_top_equal (a
->texpr
, b
->texpr
);
161 gnm_go_data_preferred_fmt (GOData
const *dat
)
164 GnmDependent
const *dep
= gnm_go_data_get_dep (dat
);
166 g_return_val_if_fail (dep
!= NULL
, NULL
);
168 eval_pos_init_dep (&ep
, dep
);
170 ? (GOFormat
*)gnm_auto_style_format_suggest (dep
->texpr
, &ep
)
174 static GODateConventions
const *
175 gnm_go_data_date_conv (GOData
const *dat
)
177 GnmDependent
const *dep
= gnm_go_data_get_dep (dat
);
179 g_return_val_if_fail (dep
!= NULL
, NULL
);
184 return workbook_date_conv (dep
->sheet
->workbook
);
188 gnm_go_data_serialize (GOData
const *dat
, gpointer user
)
191 GnmConventions
const *convs
= user
;
192 GnmDependent
const *dep
= gnm_go_data_get_dep (dat
);
194 if (dep
->sheet
== NULL
)
195 return g_strdup ("No sheet for GnmGOData");
197 g_warning ("NULL convs in gnm_go_data_serialize");
198 convs
= gnm_conventions_default
;
201 res
= gnm_expr_top_as_string (dep
->texpr
,
202 parse_pos_init_dep (&pp
, dep
),
205 g_printerr ("Serializing %s\n", res
);
211 gnm_go_data_unserialize (GOData
*dat
, char const *str
, gpointer user
)
213 GnmConventions
const *convs
= user
;
214 GnmExprTop
const *texpr
;
216 GnmDependent
*dep
= gnm_go_data_get_dep (dat
);
219 g_warning ("NULL convs in gnm_go_data_serialize");
220 convs
= gnm_conventions_default
;
223 /* It is too early in the life cycle to know where we
224 * are. Wait until later when we parse the sheet */
225 if (dep
->sheet
== NULL
) {
226 set_pending_str (dat
, str
);
227 /* Ugh. We assume that convs will stay valid. */
228 set_pending_convs (dat
, convs
);
232 parse_pos_init_dep (&pp
, dep
);
233 texpr
= gnm_expr_parse_str (str
, &pp
, (GO_IS_DATA_VECTOR (dat
))?
234 GNM_EXPR_PARSE_PERMIT_MULTIPLE_EXPRESSIONS
:
235 GNM_EXPR_PARSE_DEFAULT
,
238 dependent_set_expr (dep
, texpr
);
239 gnm_expr_top_unref (texpr
);
246 gnm_go_data_set_sheet (GOData
*dat
, Sheet
*sheet
)
248 GnmDependent
*dep
= gnm_go_data_get_dep (dat
);
253 if (dependent_is_linked (dep
)) {
254 dependent_unlink (dep
);
262 * Do we need to parse one now that we have more context ? */
263 if (dep
->texpr
== NULL
) {
264 char const *str
= get_pending_str (dat
);
265 GnmConventions
*convs
= get_pending_convs (dat
);
266 if (str
!= NULL
) { /* bingo */
267 dep
->sheet
= sheet
; /* cheat a bit */
268 if (gnm_go_data_unserialize (dat
, str
, convs
)) {
269 set_pending_str (dat
, NULL
);
270 set_pending_convs (dat
, NULL
);
271 go_data_emit_changed (GO_DATA (dat
));
277 dependent_set_sheet (dep
, sheet
);
281 * gnm_go_data_get_sheet:
284 * Returns: (transfer none): the sheet.
287 gnm_go_data_get_sheet (GOData
const *dat
)
289 GnmDependent
*dep
= gnm_go_data_get_dep (dat
);
290 g_return_val_if_fail (dep
!= NULL
, NULL
);
295 gnm_go_data_get_expr (GOData
const *dat
)
297 GnmDependent
*dep
= gnm_go_data_get_dep (dat
);
304 * gnm_go_data_foreach_dep:
307 * @func: (scope call):
312 gnm_go_data_foreach_dep (GOData
*dat
, SheetObject
*so
,
313 SheetObjectForeachDepFunc func
, gpointer user
)
315 GnmDependent
*dep
= gnm_go_data_get_dep (dat
);
317 func (dep
, so
, user
);
320 /**************************************************************************/
322 struct _GnmGODataScalar
{
328 typedef GODataScalarClass GnmGODataScalarClass
;
330 #define DEP_TO_SCALAR(d_ptr) (GnmGODataScalar *)(((char *)d_ptr) - G_STRUCT_OFFSET (GnmGODataScalar, dep))
332 static GObjectClass
*scalar_parent_klass
;
335 scalar_get_val (GnmGODataScalar
*scalar
)
337 if (scalar
->val
!= NULL
) {
338 value_release (scalar
->val
);
340 g_free (scalar
->val_str
);
341 scalar
->val_str
= NULL
;
343 if (scalar
->val
== NULL
) {
344 if (scalar
->dep
.texpr
!= NULL
) {
347 eval_pos_init_dep (&pos
, &scalar
->dep
);
349 scalar
->val
= gnm_expr_top_eval
350 (scalar
->dep
.texpr
, &pos
,
351 GNM_EXPR_EVAL_PERMIT_EMPTY
);
353 scalar
->val
= value_new_empty ();
359 gnm_go_data_scalar_eval (GnmDependent
*dep
)
361 GnmGODataScalar
*scalar
= DEP_TO_SCALAR (dep
);
363 value_release (scalar
->val
);
365 g_free (scalar
->val_str
);
366 scalar
->val_str
= NULL
;
367 go_data_emit_changed (GO_DATA (scalar
));
371 gnm_go_data_scalar_finalize (GObject
*obj
)
373 GnmGODataScalar
*scalar
= (GnmGODataScalar
*)obj
;
375 dependent_set_expr (&scalar
->dep
, NULL
);
376 value_release (scalar
->val
);
378 g_free (scalar
->val_str
);
379 scalar
->val_str
= NULL
;
381 scalar_parent_klass
->finalize (obj
);
385 gnm_go_data_scalar_get_value (GODataScalar
*dat
)
387 return value_get_as_float (scalar_get_val ((GnmGODataScalar
*)dat
));
391 gnm_go_data_scalar_get_str (GODataScalar
*dat
)
393 GnmGODataScalar
*scalar
= (GnmGODataScalar
*)dat
;
394 GOFormat
const *fmt
= NULL
;
396 if (scalar
->val_str
== NULL
) {
399 eval_pos_init_dep (&ep
, &scalar
->dep
);
400 if (scalar
->dep
.texpr
)
401 fmt
= gnm_auto_style_format_suggest (scalar
->dep
.texpr
, &ep
);
403 render_val (scalar_get_val (scalar
), 0, 0, fmt
, &ep
);
405 go_format_unref (fmt
);
406 return scalar
->val_str
;
409 static PangoAttrList
const *
410 gnm_go_data_scalar_get_markup (GODataScalar
*dat
)
412 PangoAttrList
const *res
= NULL
;
413 GOFormat
const *fmt
= gnm_go_data_preferred_fmt (GO_DATA (dat
));
414 if (fmt
&& go_format_is_markup (fmt
))
415 res
= go_format_get_markup (fmt
);
416 go_format_unref (fmt
);
421 gnm_go_data_scalar_class_init (GObjectClass
*gobject_klass
)
423 GODataClass
*godata_klass
= (GODataClass
*) gobject_klass
;
424 GODataScalarClass
*scalar_klass
= (GODataScalarClass
*) gobject_klass
;
426 scalar_parent_klass
= g_type_class_peek_parent (gobject_klass
);
427 gobject_klass
->finalize
= gnm_go_data_scalar_finalize
;
428 godata_klass
->dup
= gnm_go_data_dup
;
429 godata_klass
->eq
= gnm_go_data_eq
;
430 godata_klass
->preferred_fmt
= gnm_go_data_preferred_fmt
;
431 godata_klass
->date_conv
= gnm_go_data_date_conv
;
432 godata_klass
->serialize
= gnm_go_data_serialize
;
433 godata_klass
->unserialize
= gnm_go_data_unserialize
;
434 scalar_klass
->get_value
= gnm_go_data_scalar_get_value
;
435 scalar_klass
->get_str
= gnm_go_data_scalar_get_str
;
436 scalar_klass
->get_markup
= gnm_go_data_scalar_get_markup
;
440 gnm_go_data_scalar_debug_name (GnmDependent
const *dep
, GString
*target
)
442 g_string_append_printf (target
, "GraphScalar%p", (void *)dep
);
445 static DEPENDENT_MAKE_TYPE (gnm_go_data_scalar
, NULL
)
448 gnm_go_data_scalar_init (GObject
*obj
)
450 GnmGODataScalar
*scalar
= (GnmGODataScalar
*)obj
;
451 scalar
->dep
.flags
= gnm_go_data_scalar_get_dep_type ();
454 GSF_CLASS (GnmGODataScalar
, gnm_go_data_scalar
,
455 gnm_go_data_scalar_class_init
, gnm_go_data_scalar_init
,
459 gnm_go_data_scalar_new_expr (Sheet
*sheet
, GnmExprTop
const *texpr
)
461 GnmGODataScalar
*res
= g_object_new (gnm_go_data_scalar_get_type (), NULL
);
462 res
->dep
.texpr
= texpr
;
463 res
->dep
.sheet
= sheet
;
464 return GO_DATA (res
);
467 /**************************************************************************/
469 struct _GnmGODataVector
{
477 typedef GODataVectorClass GnmGODataVectorClass
;
479 #define DEP_TO_VECTOR(d_ptr) (GnmGODataVector *)(((char *)d_ptr) - G_STRUCT_OFFSET (GnmGODataVector, dep))
481 static GObjectClass
*vector_parent_klass
;
484 gnm_go_data_vector_eval (GnmDependent
*dep
)
486 GnmGODataVector
*vec
= DEP_TO_VECTOR (dep
);
488 value_release (vec
->val
);
491 g_ptr_array_free (vec
->markup
, TRUE
);
495 g_ptr_array_free (vec
->strs
, TRUE
);
498 go_data_emit_changed (GO_DATA (vec
));
502 gnm_go_data_vector_finalize (GObject
*obj
)
504 GnmGODataVector
*vec
= (GnmGODataVector
*)obj
;
506 dependent_set_expr (&vec
->dep
, NULL
);
507 value_release (vec
->val
);
510 g_free (vec
->base
.values
);
511 vec
->base
.values
= NULL
;
513 g_ptr_array_free (vec
->markup
, TRUE
);
517 g_ptr_array_free (vec
->strs
, TRUE
);
521 vector_parent_klass
->finalize (obj
);
525 gnm_go_data_vector_load_len (GODataVector
*dat
)
527 GnmGODataVector
*vec
= (GnmGODataVector
*)dat
;
530 Sheet
*start_sheet
, *end_sheet
;
531 int old_len
= dat
->len
;
534 eval_pos_init_dep (&ep
, &vec
->dep
);
535 if (vec
->val
== NULL
&& vec
->dep
.texpr
!= NULL
) {
537 if (GNM_EXPR_GET_OPER (vec
->dep
.texpr
->expr
) == GNM_EXPR_OP_SET
&&
538 gnm_expr_is_rangeref (vec
->dep
.texpr
->expr
) && ((l
= gnm_expr_top_get_ranges (vec
->dep
.texpr
))) && l
->next
!= NULL
) {
539 unsigned len
= g_slist_length (l
);
542 vec
->val
= value_new_array_empty (len
, 1);
543 for (i
= 0; i
< len
; i
++) {
544 vec
->val
->v_array
.vals
[i
][0] = cur
->data
;
550 for (cur
= l
; cur
!= NULL
; cur
= cur
->next
)
551 value_release (cur
->data
);
553 vec
->val
= gnm_expr_top_eval (vec
->dep
.texpr
, &ep
,
554 GNM_EXPR_EVAL_PERMIT_NON_SCALAR
| GNM_EXPR_EVAL_PERMIT_EMPTY
| GNM_EXPR_EVAL_ARRAY_CONTEXT
);
559 if (vec
->val
!= NULL
) {
560 switch (vec
->val
->v_any
.type
) {
561 case VALUE_CELLRANGE
:
562 gnm_rangeref_normalize (&vec
->val
->v_range
.cell
, &ep
,
563 &start_sheet
, &end_sheet
, &r
);
565 /* add +1 to max_used so that we can have matrices with
566 * empty cells at the end, see #684072 */
567 if (r
.end
.col
> start_sheet
->cols
.max_used
)
568 r
.end
.col
= start_sheet
->cols
.max_used
+ 1;
569 if (r
.end
.row
> start_sheet
->rows
.max_used
)
570 r
.end
.row
= start_sheet
->rows
.max_used
+ 1;
572 if (r
.end
.col
>= r
.start
.col
&& r
.end
.row
>= r
.start
.row
) {
573 guint w
= range_width (&r
);
574 guint h
= range_height (&r
);
576 new_len
= (guint64
)h
* w
* (end_sheet
->index_in_wb
- start_sheet
->index_in_wb
+ 1);
584 for (j
= 0; j
< vec
->val
->v_array
.y
; j
++)
585 for (i
= 0; i
< vec
->val
->v_array
.x
; i
++) {
586 v
= vec
->val
->v_array
.vals
[i
][j
];
587 if (VALUE_IS_CELLRANGE (v
)) {
588 gnm_rangeref_normalize (&v
->v_range
.cell
, &ep
,
589 &start_sheet
, &end_sheet
, &r
);
590 new_len
+= (guint64
)range_width (&r
) * range_height (&r
)
591 * (end_sheet
->index_in_wb
- start_sheet
->index_in_wb
+ 1);
595 vec
->as_col
= (vec
->val
->v_array
.y
> vec
->val
->v_array
.x
);
609 /* Protect against overflow in ->len as well as when allocating ->values. */
610 new_len
= MIN (new_len
, (gint64
)(G_MAXINT
/ sizeof (dat
->values
[0])));
613 if (dat
->values
!= NULL
&& old_len
!= dat
->len
) {
614 g_free (dat
->values
);
617 dat
->base
.flags
|= GO_DATA_VECTOR_LEN_CACHED
;
620 struct assign_closure
{
621 const GODateConventions
*date_conv
;
622 double minimum
, maximum
;
630 cb_assign_val (GnmCellIter
const *iter
, struct assign_closure
*dat
)
635 if ((gssize
)dat
->i
>= dat
->vals_len
)
638 if (iter
->cell
!= NULL
) {
639 gnm_cell_eval (iter
->cell
);
640 v
= iter
->cell
->value
;
644 if (VALUE_IS_EMPTY_OR_ERROR (v
)) {
645 dat
->vals
[dat
->i
++] = go_nan
;
650 if (VALUE_IS_STRING (v
)) {
651 v
= format_match_number (value_peek_string (v
), NULL
,
654 dat
->vals
[dat
->i
++] = go_nan
;
657 res
= value_get_as_float (v
);
660 res
= value_get_as_float (v
);
662 dat
->vals
[dat
->i
++] = res
;
663 if (dat
->minimum
> res
)
665 if (dat
->maximum
< res
)
671 gnm_go_data_vector_load_values (GODataVector
*dat
)
673 GnmGODataVector
*vec
= (GnmGODataVector
*)dat
;
676 Sheet
*start_sheet
, *end_sheet
;
677 double *vals
, minimum
, maximum
;
679 struct assign_closure closure
;
681 (void)go_data_vector_get_len (dat
); /* force calculation */
683 if (dat
->len
<= 0 || !vec
->dep
.sheet
) {
685 dat
->minimum
= go_nan
;
686 dat
->maximum
= go_nan
;
687 dat
->base
.flags
|= GO_DATA_CACHE_IS_VALID
;
691 closure
.date_conv
= workbook_date_conv (vec
->dep
.sheet
->workbook
);
693 if (dat
->values
== NULL
)
694 dat
->values
= g_new (double, dat
->len
);
696 switch (vec
->val
->v_any
.type
) {
697 case VALUE_CELLRANGE
:
698 gnm_rangeref_normalize (&vec
->val
->v_range
.cell
,
699 eval_pos_init_dep (&ep
, &vec
->dep
),
700 &start_sheet
, &end_sheet
, &r
);
702 /* clip here rather than relying on sheet_foreach
703 * because that only clips if we ignore blanks
704 * but add +1 to max_used so that we can have matrices with
705 * empty cells at the end, see #684072 */
706 if (r
.end
.row
> start_sheet
->rows
.max_used
)
707 r
.end
.row
= start_sheet
->rows
.max_used
+ 1;
708 if (r
.end
.col
> start_sheet
->cols
.max_used
)
709 r
.end
.col
= start_sheet
->cols
.max_used
+ 1;
711 /* In case the sheet is empty */
712 if (r
.start
.col
<= r
.end
.col
&& r
.start
.row
<= r
.end
.row
) {
713 closure
.maximum
= - G_MAXDOUBLE
;
714 closure
.minimum
= G_MAXDOUBLE
;
715 closure
.vals
= dat
->values
;
716 closure
.vals_len
= dat
->len
;
719 if (start_sheet
!= end_sheet
)
720 workbook_foreach_cell_in_range (&ep
, vec
->val
,
721 CELL_ITER_IGNORE_FILTERED
,
722 (CellIterFunc
)cb_assign_val
,
725 sheet_foreach_cell_in_range (start_sheet
, CELL_ITER_IGNORE_FILTERED
,
726 r
.start
.col
, r
.start
.row
, r
.end
.col
, r
.end
.row
,
727 (CellIterFunc
)cb_assign_val
, &closure
);
728 dat
->len
= closure
.last
+ 1; /* clip */
729 minimum
= closure
.minimum
;
730 maximum
= closure
.maximum
;
732 minimum
= maximum
= vals
[0] = go_nan
;
736 guint64 last
= 0, max
= dat
->len
;
737 int len
= vec
->val
->v_array
.y
* vec
->val
->v_array
.x
;
738 int x
= 0, y
= vec
->val
->v_array
.y
;
740 maximum
= - G_MAXDOUBLE
;
741 minimum
= G_MAXDOUBLE
;
744 x
= vec
->val
->v_array
.x
;
748 v
= vec
->val
->v_array
.vals
[x
][y
];
750 if (VALUE_IS_CELLRANGE (v
)) {
751 gnm_rangeref_normalize (&v
->v_range
.cell
,
752 eval_pos_init_dep (&ep
, &vec
->dep
),
753 &start_sheet
, &end_sheet
, &r
);
755 /* clip here rather than relying on sheet_foreach
756 * because that only clips if we ignore blanks */
757 if (r
.end
.row
> start_sheet
->rows
.max_used
)
758 r
.end
.row
= start_sheet
->rows
.max_used
;
759 if (r
.end
.col
> start_sheet
->cols
.max_used
)
760 r
.end
.col
= start_sheet
->cols
.max_used
;
762 if (r
.start
.col
<= r
.end
.col
&& r
.start
.row
<= r
.end
.row
) {
763 closure
.maximum
= - G_MAXDOUBLE
;
764 closure
.minimum
= G_MAXDOUBLE
;
765 closure
.vals
= dat
->values
;
766 closure
.vals_len
= max
;
767 closure
.last
= last
- 1;
769 if (start_sheet
!= end_sheet
)
770 workbook_foreach_cell_in_range (&ep
, vec
->val
,
771 CELL_ITER_IGNORE_FILTERED
,
772 (CellIterFunc
)cb_assign_val
,
775 sheet_foreach_cell_in_range (start_sheet
, CELL_ITER_IGNORE_FILTERED
,
776 r
.start
.col
, r
.start
.row
, r
.end
.col
, r
.end
.row
,
777 (CellIterFunc
)cb_assign_val
, &closure
);
778 last
= dat
->len
= closure
.last
+ 1; /* clip */
779 if (minimum
> closure
.minimum
)
780 minimum
= closure
.minimum
;
781 if (maximum
< closure
.maximum
)
782 maximum
= closure
.maximum
;
785 } else if (VALUE_IS_EMPTY_OR_ERROR (v
)) {
788 } else if (VALUE_IS_STRING (v
)) {
789 GnmValue
*tmp
= format_match_number
790 (value_peek_string (v
), NULL
,
796 vals
[len
] = value_get_as_float (tmp
);
799 vals
[len
] = value_get_as_float (v
);
800 if (minimum
> vals
[len
])
802 if (maximum
< vals
[len
])
809 v
= format_match_number (value_peek_string (vec
->val
),
813 minimum
= maximum
= vals
[0] = value_get_as_float (v
);
817 /* fall through to errors */
821 minimum
= maximum
= vals
[0] = go_nan
;
824 minimum
= maximum
= vals
[0] = value_get_as_float (vec
->val
);
829 dat
->minimum
= minimum
;
830 dat
->maximum
= maximum
;
831 dat
->base
.flags
|= GO_DATA_CACHE_IS_VALID
;
835 gnm_go_data_vector_get_value (GODataVector
*dat
, unsigned i
)
837 GnmGODataVector
*vec
= (GnmGODataVector
*)dat
;
840 gboolean valid
= FALSE
;
842 if (vec
->val
== NULL
)
843 gnm_go_data_vector_load_len (dat
);
845 if (VALUE_IS_ARRAY (vec
->val
)) {
846 if ((dat
->base
.flags
& GO_DATA_CACHE_IS_VALID
) == 0)
847 gnm_go_data_vector_load_values (dat
);
848 return dat
->values
[i
];
850 eval_pos_init_dep (&ep
, &vec
->dep
);
851 v
= value_dup (vec
->as_col
852 ? value_area_get_x_y (vec
->val
, 0, i
, &ep
)
853 : value_area_get_x_y (vec
->val
, i
, 0, &ep
));
857 v
= value_coerce_to_number (v
, &valid
, &ep
);
859 gnm_float res
= value_get_as_float (v
);
869 struct string_closure
{
871 GODateConventions
const *date_conv
;
875 cb_assign_string (GnmCellIter
const *iter
, struct string_closure
*closure
)
880 if (iter
->cell
!= NULL
) {
881 gnm_cell_eval (iter
->cell
);
882 v
= iter
->cell
->value
;
885 str
= format_value (gnm_cell_get_format (iter
->cell
), v
, -1, closure
->date_conv
);
886 g_ptr_array_add (closure
->strs
, str
);
892 gnm_go_data_vector_get_str (GODataVector
*dat
, unsigned i
)
894 GnmGODataVector
*vec
= (GnmGODataVector
*)dat
;
897 GOFormat
const *fmt
= NULL
;
901 if (vec
->val
== NULL
)
902 gnm_go_data_vector_load_len (dat
);
903 g_return_val_if_fail (vec
->val
!= NULL
, NULL
);
905 eval_pos_init_dep (&ep
, &vec
->dep
);
906 if (VALUE_IS_ARRAY (vec
->val
)) {
907 /* we need to cache the strings if needed */
908 if (vec
->strs
== NULL
) {
909 int len
= vec
->val
->v_array
.y
* vec
->val
->v_array
.x
;
910 int x
= 0, y
= vec
->val
->v_array
.y
;
911 struct string_closure closure
;
912 closure
.strs
= vec
->strs
= g_ptr_array_new_with_free_func (g_free
);
913 closure
.date_conv
= ep
.sheet
? workbook_date_conv (ep
.sheet
->workbook
) : NULL
;
916 x
= vec
->val
->v_array
.x
;
920 v
= vec
->val
->v_array
.vals
[x
][y
];
922 if (VALUE_IS_CELLRANGE (v
)) {
923 /* actually we only need to cache in that case */
924 Sheet
*start_sheet
, *end_sheet
;
926 gnm_rangeref_normalize (&v
->v_range
.cell
,
927 eval_pos_init_dep (&ep
, &vec
->dep
),
928 &start_sheet
, &end_sheet
, &r
);
930 /* clip here rather than relying on sheet_foreach
931 * because that only clips if we ignore blanks */
932 if (r
.end
.row
> start_sheet
->rows
.max_used
)
933 r
.end
.row
= start_sheet
->rows
.max_used
;
934 if (r
.end
.col
> start_sheet
->cols
.max_used
)
935 r
.end
.col
= start_sheet
->cols
.max_used
;
937 if (r
.start
.col
<= r
.end
.col
&& r
.start
.row
<= r
.end
.row
)
938 sheet_foreach_cell_in_range (start_sheet
, CELL_ITER_IGNORE_FILTERED
,
939 r
.start
.col
, r
.start
.row
, r
.end
.col
, r
.end
.row
,
940 (CellIterFunc
)cb_assign_string
, &closure
);
944 if (vec
->strs
&& vec
->strs
->len
> i
)
945 ret
= g_ptr_array_index (vec
->strs
, i
);
947 return g_strdup (ret
);
948 } else if (VALUE_IS_CELLRANGE (vec
->val
)) {
949 Sheet
*start_sheet
, *end_sheet
;
951 if (vec
->strs
== NULL
) {
952 struct string_closure closure
;
953 closure
.strs
= vec
->strs
= g_ptr_array_new_with_free_func (g_free
);
954 closure
.date_conv
= ep
.sheet
? workbook_date_conv (ep
.sheet
->workbook
) : NULL
;
955 gnm_rangeref_normalize (&vec
->val
->v_range
.cell
,
956 eval_pos_init_dep (&ep
, &vec
->dep
),
957 &start_sheet
, &end_sheet
, &r
);
959 /* clip here rather than relying on sheet_foreach
960 * because that only clips if we ignore blanks */
961 if (r
.end
.row
> start_sheet
->rows
.max_used
)
962 r
.end
.row
= start_sheet
->rows
.max_used
;
963 if (r
.end
.col
> start_sheet
->cols
.max_used
)
964 r
.end
.col
= start_sheet
->cols
.max_used
;
966 if (r
.start
.col
<= r
.end
.col
&& r
.start
.row
<= r
.end
.row
)
967 sheet_foreach_cell_in_range (start_sheet
, CELL_ITER_IGNORE_FILTERED
,
968 r
.start
.col
, r
.start
.row
, r
.end
.col
, r
.end
.row
,
969 (CellIterFunc
)cb_assign_string
, &closure
);
971 if (vec
->strs
&& vec
->strs
->len
> i
)
972 ret
= g_ptr_array_index (vec
->strs
, i
);
974 return g_strdup (ret
);
980 ret
= render_val (((v
!= NULL
)? v
: vec
->val
), i
, j
, fmt
, &ep
);
985 cond_pango_attr_list_unref (PangoAttrList
*al
)
988 pango_attr_list_unref (al
);
992 cb_assign_markup (GnmCellIter
const *iter
, GPtrArray
*markup
)
994 PangoAttrList
const *l
= NULL
;
996 if (iter
->cell
!= NULL
) {
997 GOFormat
const *fmt
= gnm_cell_get_format (iter
->cell
);
998 if (go_format_is_markup (fmt
))
999 l
= go_format_get_markup (fmt
);
1001 g_ptr_array_add (markup
,
1002 l
? pango_attr_list_ref ((PangoAttrList
*)l
) : NULL
);
1007 static PangoAttrList
*
1008 gnm_go_data_vector_get_markup (GODataVector
*dat
, unsigned i
)
1010 GnmGODataVector
*vec
= (GnmGODataVector
*)dat
;
1012 if (vec
->markup
== NULL
) {
1016 Sheet
*start_sheet
, *end_sheet
;
1019 go_data_vector_get_len (dat
); /* force calculation */
1020 if (dat
->len
<= 0 || !vec
->dep
.sheet
)
1022 vec
->markup
= g_ptr_array_new_with_free_func
1023 ((GDestroyNotify
)cond_pango_attr_list_unref
);
1024 switch (vec
->val
->v_any
.type
) {
1025 case VALUE_CELLRANGE
:
1026 gnm_rangeref_normalize (&vec
->val
->v_range
.cell
,
1027 eval_pos_init_dep (&ep
, &vec
->dep
),
1028 &start_sheet
, &end_sheet
, &r
);
1030 /* clip here rather than relying on sheet_foreach
1031 * because that only clips if we ignore blanks */
1032 if (r
.end
.row
> start_sheet
->rows
.max_used
)
1033 r
.end
.row
= start_sheet
->rows
.max_used
;
1034 if (r
.end
.col
> start_sheet
->cols
.max_used
)
1035 r
.end
.col
= start_sheet
->cols
.max_used
;
1037 /* In case the sheet is empty */
1038 if (r
.start
.col
<= r
.end
.col
&& r
.start
.row
<= r
.end
.row
) {
1039 sheet_foreach_cell_in_range (start_sheet
, CELL_ITER_ALL
,
1040 r
.start
.col
, r
.start
.row
, r
.end
.col
, r
.end
.row
,
1041 (CellIterFunc
)cb_assign_markup
, vec
->markup
);
1046 int len
= vec
->as_col
? vec
->val
->v_array
.y
: vec
->val
->v_array
.x
;
1049 ? vec
->val
->v_array
.vals
[0][len
]
1050 : vec
->val
->v_array
.vals
[len
][0];
1052 if (VALUE_IS_CELLRANGE (v
)) {
1053 gnm_rangeref_normalize (&v
->v_range
.cell
,
1054 eval_pos_init_dep (&ep
, &vec
->dep
),
1055 &start_sheet
, &end_sheet
, &r
);
1057 /* clip here rather than relying on sheet_foreach
1058 * because that only clips if we ignore blanks */
1059 if (r
.end
.row
> start_sheet
->rows
.max_used
)
1060 r
.end
.row
= start_sheet
->rows
.max_used
;
1061 if (r
.end
.col
> start_sheet
->cols
.max_used
)
1062 r
.end
.col
= start_sheet
->cols
.max_used
;
1064 if (r
.start
.col
<= r
.end
.col
&& r
.start
.row
<= r
.end
.row
)
1065 sheet_foreach_cell_in_range (start_sheet
, CELL_ITER_ALL
,
1066 r
.start
.col
, r
.start
.row
, r
.end
.col
, r
.end
.row
,
1067 (CellIterFunc
)cb_assign_markup
, vec
->markup
);
1078 return pango_attr_list_copy ((vec
->markup
->len
> i
)?
1079 g_ptr_array_index (vec
->markup
, i
): NULL
);
1083 gnm_go_data_vector_class_init (GObjectClass
*gobject_klass
)
1085 GODataClass
*godata_klass
= (GODataClass
*) gobject_klass
;
1086 GODataVectorClass
*vector_klass
= (GODataVectorClass
*) gobject_klass
;
1088 vector_parent_klass
= g_type_class_peek_parent (gobject_klass
);
1089 gobject_klass
->finalize
= gnm_go_data_vector_finalize
;
1090 godata_klass
->dup
= gnm_go_data_dup
;
1091 godata_klass
->eq
= gnm_go_data_eq
;
1092 godata_klass
->preferred_fmt
= gnm_go_data_preferred_fmt
;
1093 godata_klass
->date_conv
= gnm_go_data_date_conv
;
1094 godata_klass
->serialize
= gnm_go_data_serialize
;
1095 godata_klass
->unserialize
= gnm_go_data_unserialize
;
1096 vector_klass
->load_len
= gnm_go_data_vector_load_len
;
1097 vector_klass
->load_values
= gnm_go_data_vector_load_values
;
1098 vector_klass
->get_value
= gnm_go_data_vector_get_value
;
1099 vector_klass
->get_str
= gnm_go_data_vector_get_str
;
1100 vector_klass
->get_markup
= gnm_go_data_vector_get_markup
;
1104 gnm_go_data_vector_debug_name (GnmDependent
const *dep
, GString
*target
)
1106 g_string_append_printf (target
, "GraphVector%p", (void *)dep
);
1108 static DEPENDENT_MAKE_TYPE (gnm_go_data_vector
, NULL
)
1111 gnm_go_data_vector_init (GObject
*obj
)
1113 GnmGODataVector
*vec
= (GnmGODataVector
*)obj
;
1114 vec
->dep
.flags
= gnm_go_data_vector_get_dep_type ();
1117 GSF_CLASS (GnmGODataVector
, gnm_go_data_vector
,
1118 gnm_go_data_vector_class_init
, gnm_go_data_vector_init
,
1119 GO_TYPE_DATA_VECTOR
)
1122 gnm_go_data_vector_new_expr (Sheet
*sheet
, GnmExprTop
const *texpr
)
1124 GnmGODataVector
*res
= g_object_new (gnm_go_data_vector_get_type (), NULL
);
1125 res
->dep
.texpr
= texpr
;
1126 res
->dep
.sheet
= sheet
;
1127 return GO_DATA (res
);
1130 /**************************************************************************/
1132 struct _GnmGODataMatrix
{
1137 typedef GODataMatrixClass GnmGODataMatrixClass
;
1139 #define DEP_TO_MATRIX(d_ptr) (GnmGODataMatrix *)(((char *)d_ptr) - G_STRUCT_OFFSET (GnmGODataMatrix, dep))
1141 static GObjectClass
*matrix_parent_klass
;
1144 gnm_go_data_matrix_eval (GnmDependent
*dep
)
1146 GnmGODataMatrix
*mat
= DEP_TO_MATRIX (dep
);
1148 value_release (mat
->val
);
1150 go_data_emit_changed (GO_DATA (mat
));
1154 gnm_go_data_matrix_finalize (GObject
*obj
)
1156 GnmGODataMatrix
*mat
= (GnmGODataMatrix
*)obj
;
1158 dependent_set_expr (&mat
->dep
, NULL
);
1159 value_release (mat
->val
);
1162 g_free (mat
->base
.values
);
1163 mat
->base
.values
= NULL
;
1165 matrix_parent_klass
->finalize (obj
);
1169 gnm_go_data_matrix_load_size (GODataMatrix
*dat
)
1171 GnmGODataMatrix
*mat
= (GnmGODataMatrix
*)dat
;
1174 Sheet
*start_sheet
, *end_sheet
;
1176 int old_rows
= dat
->size
.rows
, old_columns
= dat
->size
.columns
;
1178 eval_pos_init_dep (&ep
, &mat
->dep
);
1179 if (mat
->val
== NULL
) {
1180 mat
->val
= gnm_expr_top_eval (mat
->dep
.texpr
, &ep
,
1181 GNM_EXPR_EVAL_PERMIT_NON_SCALAR
| GNM_EXPR_EVAL_PERMIT_EMPTY
);
1184 if (mat
->val
!= NULL
) {
1185 switch (mat
->val
->v_any
.type
) {
1186 case VALUE_CELLRANGE
:
1187 gnm_rangeref_normalize (&mat
->val
->v_range
.cell
, &ep
,
1188 &start_sheet
, &end_sheet
, &r
);
1189 if (r
.end
.col
> start_sheet
->cols
.max_used
)
1190 r
.end
.col
= start_sheet
->cols
.max_used
;
1191 if (r
.end
.row
> start_sheet
->rows
.max_used
)
1192 r
.end
.row
= start_sheet
->rows
.max_used
;
1194 if (r
.end
.col
>= r
.start
.col
&& r
.end
.row
>= r
.start
.row
) {
1195 w
= range_width (&r
);
1196 h
= range_height (&r
);
1197 if (w
> 0 && h
> 0) {
1199 dat
->size
.columns
= w
;
1203 dat
->size
.columns
= 0;
1207 dat
->size
.columns
= 0;
1212 dat
->size
.rows
= mat
->val
->v_array
.y
;
1213 dat
->size
.columns
= mat
->val
->v_array
.x
;
1218 dat
->size
.columns
= 1;
1222 dat
->size
.columns
= 0;
1224 if (dat
->values
!= NULL
&&
1225 (old_rows
!= dat
->size
.rows
|| old_columns
!= dat
->size
.columns
)) {
1226 g_free (dat
->values
);
1229 dat
->base
.flags
|= GO_DATA_MATRIX_SIZE_CACHED
;
1232 struct assign_matrix_closure
{
1233 const GODateConventions
*date_conv
;
1234 double minimum
, maximum
;
1236 int first_row
, first_col
;
1237 int last_row
, last_col
;
1238 int row
, col
, columns
, k
;
1242 cb_assign_matrix_val (GnmCellIter
const *iter
,
1243 struct assign_matrix_closure
*dat
)
1248 if (dat
->first_col
== -1)
1249 dat
->first_col
= iter
->pp
.eval
.col
;
1250 dat
->col
= iter
->pp
.eval
.col
- dat
->first_col
;
1251 if (dat
->first_row
== -1)
1252 dat
->first_row
= iter
->pp
.eval
.row
;
1253 dat
->row
= iter
->pp
.eval
.row
- dat
->first_row
;
1255 if (iter
->cell
!= NULL
) {
1256 gnm_cell_eval (iter
->cell
);
1257 v
= iter
->cell
->value
;
1262 if (VALUE_IS_EMPTY_OR_ERROR (v
)) {
1263 dat
->vals
[dat
->row
* dat
->columns
+ dat
->col
] = go_nan
;
1267 if (dat
->last_row
< dat
->row
)
1268 dat
->last_row
= dat
->row
;
1269 if (dat
->last_col
< dat
->col
)
1270 dat
->last_col
= dat
->col
;
1272 if (VALUE_IS_STRING (v
)) {
1273 v
= format_match_number (value_peek_string (v
), NULL
,
1276 dat
->vals
[dat
->row
* dat
->columns
+ dat
->col
] = go_nan
;
1277 /* may be go_pinf should be more appropriate? */
1280 res
= value_get_as_float (v
);
1283 res
= value_get_as_float (v
);
1285 dat
->vals
[dat
->row
* dat
->columns
+ dat
->col
] = res
;
1286 if (dat
->minimum
> res
)
1288 if (dat
->maximum
< res
)
1294 gnm_go_data_matrix_load_values (GODataMatrix
*dat
)
1296 GnmGODataMatrix
*mat
= (GnmGODataMatrix
*)dat
;
1299 Sheet
*start_sheet
, *end_sheet
;
1300 GODataMatrixSize size
= go_data_matrix_get_size (dat
); /* force calculation */
1301 double *vals
, minimum
, maximum
;
1304 struct assign_matrix_closure closure
;
1306 if (size
.rows
<= 0 || size
.columns
<= 0) {
1308 dat
->minimum
= go_nan
;
1309 dat
->maximum
= go_nan
;
1310 dat
->base
.flags
|= GO_DATA_CACHE_IS_VALID
;
1314 closure
.date_conv
= workbook_date_conv (mat
->dep
.sheet
->workbook
);
1316 if (dat
->values
== NULL
)
1317 dat
->values
= g_new (double, size
.rows
* size
.columns
);
1319 switch (mat
->val
->v_any
.type
) {
1320 case VALUE_CELLRANGE
:
1321 gnm_rangeref_normalize (&mat
->val
->v_range
.cell
,
1322 eval_pos_init_dep (&ep
, &mat
->dep
),
1323 &start_sheet
, &end_sheet
, &r
);
1325 /* In case the sheet is empty */
1326 if (r
.start
.col
<= r
.end
.col
&& r
.start
.row
<= r
.end
.row
) {
1327 closure
.maximum
= - G_MAXDOUBLE
;
1328 closure
.minimum
= G_MAXDOUBLE
;
1329 closure
.vals
= dat
->values
;
1330 closure
.first_row
= closure
.last_row
= -1;
1331 closure
.first_col
= closure
.last_col
= -1;
1332 closure
.row
= closure
.col
= 0;
1333 closure
.columns
= dat
->size
.columns
;
1334 sheet_foreach_cell_in_range (start_sheet
, CELL_ITER_ALL
,
1335 r
.start
.col
, r
.start
.row
,
1336 r
.start
.col
+ dat
->size
.columns
- 1,
1337 r
.start
.row
+ dat
->size
.rows
- 1,
1338 (CellIterFunc
)cb_assign_matrix_val
, &closure
);
1339 #warning "Should we clip the matrix?"
1340 minimum
= closure
.minimum
;
1341 maximum
= closure
.maximum
;
1342 if (minimum
> maximum
)
1343 minimum
= maximum
= go_nan
;
1345 minimum
= maximum
= vals
[0] = go_nan
;
1349 maximum
= - G_MAXDOUBLE
;
1350 minimum
= G_MAXDOUBLE
;
1351 for (col
= 0; col
< size
.columns
; col
++)
1352 for (row
= 0; row
< size
.rows
; row
++) {
1353 v
= mat
->val
->v_array
.vals
[col
][row
];
1354 cur
= col
* size
.rows
+ row
;
1355 if (VALUE_IS_EMPTY_OR_ERROR (v
)) {
1356 vals
[row
* size
.columns
+ col
] = go_nan
;
1358 } else if (VALUE_IS_STRING (v
)) {
1359 GnmValue
*tmp
= format_match_number
1360 (value_peek_string (v
), NULL
,
1366 vals
[cur
] = value_get_as_float (tmp
);
1367 value_release (tmp
);
1369 vals
[cur
] = value_get_as_float (v
);
1370 if (minimum
> vals
[cur
])
1371 minimum
= vals
[cur
];
1372 if (maximum
< vals
[cur
])
1373 maximum
= vals
[cur
];
1375 if (minimum
> maximum
)
1376 minimum
= maximum
= go_nan
;
1380 v
= format_match_number (value_peek_string (mat
->val
),
1384 vals
[0] = value_get_as_float (v
);
1385 minimum
= maximum
= go_nan
;
1389 /* fall through to errors */
1393 minimum
= maximum
= vals
[0] = go_nan
;
1396 vals
[0] = value_get_as_float (mat
->val
);
1397 minimum
= maximum
= go_nan
;
1402 dat
->minimum
= minimum
;
1403 dat
->maximum
= maximum
;
1404 dat
->base
.flags
|= GO_DATA_CACHE_IS_VALID
;
1408 gnm_go_data_matrix_get_value (GODataMatrix
*dat
, unsigned i
, unsigned j
)
1410 GnmGODataMatrix
*mat
= (GnmGODataMatrix
*)dat
;
1415 if (mat
->val
== NULL
)
1416 gnm_go_data_matrix_load_size (dat
);
1418 eval_pos_init_dep (&ep
, &mat
->dep
);
1419 /* i is row and j is column */
1420 v
= value_dup (value_area_get_x_y (mat
->val
, j
, i
, &ep
));
1424 v
= value_coerce_to_number (v
, &valid
, &ep
);
1426 gnm_float res
= value_get_as_float (v
);
1435 gnm_go_data_matrix_get_str (GODataMatrix
*dat
, unsigned i
, unsigned j
)
1437 GnmGODataMatrix
*mat
= (GnmGODataMatrix
*)dat
;
1439 GOFormat
const *fmt
= NULL
;
1441 if (mat
->val
== NULL
)
1442 gnm_go_data_matrix_load_size (dat
);
1443 g_return_val_if_fail (mat
->val
!= NULL
, NULL
);
1445 eval_pos_init_dep (&ep
, &mat
->dep
);
1446 return render_val (mat
->val
, i
, j
, fmt
, &ep
);
1450 gnm_go_data_matrix_class_init (GObjectClass
*gobject_klass
)
1452 GODataClass
*godata_klass
= (GODataClass
*) gobject_klass
;
1453 GODataMatrixClass
*matrix_klass
= (GODataMatrixClass
*) gobject_klass
;
1455 matrix_parent_klass
= g_type_class_peek_parent (gobject_klass
);
1456 gobject_klass
->finalize
= gnm_go_data_matrix_finalize
;
1457 godata_klass
->dup
= gnm_go_data_dup
;
1458 godata_klass
->eq
= gnm_go_data_eq
;
1459 godata_klass
->preferred_fmt
= gnm_go_data_preferred_fmt
;
1460 godata_klass
->date_conv
= gnm_go_data_date_conv
;
1461 godata_klass
->serialize
= gnm_go_data_serialize
;
1462 godata_klass
->unserialize
= gnm_go_data_unserialize
;
1463 matrix_klass
->load_size
= gnm_go_data_matrix_load_size
;
1464 matrix_klass
->load_values
= gnm_go_data_matrix_load_values
;
1465 matrix_klass
->get_value
= gnm_go_data_matrix_get_value
;
1466 matrix_klass
->get_str
= gnm_go_data_matrix_get_str
;
1470 gnm_go_data_matrix_debug_name (GnmDependent
const *dep
, GString
*target
)
1472 g_string_append_printf (target
, "GraphMatrix%p", (void *)dep
);
1474 static DEPENDENT_MAKE_TYPE (gnm_go_data_matrix
, NULL
)
1477 gnm_go_data_matrix_init (GObject
*obj
)
1479 GnmGODataMatrix
*mat
= (GnmGODataMatrix
*)obj
;
1480 mat
->dep
.flags
= gnm_go_data_matrix_get_dep_type ();
1483 GSF_CLASS (GnmGODataMatrix
, gnm_go_data_matrix
,
1484 gnm_go_data_matrix_class_init
, gnm_go_data_matrix_init
,
1485 GO_TYPE_DATA_MATRIX
)
1488 gnm_go_data_matrix_new_expr (Sheet
*sheet
, GnmExprTop
const *texpr
)
1490 GnmGODataMatrix
*res
= g_object_new (gnm_go_data_matrix_get_type (), NULL
);
1491 res
->dep
.texpr
= texpr
;
1492 res
->dep
.sheet
= sheet
;
1493 return GO_DATA (res
);
1496 /*******************************************************************************/
1498 static GnmDependent
*
1499 gnm_go_data_get_dep (GOData
const *dat
)
1501 if (GNM_IS_GO_DATA_SCALAR (dat
))
1502 return &((GnmGODataScalar
*)dat
)->dep
;
1503 if (GNM_IS_GO_DATA_VECTOR (dat
))
1504 return &((GnmGODataVector
*)dat
)->dep
;
1505 if (GNM_IS_GO_DATA_MATRIX (dat
))
1506 return &((GnmGODataMatrix
*)dat
)->dep
;