GUI: Move .ui files from goffice resources to glib resources
[gnumeric.git] / src / graph.c
blob5896b953f6bdfa1f9d0aaf9fd63989d58d52bbe7
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 ? sheet_date_conv (ep->sheet) : 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 sheet_date_conv (dep->sheet);
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) &&
539 ((l = gnm_expr_top_get_ranges (vec->dep.texpr))) &&
540 l->next != NULL) {
541 unsigned len = g_slist_length (l);
542 GSList *cur = l;
543 unsigned i;
544 vec->val = value_new_array_empty (len, 1);
545 for (i = 0; i < len; i++) {
546 vec->val->v_array.vals[i][0] = cur->data;
547 cur = cur->next;
549 } else {
550 if (l) {
551 GSList *cur;
552 for (cur = l; cur != NULL; cur = cur->next)
553 value_release (cur->data);
555 vec->val = gnm_expr_top_eval (vec->dep.texpr, &ep,
556 GNM_EXPR_EVAL_PERMIT_NON_SCALAR | GNM_EXPR_EVAL_PERMIT_EMPTY | GNM_EXPR_EVAL_ARRAY_CONTEXT);
558 g_slist_free (l);
561 if (vec->val != NULL) {
562 switch (vec->val->v_any.type) {
563 case VALUE_CELLRANGE:
564 gnm_rangeref_normalize (&vec->val->v_range.cell, &ep,
565 &start_sheet, &end_sheet, &r);
567 /* add +1 to max_used so that we can have matrices with
568 * empty cells at the end, see #684072 */
569 if (r.end.col > start_sheet->cols.max_used)
570 r.end.col = start_sheet->cols.max_used + 1;
571 if (r.end.row > start_sheet->rows.max_used)
572 r.end.row = start_sheet->rows.max_used + 1;
574 if (r.end.col >= r.start.col && r.end.row >= r.start.row) {
575 guint w = range_width (&r);
576 guint h = range_height (&r);
577 vec->as_col = h > w;
578 new_len = (guint64)h * w * (end_sheet->index_in_wb - start_sheet->index_in_wb + 1);
580 break;
582 case VALUE_ARRAY : {
583 GnmValue *v;
584 int i, j;
585 new_len = 0;
586 for (j = 0; j < vec->val->v_array.y; j++)
587 for (i = 0; i < vec->val->v_array.x; i++) {
588 v = vec->val->v_array.vals[i][j];
589 if (VALUE_IS_CELLRANGE (v)) {
590 gnm_rangeref_normalize (&v->v_range.cell, &ep,
591 &start_sheet, &end_sheet, &r);
592 new_len += (guint64)range_width (&r) * range_height (&r)
593 * (end_sheet->index_in_wb - start_sheet->index_in_wb + 1);
594 } else
595 new_len++;
597 vec->as_col = (vec->val->v_array.y > vec->val->v_array.x);
598 break;
600 case VALUE_ERROR:
601 new_len = 0;
602 break;
604 default:
605 new_len = 1;
606 vec->as_col = TRUE;
608 } else
609 new_len = 0;
611 /* Protect against overflow in ->len as well as when allocating ->values. */
612 new_len = MIN (new_len, (gint64)(G_MAXINT / sizeof (dat->values[0])));
613 dat->len = new_len;
615 if (dat->values != NULL && old_len != dat->len) {
616 g_free (dat->values);
617 dat->values = NULL;
619 dat->base.flags |= GO_DATA_VECTOR_LEN_CACHED;
622 struct assign_closure {
623 const GODateConventions *date_conv;
624 double minimum, maximum;
625 double *vals;
626 gssize vals_len;
627 guint64 last;
628 guint64 i;
631 static GnmValue *
632 cb_assign_val (GnmCellIter const *iter, struct assign_closure *dat)
634 GnmValue *v;
635 double res;
637 if ((gssize)dat->i >= dat->vals_len)
638 return NULL;
640 if (iter->cell != NULL) {
641 gnm_cell_eval (iter->cell);
642 v = iter->cell->value;
643 } else
644 v = NULL;
646 if (VALUE_IS_EMPTY_OR_ERROR (v)) {
647 dat->vals[dat->i++] = go_nan;
648 return NULL;
651 dat->last = dat->i;
652 if (VALUE_IS_STRING (v)) {
653 v = format_match_number (value_peek_string (v), NULL,
654 dat->date_conv);
655 if (v == NULL) {
656 dat->vals[dat->i++] = go_nan;
657 return NULL;
659 res = value_get_as_float (v);
660 value_release (v);
661 } else
662 res = value_get_as_float (v);
664 dat->vals[dat->i++] = res;
665 if (dat->minimum > res)
666 dat->minimum = res;
667 if (dat->maximum < res)
668 dat->maximum = res;
669 return NULL;
672 static void
673 gnm_go_data_vector_load_values (GODataVector *dat)
675 GnmGODataVector *vec = (GnmGODataVector *)dat;
676 GnmEvalPos ep;
677 GnmRange r;
678 Sheet *start_sheet, *end_sheet;
679 double *vals, minimum, maximum;
680 GnmValue *v;
681 struct assign_closure closure;
683 (void)go_data_vector_get_len (dat); /* force calculation */
685 if (dat->len <= 0 || !vec->dep.sheet) {
686 dat->values = NULL;
687 dat->minimum = go_nan;
688 dat->maximum = go_nan;
689 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
690 return;
693 closure.date_conv = sheet_date_conv (vec->dep.sheet);
695 if (dat->values == NULL)
696 dat->values = g_new (double, dat->len);
697 vals = dat->values;
698 switch (vec->val->v_any.type) {
699 case VALUE_CELLRANGE:
700 gnm_rangeref_normalize (&vec->val->v_range.cell,
701 eval_pos_init_dep (&ep, &vec->dep),
702 &start_sheet, &end_sheet, &r);
704 /* clip here rather than relying on sheet_foreach
705 * because that only clips if we ignore blanks
706 * but add +1 to max_used so that we can have matrices with
707 * empty cells at the end, see #684072 */
708 if (r.end.row > start_sheet->rows.max_used)
709 r.end.row = start_sheet->rows.max_used + 1;
710 if (r.end.col > start_sheet->cols.max_used)
711 r.end.col = start_sheet->cols.max_used + 1;
713 /* In case the sheet is empty */
714 if (r.start.col <= r.end.col && r.start.row <= r.end.row) {
715 closure.maximum = - G_MAXDOUBLE;
716 closure.minimum = G_MAXDOUBLE;
717 closure.vals = dat->values;
718 closure.vals_len = dat->len;
719 closure.last = -1;
720 closure.i = 0;
721 if (start_sheet != end_sheet)
722 workbook_foreach_cell_in_range (&ep, vec->val,
723 CELL_ITER_IGNORE_FILTERED,
724 (CellIterFunc)cb_assign_val,
725 &closure);
726 else
727 sheet_foreach_cell_in_range
728 (start_sheet, CELL_ITER_IGNORE_FILTERED,
730 (CellIterFunc)cb_assign_val, &closure);
731 dat->len = closure.last + 1; /* clip */
732 minimum = closure.minimum;
733 maximum = closure.maximum;
734 } else
735 minimum = maximum = vals[0] = go_nan;
736 break;
738 case VALUE_ARRAY : {
739 guint64 last = 0, max = dat->len;
740 int len = vec->val->v_array.y * vec->val->v_array.x;
741 int x = 0, y = vec->val->v_array.y;
742 GnmValue *v;
743 maximum = - G_MAXDOUBLE;
744 minimum = G_MAXDOUBLE;
745 while (len-- > 0) {
746 if (x == 0) {
747 x = vec->val->v_array.x;
748 y--;
750 x--;
751 v = vec->val->v_array.vals [x][y];
753 if (VALUE_IS_CELLRANGE (v)) {
754 gnm_rangeref_normalize (&v->v_range.cell,
755 eval_pos_init_dep (&ep, &vec->dep),
756 &start_sheet, &end_sheet, &r);
758 /* clip here rather than relying on sheet_foreach
759 * because that only clips if we ignore blanks */
760 if (r.end.row > start_sheet->rows.max_used)
761 r.end.row = start_sheet->rows.max_used;
762 if (r.end.col > start_sheet->cols.max_used)
763 r.end.col = start_sheet->cols.max_used;
765 if (r.start.col <= r.end.col && r.start.row <= r.end.row) {
766 closure.maximum = - G_MAXDOUBLE;
767 closure.minimum = G_MAXDOUBLE;
768 closure.vals = dat->values;
769 closure.vals_len = max;
770 closure.last = last - 1;
771 closure.i = last;
772 if (start_sheet != end_sheet)
773 workbook_foreach_cell_in_range (&ep, vec->val,
774 CELL_ITER_IGNORE_FILTERED,
775 (CellIterFunc)cb_assign_val,
776 &closure);
777 else
778 sheet_foreach_cell_in_range (start_sheet,
779 CELL_ITER_IGNORE_FILTERED,
781 (CellIterFunc)cb_assign_val, &closure);
782 last = dat->len = closure.last + 1; /* clip */
783 if (minimum > closure.minimum)
784 minimum = closure.minimum;
785 if (maximum < closure.maximum)
786 maximum = closure.maximum;
788 continue;
789 } else if (VALUE_IS_EMPTY_OR_ERROR (v)) {
790 vals[len] = go_nan;
791 continue;
792 } else if (VALUE_IS_STRING (v)) {
793 GnmValue *tmp = format_match_number
794 (value_peek_string (v), NULL,
795 closure.date_conv);
796 if (tmp == NULL) {
797 vals[len] = go_nan;
798 continue;
800 vals[len] = value_get_as_float (tmp);
801 value_release (tmp);
802 } else
803 vals[len] = value_get_as_float (v);
804 if (minimum > vals[len])
805 minimum = vals[len];
806 if (maximum < vals[len])
807 maximum = vals[len];
809 break;
812 case VALUE_STRING:
813 v = format_match_number (value_peek_string (vec->val),
814 NULL,
815 closure.date_conv);
816 if (v != NULL) {
817 minimum = maximum = vals[0] = value_get_as_float (v);
818 value_release (v);
819 break;
821 /* fall through to errors */
823 case VALUE_EMPTY:
824 case VALUE_ERROR:
825 minimum = maximum = vals[0] = go_nan;
826 break;
827 default:
828 minimum = maximum = vals[0] = value_get_as_float (vec->val);
829 break;
832 dat->values = vals;
833 dat->minimum = minimum;
834 dat->maximum = maximum;
835 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
838 static double
839 gnm_go_data_vector_get_value (GODataVector *dat, unsigned i)
841 GnmGODataVector *vec = (GnmGODataVector *)dat;
842 GnmValue *v;
843 GnmEvalPos ep;
844 gboolean valid = FALSE;
846 if (vec->val == NULL)
847 gnm_go_data_vector_load_len (dat);
849 if (VALUE_IS_ARRAY (vec->val)) {
850 if ((dat->base.flags & GO_DATA_CACHE_IS_VALID) == 0)
851 gnm_go_data_vector_load_values (dat);
852 return dat->values[i];
853 } else {
854 eval_pos_init_dep (&ep, &vec->dep);
855 v = value_dup (vec->as_col
856 ? value_area_get_x_y (vec->val, 0, i, &ep)
857 : value_area_get_x_y (vec->val, i, 0, &ep));
858 if (NULL == v)
859 return go_nan;
861 v = value_coerce_to_number (v, &valid, &ep);
862 if (valid) {
863 gnm_float res = value_get_as_float (v);
864 value_release (v);
865 return res;
867 value_release (v);
869 return go_nan;
873 struct string_closure {
874 GPtrArray *strs;
875 GODateConventions const *date_conv;
878 static gpointer
879 cb_assign_string (GnmCellIter const *iter, struct string_closure *closure)
881 GnmValue *v = NULL;
882 char *str = NULL;
884 if (iter->cell != NULL) {
885 gnm_cell_eval (iter->cell);
886 v = iter->cell->value;
888 if (v != NULL)
889 str = format_value (gnm_cell_get_format (iter->cell), v, -1, closure->date_conv);
890 g_ptr_array_add (closure->strs, str);
892 return NULL;
895 static char *
896 gnm_go_data_vector_get_str (GODataVector *dat, unsigned i)
898 GnmGODataVector *vec = (GnmGODataVector *)dat;
899 GnmEvalPos ep;
900 int j;
901 GOFormat const *fmt = NULL;
902 char *ret = NULL;
903 GnmValue *v = NULL;
905 if (vec->val == NULL)
906 gnm_go_data_vector_load_len (dat);
907 g_return_val_if_fail (vec->val != NULL, NULL);
909 eval_pos_init_dep (&ep, &vec->dep);
910 if (VALUE_IS_ARRAY (vec->val)) {
911 /* we need to cache the strings if needed */
912 if (vec->strs == NULL) {
913 int len = vec->val->v_array.y * vec->val->v_array.x;
914 int x = 0, y = vec->val->v_array.y;
915 struct string_closure closure;
916 closure.strs = vec->strs = g_ptr_array_new_with_free_func (g_free);
917 closure.date_conv = ep.sheet ? sheet_date_conv (ep.sheet) : NULL;
918 while (len-- > 0) {
919 if (x == 0) {
920 x = vec->val->v_array.x;
921 y--;
923 x--;
924 v = vec->val->v_array.vals [x][y];
926 if (VALUE_IS_CELLRANGE (v)) {
927 /* actually we only need to cache in that case */
928 Sheet *start_sheet, *end_sheet;
929 GnmRange r;
930 gnm_rangeref_normalize (&v->v_range.cell,
931 eval_pos_init_dep (&ep, &vec->dep),
932 &start_sheet, &end_sheet, &r);
934 /* clip here rather than relying on sheet_foreach
935 * because that only clips if we ignore blanks */
936 if (r.end.row > start_sheet->rows.max_used)
937 r.end.row = start_sheet->rows.max_used;
938 if (r.end.col > start_sheet->cols.max_used)
939 r.end.col = start_sheet->cols.max_used;
941 if (r.start.col <= r.end.col && r.start.row <= r.end.row)
942 sheet_foreach_cell_in_range (start_sheet,
943 CELL_ITER_IGNORE_FILTERED,
945 (CellIterFunc)cb_assign_string, &closure);
949 if (vec->strs && vec->strs->len > i)
950 ret = g_ptr_array_index (vec->strs, i);
951 if (ret != NULL)
952 return g_strdup (ret);
953 } else if (VALUE_IS_CELLRANGE (vec->val)) {
954 Sheet *start_sheet, *end_sheet;
955 GnmRange r;
956 if (vec->strs == NULL) {
957 struct string_closure closure;
958 closure.strs = vec->strs = g_ptr_array_new_with_free_func (g_free);
959 closure.date_conv = ep.sheet ? sheet_date_conv (ep.sheet) : NULL;
960 gnm_rangeref_normalize (&vec->val->v_range.cell,
961 eval_pos_init_dep (&ep, &vec->dep),
962 &start_sheet, &end_sheet, &r);
964 /* clip here rather than relying on sheet_foreach
965 * because that only clips if we ignore blanks */
966 if (r.end.row > start_sheet->rows.max_used)
967 r.end.row = start_sheet->rows.max_used;
968 if (r.end.col > start_sheet->cols.max_used)
969 r.end.col = start_sheet->cols.max_used;
971 if (r.start.col <= r.end.col && r.start.row <= r.end.row)
972 sheet_foreach_cell_in_range (start_sheet,
973 CELL_ITER_IGNORE_FILTERED,
975 (CellIterFunc)cb_assign_string, &closure);
977 if (vec->strs && vec->strs->len > i)
978 ret = g_ptr_array_index (vec->strs, i);
979 if (ret != NULL)
980 return g_strdup (ret);
982 if (vec->as_col)
983 j = 0;
984 else
985 j = i, i = 0;
986 ret = render_val (((v != NULL)? v: vec->val), i, j, fmt, &ep);
987 return ret;
990 static void
991 cond_pango_attr_list_unref (PangoAttrList *al)
993 if (al)
994 pango_attr_list_unref (al);
997 static gpointer
998 cb_assign_markup (GnmCellIter const *iter, GPtrArray *markup)
1000 PangoAttrList const *l = NULL;
1002 if (iter->cell != NULL) {
1003 GOFormat const *fmt = gnm_cell_get_format (iter->cell);
1004 if (go_format_is_markup (fmt))
1005 l = go_format_get_markup (fmt);
1007 g_ptr_array_add (markup,
1008 l ? pango_attr_list_ref ((PangoAttrList *)l) : NULL);
1010 return NULL;
1013 static PangoAttrList *
1014 gnm_go_data_vector_get_markup (GODataVector *dat, unsigned i)
1016 GnmGODataVector *vec = (GnmGODataVector *)dat;
1018 if (vec->markup == NULL) {
1019 /* load markups */
1020 GnmEvalPos ep;
1021 GnmRange r;
1022 Sheet *start_sheet, *end_sheet;
1023 GnmValue *v;
1025 go_data_vector_get_len (dat); /* force calculation */
1026 if (dat->len <= 0 || !vec->dep.sheet)
1027 return NULL;
1028 vec->markup = g_ptr_array_new_with_free_func
1029 ((GDestroyNotify)cond_pango_attr_list_unref);
1030 switch (vec->val->v_any.type) {
1031 case VALUE_CELLRANGE:
1032 gnm_rangeref_normalize (&vec->val->v_range.cell,
1033 eval_pos_init_dep (&ep, &vec->dep),
1034 &start_sheet, &end_sheet, &r);
1036 /* clip here rather than relying on sheet_foreach
1037 * because that only clips if we ignore blanks */
1038 if (r.end.row > start_sheet->rows.max_used)
1039 r.end.row = start_sheet->rows.max_used;
1040 if (r.end.col > start_sheet->cols.max_used)
1041 r.end.col = start_sheet->cols.max_used;
1043 /* In case the sheet is empty */
1044 if (r.start.col <= r.end.col && r.start.row <= r.end.row) {
1045 sheet_foreach_cell_in_range (start_sheet,
1046 CELL_ITER_ALL,
1048 (CellIterFunc)cb_assign_markup, vec->markup);
1050 break;
1052 case VALUE_ARRAY: {
1053 int len = vec->as_col? vec->val->v_array.y: vec->val->v_array.x;
1054 while (len-- > 0) {
1055 v = vec->as_col
1056 ? vec->val->v_array.vals [0][len]
1057 : vec->val->v_array.vals [len][0];
1059 if (VALUE_IS_CELLRANGE (v)) {
1060 gnm_rangeref_normalize (&v->v_range.cell,
1061 eval_pos_init_dep (&ep, &vec->dep),
1062 &start_sheet, &end_sheet, &r);
1064 /* clip here rather than relying on sheet_foreach
1065 * because that only clips if we ignore blanks */
1066 if (r.end.row > start_sheet->rows.max_used)
1067 r.end.row = start_sheet->rows.max_used;
1068 if (r.end.col > start_sheet->cols.max_used)
1069 r.end.col = start_sheet->cols.max_used;
1071 if (r.start.col <= r.end.col && r.start.row <= r.end.row)
1072 sheet_foreach_cell_in_range (start_sheet,
1073 CELL_ITER_ALL,
1075 (CellIterFunc)cb_assign_markup, vec->markup);
1078 break;
1081 default:
1082 break;
1086 return pango_attr_list_copy ((vec->markup->len > i)?
1087 g_ptr_array_index (vec->markup, i): NULL);
1090 static void
1091 gnm_go_data_vector_class_init (GObjectClass *gobject_klass)
1093 GODataClass *godata_klass = (GODataClass *) gobject_klass;
1094 GODataVectorClass *vector_klass = (GODataVectorClass *) gobject_klass;
1096 vector_parent_klass = g_type_class_peek_parent (gobject_klass);
1097 gobject_klass->finalize = gnm_go_data_vector_finalize;
1098 godata_klass->dup = gnm_go_data_dup;
1099 godata_klass->eq = gnm_go_data_eq;
1100 godata_klass->preferred_fmt = gnm_go_data_preferred_fmt;
1101 godata_klass->date_conv = gnm_go_data_date_conv;
1102 godata_klass->serialize = gnm_go_data_serialize;
1103 godata_klass->unserialize = gnm_go_data_unserialize;
1104 vector_klass->load_len = gnm_go_data_vector_load_len;
1105 vector_klass->load_values = gnm_go_data_vector_load_values;
1106 vector_klass->get_value = gnm_go_data_vector_get_value;
1107 vector_klass->get_str = gnm_go_data_vector_get_str;
1108 vector_klass->get_markup = gnm_go_data_vector_get_markup;
1111 static void
1112 gnm_go_data_vector_debug_name (GnmDependent const *dep, GString *target)
1114 g_string_append_printf (target, "GraphVector%p", (void *)dep);
1116 static DEPENDENT_MAKE_TYPE (gnm_go_data_vector, NULL)
1118 static void
1119 gnm_go_data_vector_init (GObject *obj)
1121 GnmGODataVector *vec = (GnmGODataVector *)obj;
1122 vec->dep.flags = gnm_go_data_vector_get_dep_type ();
1125 GSF_CLASS (GnmGODataVector, gnm_go_data_vector,
1126 gnm_go_data_vector_class_init, gnm_go_data_vector_init,
1127 GO_TYPE_DATA_VECTOR)
1129 GOData *
1130 gnm_go_data_vector_new_expr (Sheet *sheet, GnmExprTop const *texpr)
1132 GnmGODataVector *res = g_object_new (gnm_go_data_vector_get_type (), NULL);
1133 res->dep.texpr = texpr;
1134 res->dep.sheet = sheet;
1135 return GO_DATA (res);
1138 /**************************************************************************/
1140 struct _GnmGODataMatrix {
1141 GODataMatrix base;
1142 GnmDependent dep;
1143 GnmValue *val;
1145 typedef GODataMatrixClass GnmGODataMatrixClass;
1147 #define DEP_TO_MATRIX(d_ptr) (GnmGODataMatrix *)(((char *)d_ptr) - G_STRUCT_OFFSET (GnmGODataMatrix, dep))
1149 static GObjectClass *matrix_parent_klass;
1151 static void
1152 gnm_go_data_matrix_eval (GnmDependent *dep)
1154 GnmGODataMatrix *mat = DEP_TO_MATRIX (dep);
1156 value_release (mat->val);
1157 mat->val = NULL;
1158 go_data_emit_changed (GO_DATA (mat));
1161 static void
1162 gnm_go_data_matrix_finalize (GObject *obj)
1164 GnmGODataMatrix *mat = (GnmGODataMatrix *)obj;
1166 dependent_set_expr (&mat->dep, NULL);
1167 value_release (mat->val);
1168 mat->val = NULL;
1170 g_free (mat->base.values);
1171 mat->base.values = NULL;
1173 matrix_parent_klass->finalize (obj);
1176 static void
1177 gnm_go_data_matrix_load_size (GODataMatrix *dat)
1179 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1180 GnmEvalPos ep;
1181 GnmRange r;
1182 Sheet *start_sheet, *end_sheet;
1183 unsigned h, w;
1184 int old_rows = dat->size.rows, old_columns = dat->size.columns;
1186 eval_pos_init_dep (&ep, &mat->dep);
1187 if (mat->val == NULL) {
1188 mat->val = gnm_expr_top_eval (mat->dep.texpr, &ep,
1189 GNM_EXPR_EVAL_PERMIT_NON_SCALAR | GNM_EXPR_EVAL_PERMIT_EMPTY);
1192 if (mat->val != NULL) {
1193 switch (mat->val->v_any.type) {
1194 case VALUE_CELLRANGE:
1195 gnm_rangeref_normalize (&mat->val->v_range.cell, &ep,
1196 &start_sheet, &end_sheet, &r);
1197 if (r.end.col > start_sheet->cols.max_used)
1198 r.end.col = start_sheet->cols.max_used;
1199 if (r.end.row > start_sheet->rows.max_used)
1200 r.end.row = start_sheet->rows.max_used;
1202 if (r.end.col >= r.start.col && r.end.row >= r.start.row) {
1203 w = range_width (&r);
1204 h = range_height (&r);
1205 if (w > 0 && h > 0) {
1206 dat->size.rows = h;
1207 dat->size.columns = w;
1209 else {
1210 dat->size.rows = 0;
1211 dat->size.columns = 0;
1213 } else {
1214 dat->size.rows = 0;
1215 dat->size.columns = 0;
1217 break;
1219 case VALUE_ARRAY:
1220 dat->size.rows = mat->val->v_array.y;
1221 dat->size.columns = mat->val->v_array.x;
1222 break;
1224 default:
1225 dat->size.rows = 1;
1226 dat->size.columns = 1;
1228 } else {
1229 dat->size.rows = 0;
1230 dat->size.columns = 0;
1232 if (dat->values != NULL &&
1233 (old_rows != dat->size.rows || old_columns != dat->size.columns)) {
1234 g_free (dat->values);
1235 dat->values = NULL;
1237 dat->base.flags |= GO_DATA_MATRIX_SIZE_CACHED;
1240 struct assign_matrix_closure {
1241 const GODateConventions *date_conv;
1242 double minimum, maximum;
1243 double *vals;
1244 int first_row, first_col;
1245 int last_row, last_col;
1246 int row, col, columns, k;
1249 static GnmValue *
1250 cb_assign_matrix_val (GnmCellIter const *iter,
1251 struct assign_matrix_closure *dat)
1253 GnmValue *v;
1254 double res;
1256 if (dat->first_col == -1)
1257 dat->first_col = iter->pp.eval.col;
1258 dat->col = iter->pp.eval.col - dat->first_col;
1259 if (dat->first_row == -1)
1260 dat->first_row = iter->pp.eval.row;
1261 dat->row = iter->pp.eval.row - dat->first_row;
1263 if (iter->cell != NULL) {
1264 gnm_cell_eval (iter->cell);
1265 v = iter->cell->value;
1266 } else
1267 v = NULL;
1270 if (VALUE_IS_EMPTY_OR_ERROR (v)) {
1271 dat->vals[dat->row * dat->columns + dat->col] = go_nan;
1272 return NULL;
1275 if (dat->last_row < dat->row)
1276 dat->last_row = dat->row;
1277 if (dat->last_col < dat->col)
1278 dat->last_col = dat->col;
1280 if (VALUE_IS_STRING (v)) {
1281 v = format_match_number (value_peek_string (v), NULL,
1282 dat->date_conv);
1283 if (v == NULL) {
1284 dat->vals[dat->row * dat->columns + dat->col] = go_nan;
1285 /* may be go_pinf should be more appropriate? */
1286 return NULL;
1288 res = value_get_as_float (v);
1289 value_release (v);
1290 } else
1291 res = value_get_as_float (v);
1293 dat->vals[dat->row * dat->columns + dat->col] = res;
1294 if (dat->minimum > res)
1295 dat->minimum = res;
1296 if (dat->maximum < res)
1297 dat->maximum = res;
1298 return NULL;
1301 static void
1302 gnm_go_data_matrix_load_values (GODataMatrix *dat)
1304 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1305 GnmEvalPos ep;
1306 GnmRange r;
1307 Sheet *start_sheet, *end_sheet;
1308 GODataMatrixSize size = go_data_matrix_get_size (dat); /* force calculation */
1309 double *vals, minimum, maximum;
1310 GnmValue *v;
1311 int row, col, cur;
1312 struct assign_matrix_closure closure;
1314 if (size.rows <= 0 || size.columns <= 0) {
1315 dat->values = NULL;
1316 dat->minimum = go_nan;
1317 dat->maximum = go_nan;
1318 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
1319 return;
1322 closure.date_conv = sheet_date_conv (mat->dep.sheet);
1324 if (dat->values == NULL)
1325 dat->values = g_new (double, size.rows * size.columns);
1326 vals = dat->values;
1327 switch (mat->val->v_any.type) {
1328 case VALUE_CELLRANGE:
1329 gnm_rangeref_normalize (&mat->val->v_range.cell,
1330 eval_pos_init_dep (&ep, &mat->dep),
1331 &start_sheet, &end_sheet, &r);
1333 /* In case the sheet is empty */
1334 if (r.start.col <= r.end.col && r.start.row <= r.end.row) {
1335 closure.maximum = - G_MAXDOUBLE;
1336 closure.minimum = G_MAXDOUBLE;
1337 closure.vals = dat->values;
1338 closure.first_row = closure.last_row = -1;
1339 closure.first_col = closure.last_col = -1;
1340 closure.row = closure.col = 0;
1341 closure.columns = dat->size.columns;
1342 sheet_foreach_cell_in_region (start_sheet, CELL_ITER_ALL,
1343 r.start.col, r.start.row,
1344 r.start.col + dat->size.columns - 1,
1345 r.start.row + dat->size.rows - 1,
1346 (CellIterFunc)cb_assign_matrix_val, &closure);
1347 #warning "Should we clip the matrix?"
1348 minimum = closure.minimum;
1349 maximum = closure.maximum;
1350 if (minimum > maximum)
1351 minimum = maximum = go_nan;
1352 } else
1353 minimum = maximum = vals[0] = go_nan;
1354 break;
1356 case VALUE_ARRAY:
1357 maximum = - G_MAXDOUBLE;
1358 minimum = G_MAXDOUBLE;
1359 for (col = 0; col < size.columns; col ++)
1360 for (row = 0; row < size.rows; row++) {
1361 v = mat->val->v_array.vals[col][row];
1362 cur = col * size.rows + row;
1363 if (VALUE_IS_EMPTY_OR_ERROR (v)) {
1364 vals[row * size.columns + col] = go_nan;
1365 continue;
1366 } else if (VALUE_IS_STRING (v)) {
1367 GnmValue *tmp = format_match_number
1368 (value_peek_string (v), NULL,
1369 closure.date_conv);
1370 if (tmp == NULL) {
1371 vals[cur] = go_nan;
1372 continue;
1374 vals[cur] = value_get_as_float (tmp);
1375 value_release (tmp);
1376 } else
1377 vals[cur] = value_get_as_float (v);
1378 if (minimum > vals[cur])
1379 minimum = vals[cur];
1380 if (maximum < vals[cur])
1381 maximum = vals[cur];
1383 if (minimum > maximum)
1384 minimum = maximum = go_nan;
1385 break;
1387 case VALUE_STRING:
1388 v = format_match_number (value_peek_string (mat->val),
1389 NULL,
1390 closure.date_conv);
1391 if (v != NULL) {
1392 vals[0] = value_get_as_float (v);
1393 minimum = maximum = go_nan;
1394 value_release (v);
1395 break;
1397 /* fall through to errors */
1399 case VALUE_EMPTY:
1400 case VALUE_ERROR:
1401 minimum = maximum = vals[0] = go_nan;
1402 break;
1403 default:
1404 vals[0] = value_get_as_float (mat->val);
1405 minimum = maximum = go_nan;
1406 break;
1409 dat->values = vals;
1410 dat->minimum = minimum;
1411 dat->maximum = maximum;
1412 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
1415 static double
1416 gnm_go_data_matrix_get_value (GODataMatrix *dat, unsigned i, unsigned j)
1418 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1419 GnmValue *v;
1420 GnmEvalPos ep;
1421 gboolean valid;
1423 if (mat->val == NULL)
1424 gnm_go_data_matrix_load_size (dat);
1426 eval_pos_init_dep (&ep, &mat->dep);
1427 /* i is row and j is column */
1428 v = value_dup (value_area_get_x_y (mat->val, j, i, &ep));
1429 if (NULL == v)
1430 return go_nan;
1432 v = value_coerce_to_number (v, &valid, &ep);
1433 if (valid) {
1434 gnm_float res = value_get_as_float (v);
1435 value_release (v);
1436 return res;
1438 value_release (v);
1439 return go_nan;
1442 static char *
1443 gnm_go_data_matrix_get_str (GODataMatrix *dat, unsigned i, unsigned j)
1445 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1446 GnmEvalPos ep;
1447 GOFormat const *fmt = NULL;
1449 if (mat->val == NULL)
1450 gnm_go_data_matrix_load_size (dat);
1451 g_return_val_if_fail (mat->val != NULL, NULL);
1453 eval_pos_init_dep (&ep, &mat->dep);
1454 return render_val (mat->val, i, j, fmt, &ep);
1457 static void
1458 gnm_go_data_matrix_class_init (GObjectClass *gobject_klass)
1460 GODataClass *godata_klass = (GODataClass *) gobject_klass;
1461 GODataMatrixClass *matrix_klass = (GODataMatrixClass *) gobject_klass;
1463 matrix_parent_klass = g_type_class_peek_parent (gobject_klass);
1464 gobject_klass->finalize = gnm_go_data_matrix_finalize;
1465 godata_klass->dup = gnm_go_data_dup;
1466 godata_klass->eq = gnm_go_data_eq;
1467 godata_klass->preferred_fmt = gnm_go_data_preferred_fmt;
1468 godata_klass->date_conv = gnm_go_data_date_conv;
1469 godata_klass->serialize = gnm_go_data_serialize;
1470 godata_klass->unserialize = gnm_go_data_unserialize;
1471 matrix_klass->load_size = gnm_go_data_matrix_load_size;
1472 matrix_klass->load_values = gnm_go_data_matrix_load_values;
1473 matrix_klass->get_value = gnm_go_data_matrix_get_value;
1474 matrix_klass->get_str = gnm_go_data_matrix_get_str;
1477 static void
1478 gnm_go_data_matrix_debug_name (GnmDependent const *dep, GString *target)
1480 g_string_append_printf (target, "GraphMatrix%p", (void *)dep);
1482 static DEPENDENT_MAKE_TYPE (gnm_go_data_matrix, NULL)
1484 static void
1485 gnm_go_data_matrix_init (GObject *obj)
1487 GnmGODataMatrix *mat = (GnmGODataMatrix *)obj;
1488 mat->dep.flags = gnm_go_data_matrix_get_dep_type ();
1491 GSF_CLASS (GnmGODataMatrix, gnm_go_data_matrix,
1492 gnm_go_data_matrix_class_init, gnm_go_data_matrix_init,
1493 GO_TYPE_DATA_MATRIX)
1495 GOData *
1496 gnm_go_data_matrix_new_expr (Sheet *sheet, GnmExprTop const *texpr)
1498 GnmGODataMatrix *res = g_object_new (gnm_go_data_matrix_get_type (), NULL);
1499 res->dep.texpr = texpr;
1500 res->dep.sheet = sheet;
1501 return GO_DATA (res);
1504 /*******************************************************************************/
1506 static GnmDependent *
1507 gnm_go_data_get_dep (GOData const *dat)
1509 if (GNM_IS_GO_DATA_SCALAR (dat))
1510 return &((GnmGODataScalar *)dat)->dep;
1511 if (GNM_IS_GO_DATA_VECTOR (dat))
1512 return &((GnmGODataVector *)dat)->dep;
1513 if (GNM_IS_GO_DATA_MATRIX (dat))
1514 return &((GnmGODataMatrix *)dat)->dep;
1515 return NULL;