Compilation: fix warning.
[gnumeric.git] / src / graph.c
blobd736fa50fa507fbfe200f1963f6fb146efa6e1df
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
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
20 * USA
22 #include <gnumeric-config.h>
23 #include "graph.h"
24 #include "dependent.h"
25 #include "expr.h"
26 #include "cell.h"
27 #include "value.h"
28 #include "number-match.h"
29 #include "mathfunc.h"
30 #include "sheet.h"
31 #include "workbook.h"
32 #include "position.h"
33 #include "gnm-format.h"
34 #include "auto-format.h"
35 #include "ranges.h"
36 #include "parse-util.h"
37 #include "expr-impl.h"
38 #include <goffice/goffice.h>
40 #include <gsf/gsf-impl-utils.h>
41 #include <string.h>
43 /* ------------------------------------------------------------------------- */
45 static char *
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");
57 static void
58 set_pending_str (const GOData *data, const char *str)
60 g_object_set_data_full (G_OBJECT (data),
61 "unserialize", g_strdup (str),
62 g_free);
65 static void
66 set_pending_convs (GOData *data, const GnmConventions *convs)
68 g_object_set_data_full (G_OBJECT (data),
69 "unserialize-convs",
70 gnm_conventions_ref ((gpointer)convs),
71 (GDestroyNotify)gnm_conventions_unref);
74 /* ------------------------------------------------------------------------- */
76 static char *
77 render_val (GnmValue const *v, int i, int j,
78 GOFormat const *fmt, GnmEvalPos const *ep)
80 GODateConventions const *date_conv;
82 if (!v)
83 return NULL;
85 date_conv = ep->sheet ? workbook_date_conv (ep->sheet->workbook) : NULL;
87 #if 0
88 g_printerr ("Rendering %s with fmt=%s\n",
89 value_peek_string (v),
90 fmt ? go_format_as_XL (fmt) : "-");
91 #endif
93 if (VALUE_IS_CELLRANGE (v)) {
94 Sheet *start_sheet, *end_sheet;
95 GnmCell *cell;
96 GnmRange r;
98 gnm_rangeref_normalize (&v->v_range.cell, ep,
99 &start_sheet, &end_sheet, &r);
100 r.start.row += i;
101 r.start.col += j;
102 cell = sheet_cell_get (start_sheet, r.start.col, r.start.row);
103 if (cell == NULL)
104 return NULL;
105 gnm_cell_eval (cell);
106 v = cell->value;
108 if (fmt == NULL)
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);
120 static GOData *
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;
128 if (dst_dep->texpr)
129 gnm_expr_top_ref (dst_dep->texpr);
131 if (src_dep->sheet)
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);
142 static gboolean
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)))
151 return FALSE;
152 if (get_pending_convs (data_a) != get_pending_convs (data_b))
153 return FALSE;
154 return TRUE;
157 return a->texpr && b->texpr && gnm_expr_top_equal (a->texpr, b->texpr);
160 static GOFormat *
161 gnm_go_data_preferred_fmt (GOData const *dat)
163 GnmEvalPos ep;
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);
169 return dep->texpr
170 ? (GOFormat *)gnm_auto_style_format_suggest (dep->texpr, &ep)
171 : NULL;
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);
181 if (!dep->sheet)
182 return NULL;
184 return workbook_date_conv (dep->sheet->workbook);
187 static char *
188 gnm_go_data_serialize (GOData const *dat, gpointer user)
190 GnmParsePos pp;
191 GnmConventions const *convs = user;
192 GnmDependent const *dep = gnm_go_data_get_dep (dat);
193 char *res;
194 if (dep->sheet == NULL)
195 return g_strdup ("No sheet for GnmGOData");
196 if (!convs) {
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),
203 convs);
204 #if 0
205 g_printerr ("Serializing %s\n", res);
206 #endif
207 return res;
210 static gboolean
211 gnm_go_data_unserialize (GOData *dat, char const *str, gpointer user)
213 GnmConventions const *convs = user;
214 GnmExprTop const *texpr;
215 GnmParsePos pp;
216 GnmDependent *dep = gnm_go_data_get_dep (dat);
218 if (!convs) {
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);
229 return TRUE;
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,
236 convs, NULL);
237 if (texpr != NULL) {
238 dependent_set_expr (dep, texpr);
239 gnm_expr_top_unref (texpr);
240 return TRUE;
242 return FALSE;
245 void
246 gnm_go_data_set_sheet (GOData *dat, Sheet *sheet)
248 GnmDependent *dep = gnm_go_data_get_dep (dat);
250 if (dep == NULL)
251 return;
253 if (dependent_is_linked (dep)) {
254 dependent_unlink (dep);
255 dep->sheet = NULL;
258 if (sheet == NULL)
259 return;
261 /* no expression?
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));
276 dep->sheet = NULL;
277 dependent_set_sheet (dep, sheet);
281 * gnm_go_data_get_sheet:
282 * @dat: #GOData
284 * Returns: (transfer none): the sheet.
286 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);
291 return dep->sheet;
294 GnmExprTop const *
295 gnm_go_data_get_expr (GOData const *dat)
297 GnmDependent *dep = gnm_go_data_get_dep (dat);
298 if (!dep)
299 return NULL;
300 return dep->texpr;
304 * gnm_go_data_foreach_dep:
305 * @dat: #GOData
306 * @so: #SheetObject
307 * @func: (scope call):
308 * @user: user data.
311 void
312 gnm_go_data_foreach_dep (GOData *dat, SheetObject *so,
313 SheetObjectForeachDepFunc func, gpointer user)
315 GnmDependent *dep = gnm_go_data_get_dep (dat);
316 if (dep)
317 func (dep, so, user);
320 /**************************************************************************/
322 struct _GnmGODataScalar {
323 GODataScalar base;
324 GnmDependent dep;
325 GnmValue *val;
326 char *val_str;
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;
334 static GnmValue *
335 scalar_get_val (GnmGODataScalar *scalar)
337 if (scalar->val != NULL) {
338 value_release (scalar->val);
339 scalar->val = NULL;
340 g_free (scalar->val_str);
341 scalar->val_str = NULL;
343 if (scalar->val == NULL) {
344 if (scalar->dep.texpr != NULL) {
345 GnmEvalPos pos;
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);
352 } else
353 scalar->val = value_new_empty ();
355 return scalar->val;
358 static void
359 gnm_go_data_scalar_eval (GnmDependent *dep)
361 GnmGODataScalar *scalar = DEP_TO_SCALAR (dep);
363 value_release (scalar->val);
364 scalar->val = NULL;
365 g_free (scalar->val_str);
366 scalar->val_str = NULL;
367 go_data_emit_changed (GO_DATA (scalar));
370 static void
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);
377 scalar->val = NULL;
378 g_free (scalar->val_str);
379 scalar->val_str = NULL;
381 scalar_parent_klass->finalize (obj);
384 static double
385 gnm_go_data_scalar_get_value (GODataScalar *dat)
387 return value_get_as_float (scalar_get_val ((GnmGODataScalar *)dat));
390 static char const *
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) {
397 GnmEvalPos ep;
399 eval_pos_init_dep (&ep, &scalar->dep);
400 if (scalar->dep.texpr)
401 fmt = gnm_auto_style_format_suggest (scalar->dep.texpr, &ep);
402 scalar->val_str =
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);
417 return res;
420 static void
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;
439 static void
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)
447 static void
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,
456 GO_TYPE_DATA_SCALAR)
458 GOData *
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 {
470 GODataVector base;
471 GnmDependent dep;
472 GnmValue *val;
473 gboolean as_col;
474 GPtrArray *markup;
475 GPtrArray *strs;
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;
483 static void
484 gnm_go_data_vector_eval (GnmDependent *dep)
486 GnmGODataVector *vec = DEP_TO_VECTOR (dep);
488 value_release (vec->val);
489 vec->val = NULL;
490 if (vec->markup) {
491 g_ptr_array_free (vec->markup, TRUE);
492 vec->markup = NULL;
494 if (vec->strs) {
495 g_ptr_array_free (vec->strs, TRUE);
496 vec->strs = NULL;
498 go_data_emit_changed (GO_DATA (vec));
501 static void
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);
508 vec->val = NULL;
510 g_free (vec->base.values);
511 vec->base.values = NULL;
512 if (vec->markup) {
513 g_ptr_array_free (vec->markup, TRUE);
514 vec->markup = NULL;
516 if (vec->strs) {
517 g_ptr_array_free (vec->strs, TRUE);
518 vec->strs = NULL;
521 vector_parent_klass->finalize (obj);
524 static void
525 gnm_go_data_vector_load_len (GODataVector *dat)
527 GnmGODataVector *vec = (GnmGODataVector *)dat;
528 GnmEvalPos ep;
529 GnmRange r;
530 Sheet *start_sheet, *end_sheet;
531 int old_len = dat->len;
532 guint64 new_len = 0;
534 eval_pos_init_dep (&ep, &vec->dep);
535 if (vec->val == NULL && vec->dep.texpr != NULL) {
536 GSList *l = 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);
540 GSList *cur = l;
541 unsigned i;
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;
545 cur = cur->next;
547 } else {
548 if (l) {
549 GSList *cur;
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);
556 g_slist_free (l);
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);
575 vec->as_col = h > w;
576 new_len = (guint64)h * w * (end_sheet->index_in_wb - start_sheet->index_in_wb + 1);
578 break;
580 case VALUE_ARRAY : {
581 GnmValue *v;
582 int i, j;
583 new_len = 0;
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);
592 } else
593 new_len++;
595 vec->as_col = (vec->val->v_array.y > vec->val->v_array.x);
596 break;
598 case VALUE_ERROR :
599 new_len = 0;
600 break;
602 default :
603 new_len = 1;
604 vec->as_col = TRUE;
606 } else
607 new_len = 0;
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])));
611 dat->len = new_len;
613 if (dat->values != NULL && old_len != dat->len) {
614 g_free (dat->values);
615 dat->values = NULL;
617 dat->base.flags |= GO_DATA_VECTOR_LEN_CACHED;
620 struct assign_closure {
621 const GODateConventions *date_conv;
622 double minimum, maximum;
623 double *vals;
624 gssize vals_len;
625 guint64 last;
626 guint64 i;
629 static GnmValue *
630 cb_assign_val (GnmCellIter const *iter, struct assign_closure *dat)
632 GnmValue *v;
633 double res;
635 if ((gssize)dat->i >= dat->vals_len)
636 return NULL;
638 if (iter->cell != NULL) {
639 gnm_cell_eval (iter->cell);
640 v = iter->cell->value;
641 } else
642 v = NULL;
644 if (VALUE_IS_EMPTY_OR_ERROR (v)) {
645 dat->vals[dat->i++] = go_nan;
646 return NULL;
649 dat->last = dat->i;
650 if (VALUE_IS_STRING (v)) {
651 v = format_match_number (value_peek_string (v), NULL,
652 dat->date_conv);
653 if (v == NULL) {
654 dat->vals[dat->i++] = go_nan;
655 return NULL;
657 res = value_get_as_float (v);
658 value_release (v);
659 } else
660 res = value_get_as_float (v);
662 dat->vals[dat->i++] = res;
663 if (dat->minimum > res)
664 dat->minimum = res;
665 if (dat->maximum < res)
666 dat->maximum = res;
667 return NULL;
670 static void
671 gnm_go_data_vector_load_values (GODataVector *dat)
673 GnmGODataVector *vec = (GnmGODataVector *)dat;
674 GnmEvalPos ep;
675 GnmRange r;
676 Sheet *start_sheet, *end_sheet;
677 double *vals, minimum, maximum;
678 GnmValue *v;
679 struct assign_closure closure;
681 (void)go_data_vector_get_len (dat); /* force calculation */
683 if (dat->len <= 0 || !vec->dep.sheet) {
684 dat->values = NULL;
685 dat->minimum = go_nan;
686 dat->maximum = go_nan;
687 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
688 return;
691 closure.date_conv = workbook_date_conv (vec->dep.sheet->workbook);
693 if (dat->values == NULL)
694 dat->values = g_new (double, dat->len);
695 vals = dat->values;
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;
717 closure.last = -1;
718 closure.i = 0;
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,
723 &closure);
724 else
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;
731 } else
732 minimum = maximum = vals[0] = go_nan;
733 break;
735 case VALUE_ARRAY : {
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;
739 GnmValue *v;
740 maximum = - G_MAXDOUBLE;
741 minimum = G_MAXDOUBLE;
742 while (len-- > 0) {
743 if (x == 0) {
744 x = vec->val->v_array.x;
745 y--;
747 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;
768 closure.i = last;
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,
773 &closure);
774 else
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;
784 continue;
785 } else if (VALUE_IS_EMPTY_OR_ERROR (v)) {
786 vals[len] = go_nan;
787 continue;
788 } else if (VALUE_IS_STRING (v)) {
789 GnmValue *tmp = format_match_number
790 (value_peek_string (v), NULL,
791 closure.date_conv);
792 if (tmp == NULL) {
793 vals[len] = go_nan;
794 continue;
796 vals[len] = value_get_as_float (tmp);
797 value_release (tmp);
798 } else
799 vals[len] = value_get_as_float (v);
800 if (minimum > vals[len])
801 minimum = vals[len];
802 if (maximum < vals[len])
803 maximum = vals[len];
805 break;
808 case VALUE_STRING :
809 v = format_match_number (value_peek_string (vec->val),
810 NULL,
811 closure.date_conv);
812 if (v != NULL) {
813 minimum = maximum = vals[0] = value_get_as_float (v);
814 value_release (v);
815 break;
817 /* fall through to errors */
819 case VALUE_EMPTY :
820 case VALUE_ERROR :
821 minimum = maximum = vals[0] = go_nan;
822 break;
823 default :
824 minimum = maximum = vals[0] = value_get_as_float (vec->val);
825 break;
828 dat->values = vals;
829 dat->minimum = minimum;
830 dat->maximum = maximum;
831 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
834 static double
835 gnm_go_data_vector_get_value (GODataVector *dat, unsigned i)
837 GnmGODataVector *vec = (GnmGODataVector *)dat;
838 GnmValue *v;
839 GnmEvalPos ep;
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];
849 } else {
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));
854 if (NULL == v)
855 return go_nan;
857 v = value_coerce_to_number (v, &valid, &ep);
858 if (valid) {
859 gnm_float res = value_get_as_float (v);
860 value_release (v);
861 return res;
863 value_release (v);
865 return go_nan;
869 struct string_closure {
870 GPtrArray *strs;
871 GODateConventions const *date_conv;
874 static gpointer
875 cb_assign_string (GnmCellIter const *iter, struct string_closure *closure)
877 GnmValue *v = NULL;
878 char *str = NULL;
880 if (iter->cell != NULL) {
881 gnm_cell_eval (iter->cell);
882 v = iter->cell->value;
884 if (v != NULL)
885 str = format_value (gnm_cell_get_format (iter->cell), v, -1, closure->date_conv);
886 g_ptr_array_add (closure->strs, str);
888 return NULL;
891 static char *
892 gnm_go_data_vector_get_str (GODataVector *dat, unsigned i)
894 GnmGODataVector *vec = (GnmGODataVector *)dat;
895 GnmEvalPos ep;
896 int j;
897 GOFormat const *fmt = NULL;
898 char *ret = NULL;
899 GnmValue *v = 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;
914 while (len-- > 0) {
915 if (x == 0) {
916 x = vec->val->v_array.x;
917 y--;
919 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;
925 GnmRange r;
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);
946 if (ret != NULL)
947 return g_strdup (ret);
948 } else if (VALUE_IS_CELLRANGE (vec->val)) {
949 Sheet *start_sheet, *end_sheet;
950 GnmRange r;
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);
973 if (ret != NULL)
974 return g_strdup (ret);
976 if (vec->as_col)
977 j = 0;
978 else
979 j = i, i = 0;
980 ret = render_val (((v != NULL)? v: vec->val), i, j, fmt, &ep);
981 return ret;
984 static void
985 cond_pango_attr_list_unref (PangoAttrList *al)
987 if (al)
988 pango_attr_list_unref (al);
991 static gpointer
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);
1004 return 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) {
1013 /* load markups */
1014 GnmEvalPos ep;
1015 GnmRange r;
1016 Sheet *start_sheet, *end_sheet;
1017 GnmValue *v;
1019 go_data_vector_get_len (dat); /* force calculation */
1020 if (dat->len <= 0 || !vec->dep.sheet)
1021 return NULL;
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);
1043 break;
1045 case VALUE_ARRAY: {
1046 int len = vec->as_col? vec->val->v_array.y: vec->val->v_array.x;
1047 while (len-- > 0) {
1048 v = vec->as_col
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);
1070 break;
1073 default:
1074 break;
1078 return pango_attr_list_copy ((vec->markup->len > i)?
1079 g_ptr_array_index (vec->markup, i): NULL);
1082 static void
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;
1103 static void
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)
1110 static void
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)
1121 GOData *
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 {
1133 GODataMatrix base;
1134 GnmDependent dep;
1135 GnmValue *val;
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;
1143 static void
1144 gnm_go_data_matrix_eval (GnmDependent *dep)
1146 GnmGODataMatrix *mat = DEP_TO_MATRIX (dep);
1148 value_release (mat->val);
1149 mat->val = NULL;
1150 go_data_emit_changed (GO_DATA (mat));
1153 static void
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);
1160 mat->val = NULL;
1162 g_free (mat->base.values);
1163 mat->base.values = NULL;
1165 matrix_parent_klass->finalize (obj);
1168 static void
1169 gnm_go_data_matrix_load_size (GODataMatrix *dat)
1171 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1172 GnmEvalPos ep;
1173 GnmRange r;
1174 Sheet *start_sheet, *end_sheet;
1175 unsigned h, w;
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) {
1198 dat->size.rows = h;
1199 dat->size.columns = w;
1201 else {
1202 dat->size.rows = 0;
1203 dat->size.columns = 0;
1205 } else {
1206 dat->size.rows = 0;
1207 dat->size.columns = 0;
1209 break;
1211 case VALUE_ARRAY :
1212 dat->size.rows = mat->val->v_array.y;
1213 dat->size.columns = mat->val->v_array.x;
1214 break;
1216 default :
1217 dat->size.rows = 1;
1218 dat->size.columns = 1;
1220 } else {
1221 dat->size.rows = 0;
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);
1227 dat->values = NULL;
1229 dat->base.flags |= GO_DATA_MATRIX_SIZE_CACHED;
1232 struct assign_matrix_closure {
1233 const GODateConventions *date_conv;
1234 double minimum, maximum;
1235 double *vals;
1236 int first_row, first_col;
1237 int last_row, last_col;
1238 int row, col, columns, k;
1241 static GnmValue *
1242 cb_assign_matrix_val (GnmCellIter const *iter,
1243 struct assign_matrix_closure *dat)
1245 GnmValue *v;
1246 double res;
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;
1258 } else
1259 v = NULL;
1262 if (VALUE_IS_EMPTY_OR_ERROR (v)) {
1263 dat->vals[dat->row * dat->columns + dat->col] = go_nan;
1264 return NULL;
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,
1274 dat->date_conv);
1275 if (v == NULL) {
1276 dat->vals[dat->row * dat->columns + dat->col] = go_nan;
1277 /* may be go_pinf should be more appropriate? */
1278 return NULL;
1280 res = value_get_as_float (v);
1281 value_release (v);
1282 } else
1283 res = value_get_as_float (v);
1285 dat->vals[dat->row * dat->columns + dat->col] = res;
1286 if (dat->minimum > res)
1287 dat->minimum = res;
1288 if (dat->maximum < res)
1289 dat->maximum = res;
1290 return NULL;
1293 static void
1294 gnm_go_data_matrix_load_values (GODataMatrix *dat)
1296 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1297 GnmEvalPos ep;
1298 GnmRange r;
1299 Sheet *start_sheet, *end_sheet;
1300 GODataMatrixSize size = go_data_matrix_get_size (dat); /* force calculation */
1301 double *vals, minimum, maximum;
1302 GnmValue *v;
1303 int row, col, cur;
1304 struct assign_matrix_closure closure;
1306 if (size.rows <= 0 || size.columns <= 0) {
1307 dat->values = NULL;
1308 dat->minimum = go_nan;
1309 dat->maximum = go_nan;
1310 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
1311 return;
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);
1318 vals = dat->values;
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;
1344 } else
1345 minimum = maximum = vals[0] = go_nan;
1346 break;
1348 case VALUE_ARRAY :
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;
1357 continue;
1358 } else if (VALUE_IS_STRING (v)) {
1359 GnmValue *tmp = format_match_number
1360 (value_peek_string (v), NULL,
1361 closure.date_conv);
1362 if (tmp == NULL) {
1363 vals[cur] = go_nan;
1364 continue;
1366 vals[cur] = value_get_as_float (tmp);
1367 value_release (tmp);
1368 } else
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;
1377 break;
1379 case VALUE_STRING :
1380 v = format_match_number (value_peek_string (mat->val),
1381 NULL,
1382 closure.date_conv);
1383 if (v != NULL) {
1384 vals[0] = value_get_as_float (v);
1385 minimum = maximum = go_nan;
1386 value_release (v);
1387 break;
1389 /* fall through to errors */
1391 case VALUE_EMPTY :
1392 case VALUE_ERROR :
1393 minimum = maximum = vals[0] = go_nan;
1394 break;
1395 default :
1396 vals[0] = value_get_as_float (mat->val);
1397 minimum = maximum = go_nan;
1398 break;
1401 dat->values = vals;
1402 dat->minimum = minimum;
1403 dat->maximum = maximum;
1404 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
1407 static double
1408 gnm_go_data_matrix_get_value (GODataMatrix *dat, unsigned i, unsigned j)
1410 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1411 GnmValue *v;
1412 GnmEvalPos ep;
1413 gboolean valid;
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));
1421 if (NULL == v)
1422 return go_nan;
1424 v = value_coerce_to_number (v, &valid, &ep);
1425 if (valid) {
1426 gnm_float res = value_get_as_float (v);
1427 value_release (v);
1428 return res;
1430 value_release (v);
1431 return go_nan;
1434 static char *
1435 gnm_go_data_matrix_get_str (GODataMatrix *dat, unsigned i, unsigned j)
1437 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1438 GnmEvalPos ep;
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);
1449 static void
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;
1469 static void
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)
1476 static void
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)
1487 GOData *
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;
1507 return NULL;