Update Spanish translation
[gnumeric.git] / src / graph.c
blobcd1fcd3112261727fe9dcd6addc92a468be1af4f
1 /*
2 * graph.c: The gnumeric specific data wrappers for GOffice
4 * Copyright (C) 2003-2005 Jody Goldberg (jody@gnome.org)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) version 3.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 * USA
21 #include <gnumeric-config.h>
22 #include <graph.h>
23 #include <dependent.h>
24 #include <expr.h>
25 #include <cell.h>
26 #include <value.h>
27 #include <number-match.h>
28 #include <mathfunc.h>
29 #include <sheet.h>
30 #include <workbook.h>
31 #include <position.h>
32 #include <gnm-format.h>
33 #include <auto-format.h>
34 #include <ranges.h>
35 #include <parse-util.h>
36 #include <expr-impl.h>
37 #include <goffice/goffice.h>
39 #include <gsf/gsf-impl-utils.h>
40 #include <string.h>
42 /* ------------------------------------------------------------------------- */
44 static char *
45 get_pending_str (const GOData *data)
47 return g_object_get_data (G_OBJECT (data), "unserialize");
50 static GnmConventions *
51 get_pending_convs (const GOData *data)
53 return g_object_get_data (G_OBJECT (data), "unserialize-convs");
56 static void
57 set_pending_str (const GOData *data, const char *str)
59 g_object_set_data_full (G_OBJECT (data),
60 "unserialize", g_strdup (str),
61 g_free);
64 static void
65 set_pending_convs (GOData *data, const GnmConventions *convs)
67 g_object_set_data_full (G_OBJECT (data),
68 "unserialize-convs",
69 gnm_conventions_ref ((gpointer)convs),
70 (GDestroyNotify)gnm_conventions_unref);
73 /* ------------------------------------------------------------------------- */
75 static char *
76 render_val (GnmValue const *v, int i, int j,
77 GOFormat const *fmt, GnmEvalPos const *ep)
79 GODateConventions const *date_conv;
81 if (!v)
82 return NULL;
84 date_conv = ep->sheet ? sheet_date_conv (ep->sheet) : NULL;
86 #if 0
87 g_printerr ("Rendering %s with fmt=%s\n",
88 value_peek_string (v),
89 fmt ? go_format_as_XL (fmt) : "-");
90 #endif
92 if (VALUE_IS_CELLRANGE (v)) {
93 Sheet *start_sheet, *end_sheet;
94 GnmCell *cell;
95 GnmRange r;
97 gnm_rangeref_normalize (&v->v_range.cell, ep,
98 &start_sheet, &end_sheet, &r);
99 r.start.row += i;
100 r.start.col += j;
101 cell = sheet_cell_get (start_sheet, r.start.col, r.start.row);
102 if (cell == NULL)
103 return NULL;
104 gnm_cell_eval (cell);
105 v = cell->value;
107 if (fmt == NULL)
108 fmt = gnm_cell_get_format (cell);
109 } else if (VALUE_IS_ARRAY (v))
110 v = value_area_get_x_y (v, i, j, ep);
112 return format_value (fmt, v, -1, date_conv);
115 /* ------------------------------------------------------------------------- */
117 static GnmDependent *gnm_go_data_get_dep (GOData const *obj);
119 static GOData *
120 gnm_go_data_dup (GOData const *src)
122 GOData *dst = g_object_new (G_OBJECT_TYPE (src), NULL);
123 GnmDependent const *src_dep = gnm_go_data_get_dep (src);
124 GnmDependent *dst_dep = gnm_go_data_get_dep (dst);
126 dst_dep->texpr = src_dep->texpr;
127 if (dst_dep->texpr)
128 gnm_expr_top_ref (dst_dep->texpr);
130 if (src_dep->sheet)
131 dependent_set_sheet (dst_dep, src_dep->sheet);
133 if (dst_dep->texpr == NULL) {
134 set_pending_str (dst, get_pending_str (src));
135 set_pending_convs (dst, get_pending_convs (src));
138 return GO_DATA (dst);
141 static gboolean
142 gnm_go_data_eq (GOData const *data_a, GOData const *data_b)
144 GnmDependent const *a = gnm_go_data_get_dep (data_a);
145 GnmDependent const *b = gnm_go_data_get_dep (data_b);
147 if (a->texpr == NULL && b->texpr == NULL) {
148 if (go_str_compare (get_pending_str (data_a),
149 get_pending_str (data_b)))
150 return FALSE;
151 if (get_pending_convs (data_a) != get_pending_convs (data_b))
152 return FALSE;
153 return TRUE;
156 return a->texpr && b->texpr && gnm_expr_top_equal (a->texpr, b->texpr);
159 static GOFormat *
160 gnm_go_data_preferred_fmt (GOData const *dat)
162 GnmEvalPos ep;
163 GnmDependent const *dep = gnm_go_data_get_dep (dat);
165 g_return_val_if_fail (dep != NULL, NULL);
167 eval_pos_init_dep (&ep, dep);
168 return dep->texpr
169 ? (GOFormat *)gnm_auto_style_format_suggest (dep->texpr, &ep)
170 : NULL;
173 static GODateConventions const *
174 gnm_go_data_date_conv (GOData const *dat)
176 GnmDependent const *dep = gnm_go_data_get_dep (dat);
178 g_return_val_if_fail (dep != NULL, NULL);
180 if (!dep->sheet)
181 return NULL;
183 return sheet_date_conv (dep->sheet);
186 static char *
187 gnm_go_data_serialize (GOData const *dat, gpointer user)
189 GnmParsePos pp;
190 GnmConventions const *convs = user;
191 GnmDependent const *dep = gnm_go_data_get_dep (dat);
192 char *res;
193 if (dep->sheet == NULL)
194 return g_strdup ("No sheet for GnmGOData");
195 if (!convs) {
196 g_warning ("NULL convs in gnm_go_data_serialize");
197 convs = gnm_conventions_default;
200 res = gnm_expr_top_as_string (dep->texpr,
201 parse_pos_init_dep (&pp, dep),
202 convs);
203 #if 0
204 g_printerr ("Serializing %s\n", res);
205 #endif
206 return res;
209 static gboolean
210 gnm_go_data_unserialize (GOData *dat, char const *str, gpointer user)
212 GnmConventions const *convs = user;
213 GnmExprTop const *texpr;
214 GnmParsePos pp;
215 GnmDependent *dep = gnm_go_data_get_dep (dat);
217 if (!convs) {
218 g_warning ("NULL convs in gnm_go_data_serialize");
219 convs = gnm_conventions_default;
222 /* It is too early in the life cycle to know where we
223 * are. Wait until later when we parse the sheet */
224 if (dep->sheet == NULL) {
225 set_pending_str (dat, str);
226 /* Ugh. We assume that convs will stay valid. */
227 set_pending_convs (dat, convs);
228 return TRUE;
231 parse_pos_init_dep (&pp, dep);
232 texpr = gnm_expr_parse_str (str, &pp, (GO_IS_DATA_VECTOR (dat))?
233 GNM_EXPR_PARSE_PERMIT_MULTIPLE_EXPRESSIONS:
234 GNM_EXPR_PARSE_DEFAULT,
235 convs, NULL);
236 if (texpr != NULL) {
237 dependent_set_expr (dep, texpr);
238 gnm_expr_top_unref (texpr);
239 return TRUE;
241 return FALSE;
244 void
245 gnm_go_data_set_sheet (GOData *dat, Sheet *sheet)
247 GnmDependent *dep = gnm_go_data_get_dep (dat);
249 if (dep == NULL)
250 return;
252 if (dependent_is_linked (dep)) {
253 dependent_unlink (dep);
254 dep->sheet = NULL;
257 if (sheet == NULL)
258 return;
260 /* no expression?
261 * Do we need to parse one now that we have more context ? */
262 if (dep->texpr == NULL) {
263 char const *str = get_pending_str (dat);
264 GnmConventions *convs = get_pending_convs (dat);
265 if (str != NULL) { /* bingo */
266 dep->sheet = sheet; /* cheat a bit */
267 if (gnm_go_data_unserialize (dat, str, convs)) {
268 set_pending_str (dat, NULL);
269 set_pending_convs (dat, NULL);
270 go_data_emit_changed (GO_DATA (dat));
275 dep->sheet = NULL;
276 dependent_set_sheet (dep, sheet);
280 * gnm_go_data_get_sheet:
281 * @dat: #GOData
283 * Returns: (transfer none): the sheet.
285 Sheet *
286 gnm_go_data_get_sheet (GOData const *dat)
288 GnmDependent *dep = gnm_go_data_get_dep (dat);
289 g_return_val_if_fail (dep != NULL, NULL);
290 return dep->sheet;
293 GnmExprTop const *
294 gnm_go_data_get_expr (GOData const *dat)
296 GnmDependent *dep = gnm_go_data_get_dep (dat);
297 if (!dep)
298 return NULL;
299 return dep->texpr;
303 * gnm_go_data_foreach_dep:
304 * @dat: #GOData
305 * @so: #SheetObject
306 * @func: (scope call):
307 * @user: user data.
310 void
311 gnm_go_data_foreach_dep (GOData *dat, SheetObject *so,
312 SheetObjectForeachDepFunc func, gpointer user)
314 GnmDependent *dep = gnm_go_data_get_dep (dat);
315 if (dep)
316 func (dep, so, user);
319 /**************************************************************************/
321 struct _GnmGODataScalar {
322 GODataScalar base;
323 GnmDependent dep;
324 GnmValue *val;
325 char *val_str;
327 typedef GODataScalarClass GnmGODataScalarClass;
329 #define DEP_TO_SCALAR(d_ptr) (GnmGODataScalar *)(((char *)d_ptr) - G_STRUCT_OFFSET (GnmGODataScalar, dep))
331 static GObjectClass *scalar_parent_klass;
333 static GnmValue *
334 scalar_get_val (GnmGODataScalar *scalar)
336 if (scalar->val != NULL) {
337 value_release (scalar->val);
338 scalar->val = NULL;
339 g_free (scalar->val_str);
340 scalar->val_str = NULL;
342 if (scalar->val == NULL) {
343 if (scalar->dep.texpr != NULL) {
344 GnmEvalPos pos;
346 eval_pos_init_dep (&pos, &scalar->dep);
348 scalar->val = gnm_expr_top_eval
349 (scalar->dep.texpr, &pos,
350 GNM_EXPR_EVAL_PERMIT_EMPTY);
351 } else
352 scalar->val = value_new_empty ();
354 return scalar->val;
357 static void
358 gnm_go_data_scalar_eval (GnmDependent *dep)
360 GnmGODataScalar *scalar = DEP_TO_SCALAR (dep);
362 value_release (scalar->val);
363 scalar->val = NULL;
364 g_free (scalar->val_str);
365 scalar->val_str = NULL;
366 go_data_emit_changed (GO_DATA (scalar));
369 static void
370 gnm_go_data_scalar_finalize (GObject *obj)
372 GnmGODataScalar *scalar = (GnmGODataScalar *)obj;
374 dependent_set_expr (&scalar->dep, NULL);
375 value_release (scalar->val);
376 scalar->val = NULL;
377 g_free (scalar->val_str);
378 scalar->val_str = NULL;
380 scalar_parent_klass->finalize (obj);
383 static double
384 gnm_go_data_scalar_get_value (GODataScalar *dat)
386 return value_get_as_float (scalar_get_val ((GnmGODataScalar *)dat));
389 static char const *
390 gnm_go_data_scalar_get_str (GODataScalar *dat)
392 GnmGODataScalar *scalar = (GnmGODataScalar *)dat;
393 GOFormat const *fmt = NULL;
395 if (scalar->val_str == NULL) {
396 GnmEvalPos ep;
398 eval_pos_init_dep (&ep, &scalar->dep);
399 if (scalar->dep.texpr)
400 fmt = gnm_auto_style_format_suggest (scalar->dep.texpr, &ep);
401 scalar->val_str =
402 render_val (scalar_get_val (scalar), 0, 0, fmt, &ep);
404 go_format_unref (fmt);
405 return scalar->val_str;
408 static PangoAttrList const *
409 gnm_go_data_scalar_get_markup (GODataScalar *dat)
411 PangoAttrList const *res = NULL;
412 GOFormat const *fmt = gnm_go_data_preferred_fmt (GO_DATA (dat));
413 if (fmt && go_format_is_markup (fmt))
414 res = go_format_get_markup (fmt);
415 go_format_unref (fmt);
416 return res;
419 static void
420 gnm_go_data_scalar_class_init (GObjectClass *gobject_klass)
422 GODataClass *godata_klass = (GODataClass *) gobject_klass;
423 GODataScalarClass *scalar_klass = (GODataScalarClass *) gobject_klass;
425 scalar_parent_klass = g_type_class_peek_parent (gobject_klass);
426 gobject_klass->finalize = gnm_go_data_scalar_finalize;
427 godata_klass->dup = gnm_go_data_dup;
428 godata_klass->eq = gnm_go_data_eq;
429 godata_klass->preferred_fmt = gnm_go_data_preferred_fmt;
430 godata_klass->date_conv = gnm_go_data_date_conv;
431 godata_klass->serialize = gnm_go_data_serialize;
432 godata_klass->unserialize = gnm_go_data_unserialize;
433 scalar_klass->get_value = gnm_go_data_scalar_get_value;
434 scalar_klass->get_str = gnm_go_data_scalar_get_str;
435 scalar_klass->get_markup = gnm_go_data_scalar_get_markup;
438 static void
439 gnm_go_data_scalar_debug_name (GnmDependent const *dep, GString *target)
441 g_string_append_printf (target, "GraphScalar%p", (void *)dep);
444 static DEPENDENT_MAKE_TYPE (gnm_go_data_scalar, NULL)
446 static void
447 gnm_go_data_scalar_init (GObject *obj)
449 GnmGODataScalar *scalar = (GnmGODataScalar *)obj;
450 scalar->dep.flags = gnm_go_data_scalar_get_dep_type ();
453 GSF_CLASS (GnmGODataScalar, gnm_go_data_scalar,
454 gnm_go_data_scalar_class_init, gnm_go_data_scalar_init,
455 GO_TYPE_DATA_SCALAR)
457 GOData *
458 gnm_go_data_scalar_new_expr (Sheet *sheet, GnmExprTop const *texpr)
460 GnmGODataScalar *res = g_object_new (gnm_go_data_scalar_get_type (), NULL);
461 res->dep.texpr = texpr;
462 res->dep.sheet = sheet;
463 return GO_DATA (res);
466 /**************************************************************************/
468 struct _GnmGODataVector {
469 GODataVector base;
470 GnmDependent dep;
471 GnmValue *val;
472 gboolean as_col;
473 GPtrArray *markup;
474 GPtrArray *strs;
476 typedef GODataVectorClass GnmGODataVectorClass;
478 #define DEP_TO_VECTOR(d_ptr) (GnmGODataVector *)(((char *)d_ptr) - G_STRUCT_OFFSET (GnmGODataVector, dep))
480 static GObjectClass *vector_parent_klass;
482 static void
483 gnm_go_data_vector_eval (GnmDependent *dep)
485 GnmGODataVector *vec = DEP_TO_VECTOR (dep);
487 value_release (vec->val);
488 vec->val = NULL;
489 if (vec->markup) {
490 g_ptr_array_free (vec->markup, TRUE);
491 vec->markup = NULL;
493 if (vec->strs) {
494 g_ptr_array_free (vec->strs, TRUE);
495 vec->strs = NULL;
497 go_data_emit_changed (GO_DATA (vec));
500 static void
501 gnm_go_data_vector_finalize (GObject *obj)
503 GnmGODataVector *vec = (GnmGODataVector *)obj;
505 dependent_set_expr (&vec->dep, NULL);
506 value_release (vec->val);
507 vec->val = NULL;
509 g_free (vec->base.values);
510 vec->base.values = NULL;
511 if (vec->markup) {
512 g_ptr_array_free (vec->markup, TRUE);
513 vec->markup = NULL;
515 if (vec->strs) {
516 g_ptr_array_free (vec->strs, TRUE);
517 vec->strs = NULL;
520 vector_parent_klass->finalize (obj);
523 static void
524 gnm_go_data_vector_load_len (GODataVector *dat)
526 GnmGODataVector *vec = (GnmGODataVector *)dat;
527 GnmEvalPos ep;
528 GnmRange r;
529 Sheet *start_sheet, *end_sheet;
530 int old_len = dat->len;
531 guint64 new_len = 0;
533 eval_pos_init_dep (&ep, &vec->dep);
534 if (vec->val == NULL && vec->dep.texpr != NULL) {
535 GSList *l = NULL;
536 if (GNM_EXPR_GET_OPER (vec->dep.texpr->expr) == GNM_EXPR_OP_SET &&
537 gnm_expr_is_rangeref (vec->dep.texpr->expr) &&
538 ((l = gnm_expr_top_get_ranges (vec->dep.texpr))) &&
539 l->next != NULL) {
540 unsigned len = g_slist_length (l);
541 GSList *cur = l;
542 unsigned i;
543 vec->val = value_new_array_empty (len, 1);
544 for (i = 0; i < len; i++) {
545 vec->val->v_array.vals[i][0] = cur->data;
546 cur = cur->next;
548 } else {
549 if (l) {
550 GSList *cur;
551 for (cur = l; cur != NULL; cur = cur->next)
552 value_release (cur->data);
554 vec->val = gnm_expr_top_eval (vec->dep.texpr, &ep,
555 GNM_EXPR_EVAL_PERMIT_NON_SCALAR | GNM_EXPR_EVAL_PERMIT_EMPTY | GNM_EXPR_EVAL_ARRAY_CONTEXT);
557 g_slist_free (l);
560 if (vec->val != NULL) {
561 switch (vec->val->v_any.type) {
562 case VALUE_CELLRANGE:
563 gnm_rangeref_normalize (&vec->val->v_range.cell, &ep,
564 &start_sheet, &end_sheet, &r);
566 /* add +1 to max_used so that we can have matrices with
567 * empty cells at the end, see #684072 */
568 if (r.end.col > start_sheet->cols.max_used)
569 r.end.col = start_sheet->cols.max_used + 1;
570 if (r.end.row > start_sheet->rows.max_used)
571 r.end.row = start_sheet->rows.max_used + 1;
573 if (r.end.col >= r.start.col && r.end.row >= r.start.row) {
574 guint w = range_width (&r);
575 guint h = range_height (&r);
576 vec->as_col = h > w;
577 new_len = (guint64)h * w * (end_sheet->index_in_wb - start_sheet->index_in_wb + 1);
579 break;
581 case VALUE_ARRAY : {
582 GnmValue *v;
583 int i, j;
584 new_len = 0;
585 for (j = 0; j < vec->val->v_array.y; j++)
586 for (i = 0; i < vec->val->v_array.x; i++) {
587 v = vec->val->v_array.vals[i][j];
588 if (VALUE_IS_CELLRANGE (v)) {
589 gnm_rangeref_normalize (&v->v_range.cell, &ep,
590 &start_sheet, &end_sheet, &r);
591 new_len += (guint64)range_width (&r) * range_height (&r)
592 * (end_sheet->index_in_wb - start_sheet->index_in_wb + 1);
593 } else
594 new_len++;
596 vec->as_col = (vec->val->v_array.y > vec->val->v_array.x);
597 break;
599 case VALUE_ERROR:
600 new_len = 0;
601 break;
603 default:
604 new_len = 1;
605 vec->as_col = TRUE;
607 } else
608 new_len = 0;
610 /* Protect against overflow in ->len as well as when allocating ->values. */
611 new_len = MIN (new_len, (gint64)(G_MAXINT / sizeof (dat->values[0])));
612 dat->len = new_len;
614 if (dat->values != NULL && old_len != dat->len) {
615 g_free (dat->values);
616 dat->values = NULL;
618 dat->base.flags |= GO_DATA_VECTOR_LEN_CACHED;
621 struct assign_closure {
622 const GODateConventions *date_conv;
623 double minimum, maximum;
624 double *vals;
625 gssize vals_len;
626 guint64 last;
627 guint64 i;
630 static GnmValue *
631 cb_assign_val (GnmCellIter const *iter, struct assign_closure *dat)
633 GnmValue *v;
634 double res;
636 if ((gssize)dat->i >= dat->vals_len)
637 return NULL;
639 if (iter->cell != NULL) {
640 gnm_cell_eval (iter->cell);
641 v = iter->cell->value;
642 } else
643 v = NULL;
645 if (VALUE_IS_EMPTY_OR_ERROR (v)) {
646 dat->vals[dat->i++] = go_nan;
647 return NULL;
650 dat->last = dat->i;
651 if (VALUE_IS_STRING (v)) {
652 v = format_match_number (value_peek_string (v), NULL,
653 dat->date_conv);
654 if (v == NULL) {
655 dat->vals[dat->i++] = go_nan;
656 return NULL;
658 res = value_get_as_float (v);
659 value_release (v);
660 } else
661 res = value_get_as_float (v);
663 dat->vals[dat->i++] = res;
664 if (dat->minimum > res)
665 dat->minimum = res;
666 if (dat->maximum < res)
667 dat->maximum = res;
668 return NULL;
671 static void
672 gnm_go_data_vector_load_values (GODataVector *dat)
674 GnmGODataVector *vec = (GnmGODataVector *)dat;
675 GnmEvalPos ep;
676 GnmRange r;
677 Sheet *start_sheet, *end_sheet;
678 double *vals, minimum, maximum;
679 GnmValue *v;
680 struct assign_closure closure;
682 (void)go_data_vector_get_len (dat); /* force calculation */
684 if (dat->len <= 0 || !vec->dep.sheet) {
685 dat->values = NULL;
686 dat->minimum = go_nan;
687 dat->maximum = go_nan;
688 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
689 return;
692 closure.date_conv = sheet_date_conv (vec->dep.sheet);
694 if (dat->values == NULL)
695 dat->values = g_new (double, dat->len);
696 vals = dat->values;
697 switch (vec->val->v_any.type) {
698 case VALUE_CELLRANGE:
699 gnm_rangeref_normalize (&vec->val->v_range.cell,
700 eval_pos_init_dep (&ep, &vec->dep),
701 &start_sheet, &end_sheet, &r);
703 /* clip here rather than relying on sheet_foreach
704 * because that only clips if we ignore blanks
705 * but add +1 to max_used so that we can have matrices with
706 * empty cells at the end, see #684072 */
707 if (r.end.row > start_sheet->rows.max_used)
708 r.end.row = start_sheet->rows.max_used + 1;
709 if (r.end.col > start_sheet->cols.max_used)
710 r.end.col = start_sheet->cols.max_used + 1;
712 /* In case the sheet is empty */
713 if (r.start.col <= r.end.col && r.start.row <= r.end.row) {
714 closure.maximum = - G_MAXDOUBLE;
715 closure.minimum = G_MAXDOUBLE;
716 closure.vals = dat->values;
717 closure.vals_len = dat->len;
718 closure.last = -1;
719 closure.i = 0;
720 if (start_sheet != end_sheet)
721 workbook_foreach_cell_in_range (&ep, vec->val,
722 CELL_ITER_IGNORE_FILTERED,
723 (CellIterFunc)cb_assign_val,
724 &closure);
725 else
726 sheet_foreach_cell_in_range
727 (start_sheet, CELL_ITER_IGNORE_FILTERED,
729 (CellIterFunc)cb_assign_val, &closure);
730 dat->len = closure.last + 1; /* clip */
731 minimum = closure.minimum;
732 maximum = closure.maximum;
733 } else
734 minimum = maximum = vals[0] = go_nan;
735 break;
737 case VALUE_ARRAY : {
738 guint64 last = 0, max = dat->len;
739 int len = vec->val->v_array.y * vec->val->v_array.x;
740 int x = 0, y = vec->val->v_array.y;
741 GnmValue *v;
742 maximum = - G_MAXDOUBLE;
743 minimum = G_MAXDOUBLE;
744 while (len-- > 0) {
745 if (x == 0) {
746 x = vec->val->v_array.x;
747 y--;
749 x--;
750 v = vec->val->v_array.vals [x][y];
752 if (VALUE_IS_CELLRANGE (v)) {
753 gnm_rangeref_normalize (&v->v_range.cell,
754 eval_pos_init_dep (&ep, &vec->dep),
755 &start_sheet, &end_sheet, &r);
757 /* clip here rather than relying on sheet_foreach
758 * because that only clips if we ignore blanks */
759 if (r.end.row > start_sheet->rows.max_used)
760 r.end.row = start_sheet->rows.max_used;
761 if (r.end.col > start_sheet->cols.max_used)
762 r.end.col = start_sheet->cols.max_used;
764 if (r.start.col <= r.end.col && r.start.row <= r.end.row) {
765 closure.maximum = - G_MAXDOUBLE;
766 closure.minimum = G_MAXDOUBLE;
767 closure.vals = dat->values;
768 closure.vals_len = max;
769 closure.last = last - 1;
770 closure.i = last;
771 if (start_sheet != end_sheet)
772 workbook_foreach_cell_in_range (&ep, vec->val,
773 CELL_ITER_IGNORE_FILTERED,
774 (CellIterFunc)cb_assign_val,
775 &closure);
776 else
777 sheet_foreach_cell_in_range (start_sheet,
778 CELL_ITER_IGNORE_FILTERED,
780 (CellIterFunc)cb_assign_val, &closure);
781 last = dat->len = closure.last + 1; /* clip */
782 if (minimum > closure.minimum)
783 minimum = closure.minimum;
784 if (maximum < closure.maximum)
785 maximum = closure.maximum;
787 continue;
788 } else if (VALUE_IS_EMPTY_OR_ERROR (v)) {
789 vals[len] = go_nan;
790 continue;
791 } else if (VALUE_IS_STRING (v)) {
792 GnmValue *tmp = format_match_number
793 (value_peek_string (v), NULL,
794 closure.date_conv);
795 if (tmp == NULL) {
796 vals[len] = go_nan;
797 continue;
799 vals[len] = value_get_as_float (tmp);
800 value_release (tmp);
801 } else
802 vals[len] = value_get_as_float (v);
803 if (minimum > vals[len])
804 minimum = vals[len];
805 if (maximum < vals[len])
806 maximum = vals[len];
808 break;
811 case VALUE_STRING:
812 v = format_match_number (value_peek_string (vec->val),
813 NULL,
814 closure.date_conv);
815 if (v != NULL) {
816 minimum = maximum = vals[0] = value_get_as_float (v);
817 value_release (v);
818 break;
820 /* fall through to errors */
822 case VALUE_EMPTY:
823 case VALUE_ERROR:
824 minimum = maximum = vals[0] = go_nan;
825 break;
826 default:
827 minimum = maximum = vals[0] = value_get_as_float (vec->val);
828 break;
831 dat->values = vals;
832 dat->minimum = minimum;
833 dat->maximum = maximum;
834 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
837 static double
838 gnm_go_data_vector_get_value (GODataVector *dat, unsigned i)
840 GnmGODataVector *vec = (GnmGODataVector *)dat;
841 GnmValue *v;
842 GnmEvalPos ep;
843 gboolean valid = FALSE;
845 if (vec->val == NULL)
846 gnm_go_data_vector_load_len (dat);
848 if (VALUE_IS_ARRAY (vec->val)) {
849 if ((dat->base.flags & GO_DATA_CACHE_IS_VALID) == 0)
850 gnm_go_data_vector_load_values (dat);
851 return dat->values[i];
852 } else {
853 eval_pos_init_dep (&ep, &vec->dep);
854 v = value_dup (vec->as_col
855 ? value_area_get_x_y (vec->val, 0, i, &ep)
856 : value_area_get_x_y (vec->val, i, 0, &ep));
857 if (NULL == v)
858 return go_nan;
860 v = value_coerce_to_number (v, &valid, &ep);
861 if (valid) {
862 gnm_float res = value_get_as_float (v);
863 value_release (v);
864 return res;
866 value_release (v);
868 return go_nan;
872 struct string_closure {
873 GPtrArray *strs;
874 GODateConventions const *date_conv;
877 static gpointer
878 cb_assign_string (GnmCellIter const *iter, struct string_closure *closure)
880 GnmValue *v = NULL;
881 char *str = NULL;
883 if (iter->cell != NULL) {
884 gnm_cell_eval (iter->cell);
885 v = iter->cell->value;
887 if (v != NULL)
888 str = format_value (gnm_cell_get_format (iter->cell), v, -1, closure->date_conv);
889 g_ptr_array_add (closure->strs, str);
891 return NULL;
894 static char *
895 gnm_go_data_vector_get_str (GODataVector *dat, unsigned i)
897 GnmGODataVector *vec = (GnmGODataVector *)dat;
898 GnmEvalPos ep;
899 int j;
900 GOFormat const *fmt = NULL;
901 char *ret = NULL;
902 GnmValue *v = NULL;
904 if (vec->val == NULL)
905 gnm_go_data_vector_load_len (dat);
906 g_return_val_if_fail (vec->val != NULL, NULL);
908 eval_pos_init_dep (&ep, &vec->dep);
909 if (VALUE_IS_ARRAY (vec->val)) {
910 /* we need to cache the strings if needed */
911 if (vec->strs == NULL) {
912 int len = vec->val->v_array.y * vec->val->v_array.x;
913 int x = 0, y = vec->val->v_array.y;
914 struct string_closure closure;
915 closure.strs = vec->strs = g_ptr_array_new_with_free_func (g_free);
916 closure.date_conv = ep.sheet ? sheet_date_conv (ep.sheet) : NULL;
917 while (len-- > 0) {
918 if (x == 0) {
919 x = vec->val->v_array.x;
920 y--;
922 x--;
923 v = vec->val->v_array.vals [x][y];
925 if (VALUE_IS_CELLRANGE (v)) {
926 /* actually we only need to cache in that case */
927 Sheet *start_sheet, *end_sheet;
928 GnmRange r;
929 gnm_rangeref_normalize (&v->v_range.cell,
930 eval_pos_init_dep (&ep, &vec->dep),
931 &start_sheet, &end_sheet, &r);
933 /* clip here rather than relying on sheet_foreach
934 * because that only clips if we ignore blanks */
935 if (r.end.row > start_sheet->rows.max_used)
936 r.end.row = start_sheet->rows.max_used;
937 if (r.end.col > start_sheet->cols.max_used)
938 r.end.col = start_sheet->cols.max_used;
940 if (r.start.col <= r.end.col && r.start.row <= r.end.row)
941 sheet_foreach_cell_in_range (start_sheet,
942 CELL_ITER_IGNORE_FILTERED,
944 (CellIterFunc)cb_assign_string, &closure);
948 if (vec->strs && vec->strs->len > i)
949 ret = g_ptr_array_index (vec->strs, i);
950 if (ret != NULL)
951 return g_strdup (ret);
952 } else if (VALUE_IS_CELLRANGE (vec->val)) {
953 Sheet *start_sheet, *end_sheet;
954 GnmRange r;
955 if (vec->strs == NULL) {
956 struct string_closure closure;
957 closure.strs = vec->strs = g_ptr_array_new_with_free_func (g_free);
958 closure.date_conv = ep.sheet ? sheet_date_conv (ep.sheet) : NULL;
959 gnm_rangeref_normalize (&vec->val->v_range.cell,
960 eval_pos_init_dep (&ep, &vec->dep),
961 &start_sheet, &end_sheet, &r);
963 /* clip here rather than relying on sheet_foreach
964 * because that only clips if we ignore blanks */
965 if (r.end.row > start_sheet->rows.max_used)
966 r.end.row = start_sheet->rows.max_used;
967 if (r.end.col > start_sheet->cols.max_used)
968 r.end.col = start_sheet->cols.max_used;
970 if (r.start.col <= r.end.col && r.start.row <= r.end.row)
971 sheet_foreach_cell_in_range (start_sheet,
972 CELL_ITER_IGNORE_FILTERED,
974 (CellIterFunc)cb_assign_string, &closure);
976 if (vec->strs && vec->strs->len > i)
977 ret = g_ptr_array_index (vec->strs, i);
978 if (ret != NULL)
979 return g_strdup (ret);
981 if (vec->as_col)
982 j = 0;
983 else
984 j = i, i = 0;
985 ret = render_val (((v != NULL)? v: vec->val), i, j, fmt, &ep);
986 return ret;
989 static void
990 cond_pango_attr_list_unref (PangoAttrList *al)
992 if (al)
993 pango_attr_list_unref (al);
996 static gpointer
997 cb_assign_markup (GnmCellIter const *iter, GPtrArray *markup)
999 PangoAttrList const *l = NULL;
1001 if (iter->cell != NULL) {
1002 GOFormat const *fmt = gnm_cell_get_format (iter->cell);
1003 if (go_format_is_markup (fmt))
1004 l = go_format_get_markup (fmt);
1006 g_ptr_array_add (markup,
1007 l ? pango_attr_list_ref ((PangoAttrList *)l) : NULL);
1009 return NULL;
1012 static PangoAttrList *
1013 gnm_go_data_vector_get_markup (GODataVector *dat, unsigned i)
1015 GnmGODataVector *vec = (GnmGODataVector *)dat;
1017 if (vec->markup == NULL) {
1018 /* load markups */
1019 GnmEvalPos ep;
1020 GnmRange r;
1021 Sheet *start_sheet, *end_sheet;
1022 GnmValue *v;
1024 go_data_vector_get_len (dat); /* force calculation */
1025 if (dat->len <= 0 || !vec->dep.sheet)
1026 return NULL;
1027 vec->markup = g_ptr_array_new_with_free_func
1028 ((GDestroyNotify)cond_pango_attr_list_unref);
1029 switch (vec->val->v_any.type) {
1030 case VALUE_CELLRANGE:
1031 gnm_rangeref_normalize (&vec->val->v_range.cell,
1032 eval_pos_init_dep (&ep, &vec->dep),
1033 &start_sheet, &end_sheet, &r);
1035 /* clip here rather than relying on sheet_foreach
1036 * because that only clips if we ignore blanks */
1037 if (r.end.row > start_sheet->rows.max_used)
1038 r.end.row = start_sheet->rows.max_used;
1039 if (r.end.col > start_sheet->cols.max_used)
1040 r.end.col = start_sheet->cols.max_used;
1042 /* In case the sheet is empty */
1043 if (r.start.col <= r.end.col && r.start.row <= r.end.row) {
1044 sheet_foreach_cell_in_range (start_sheet,
1045 CELL_ITER_ALL,
1047 (CellIterFunc)cb_assign_markup, vec->markup);
1049 break;
1051 case VALUE_ARRAY: {
1052 int len = vec->as_col? vec->val->v_array.y: vec->val->v_array.x;
1053 while (len-- > 0) {
1054 v = vec->as_col
1055 ? vec->val->v_array.vals [0][len]
1056 : vec->val->v_array.vals [len][0];
1058 if (VALUE_IS_CELLRANGE (v)) {
1059 gnm_rangeref_normalize (&v->v_range.cell,
1060 eval_pos_init_dep (&ep, &vec->dep),
1061 &start_sheet, &end_sheet, &r);
1063 /* clip here rather than relying on sheet_foreach
1064 * because that only clips if we ignore blanks */
1065 if (r.end.row > start_sheet->rows.max_used)
1066 r.end.row = start_sheet->rows.max_used;
1067 if (r.end.col > start_sheet->cols.max_used)
1068 r.end.col = start_sheet->cols.max_used;
1070 if (r.start.col <= r.end.col && r.start.row <= r.end.row)
1071 sheet_foreach_cell_in_range (start_sheet,
1072 CELL_ITER_ALL,
1074 (CellIterFunc)cb_assign_markup, vec->markup);
1077 break;
1080 default:
1081 break;
1085 return pango_attr_list_copy ((vec->markup->len > i)?
1086 g_ptr_array_index (vec->markup, i): NULL);
1089 static void
1090 gnm_go_data_vector_class_init (GObjectClass *gobject_klass)
1092 GODataClass *godata_klass = (GODataClass *) gobject_klass;
1093 GODataVectorClass *vector_klass = (GODataVectorClass *) gobject_klass;
1095 vector_parent_klass = g_type_class_peek_parent (gobject_klass);
1096 gobject_klass->finalize = gnm_go_data_vector_finalize;
1097 godata_klass->dup = gnm_go_data_dup;
1098 godata_klass->eq = gnm_go_data_eq;
1099 godata_klass->preferred_fmt = gnm_go_data_preferred_fmt;
1100 godata_klass->date_conv = gnm_go_data_date_conv;
1101 godata_klass->serialize = gnm_go_data_serialize;
1102 godata_klass->unserialize = gnm_go_data_unserialize;
1103 vector_klass->load_len = gnm_go_data_vector_load_len;
1104 vector_klass->load_values = gnm_go_data_vector_load_values;
1105 vector_klass->get_value = gnm_go_data_vector_get_value;
1106 vector_klass->get_str = gnm_go_data_vector_get_str;
1107 vector_klass->get_markup = gnm_go_data_vector_get_markup;
1110 static void
1111 gnm_go_data_vector_debug_name (GnmDependent const *dep, GString *target)
1113 g_string_append_printf (target, "GraphVector%p", (void *)dep);
1115 static DEPENDENT_MAKE_TYPE (gnm_go_data_vector, NULL)
1117 static void
1118 gnm_go_data_vector_init (GObject *obj)
1120 GnmGODataVector *vec = (GnmGODataVector *)obj;
1121 vec->dep.flags = gnm_go_data_vector_get_dep_type ();
1124 GSF_CLASS (GnmGODataVector, gnm_go_data_vector,
1125 gnm_go_data_vector_class_init, gnm_go_data_vector_init,
1126 GO_TYPE_DATA_VECTOR)
1128 GOData *
1129 gnm_go_data_vector_new_expr (Sheet *sheet, GnmExprTop const *texpr)
1131 GnmGODataVector *res = g_object_new (gnm_go_data_vector_get_type (), NULL);
1132 res->dep.texpr = texpr;
1133 res->dep.sheet = sheet;
1134 return GO_DATA (res);
1137 /**************************************************************************/
1139 struct _GnmGODataMatrix {
1140 GODataMatrix base;
1141 GnmDependent dep;
1142 GnmValue *val;
1144 typedef GODataMatrixClass GnmGODataMatrixClass;
1146 #define DEP_TO_MATRIX(d_ptr) (GnmGODataMatrix *)(((char *)d_ptr) - G_STRUCT_OFFSET (GnmGODataMatrix, dep))
1148 static GObjectClass *matrix_parent_klass;
1150 static void
1151 gnm_go_data_matrix_eval (GnmDependent *dep)
1153 GnmGODataMatrix *mat = DEP_TO_MATRIX (dep);
1155 value_release (mat->val);
1156 mat->val = NULL;
1157 go_data_emit_changed (GO_DATA (mat));
1160 static void
1161 gnm_go_data_matrix_finalize (GObject *obj)
1163 GnmGODataMatrix *mat = (GnmGODataMatrix *)obj;
1165 dependent_set_expr (&mat->dep, NULL);
1166 value_release (mat->val);
1167 mat->val = NULL;
1169 g_free (mat->base.values);
1170 mat->base.values = NULL;
1172 matrix_parent_klass->finalize (obj);
1175 static void
1176 gnm_go_data_matrix_load_size (GODataMatrix *dat)
1178 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1179 GnmEvalPos ep;
1180 GnmRange r;
1181 Sheet *start_sheet, *end_sheet;
1182 unsigned h, w;
1183 int old_rows = dat->size.rows, old_columns = dat->size.columns;
1185 eval_pos_init_dep (&ep, &mat->dep);
1186 if (mat->val == NULL) {
1187 mat->val = gnm_expr_top_eval (mat->dep.texpr, &ep,
1188 GNM_EXPR_EVAL_PERMIT_NON_SCALAR | GNM_EXPR_EVAL_PERMIT_EMPTY);
1191 if (mat->val != NULL) {
1192 switch (mat->val->v_any.type) {
1193 case VALUE_CELLRANGE:
1194 gnm_rangeref_normalize (&mat->val->v_range.cell, &ep,
1195 &start_sheet, &end_sheet, &r);
1196 if (r.end.col > start_sheet->cols.max_used)
1197 r.end.col = start_sheet->cols.max_used;
1198 if (r.end.row > start_sheet->rows.max_used)
1199 r.end.row = start_sheet->rows.max_used;
1201 if (r.end.col >= r.start.col && r.end.row >= r.start.row) {
1202 w = range_width (&r);
1203 h = range_height (&r);
1204 if (w > 0 && h > 0) {
1205 dat->size.rows = h;
1206 dat->size.columns = w;
1208 else {
1209 dat->size.rows = 0;
1210 dat->size.columns = 0;
1212 } else {
1213 dat->size.rows = 0;
1214 dat->size.columns = 0;
1216 break;
1218 case VALUE_ARRAY:
1219 dat->size.rows = mat->val->v_array.y;
1220 dat->size.columns = mat->val->v_array.x;
1221 break;
1223 default:
1224 dat->size.rows = 1;
1225 dat->size.columns = 1;
1227 } else {
1228 dat->size.rows = 0;
1229 dat->size.columns = 0;
1231 if (dat->values != NULL &&
1232 (old_rows != dat->size.rows || old_columns != dat->size.columns)) {
1233 g_free (dat->values);
1234 dat->values = NULL;
1236 dat->base.flags |= GO_DATA_MATRIX_SIZE_CACHED;
1239 struct assign_matrix_closure {
1240 const GODateConventions *date_conv;
1241 double minimum, maximum;
1242 double *vals;
1243 int first_row, first_col;
1244 int last_row, last_col;
1245 int row, col, columns, k;
1248 static GnmValue *
1249 cb_assign_matrix_val (GnmCellIter const *iter,
1250 struct assign_matrix_closure *dat)
1252 GnmValue *v;
1253 double res;
1255 if (dat->first_col == -1)
1256 dat->first_col = iter->pp.eval.col;
1257 dat->col = iter->pp.eval.col - dat->first_col;
1258 if (dat->first_row == -1)
1259 dat->first_row = iter->pp.eval.row;
1260 dat->row = iter->pp.eval.row - dat->first_row;
1262 if (iter->cell != NULL) {
1263 gnm_cell_eval (iter->cell);
1264 v = iter->cell->value;
1265 } else
1266 v = NULL;
1269 if (VALUE_IS_EMPTY_OR_ERROR (v)) {
1270 dat->vals[dat->row * dat->columns + dat->col] = go_nan;
1271 return NULL;
1274 if (dat->last_row < dat->row)
1275 dat->last_row = dat->row;
1276 if (dat->last_col < dat->col)
1277 dat->last_col = dat->col;
1279 if (VALUE_IS_STRING (v)) {
1280 v = format_match_number (value_peek_string (v), NULL,
1281 dat->date_conv);
1282 if (v == NULL) {
1283 dat->vals[dat->row * dat->columns + dat->col] = go_nan;
1284 /* may be go_pinf should be more appropriate? */
1285 return NULL;
1287 res = value_get_as_float (v);
1288 value_release (v);
1289 } else
1290 res = value_get_as_float (v);
1292 dat->vals[dat->row * dat->columns + dat->col] = res;
1293 if (dat->minimum > res)
1294 dat->minimum = res;
1295 if (dat->maximum < res)
1296 dat->maximum = res;
1297 return NULL;
1300 static void
1301 gnm_go_data_matrix_load_values (GODataMatrix *dat)
1303 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1304 GnmEvalPos ep;
1305 GnmRange r;
1306 Sheet *start_sheet, *end_sheet;
1307 GODataMatrixSize size = go_data_matrix_get_size (dat); /* force calculation */
1308 double *vals, minimum, maximum;
1309 GnmValue *v;
1310 int row, col, cur;
1311 struct assign_matrix_closure closure;
1313 if (size.rows <= 0 || size.columns <= 0) {
1314 dat->values = NULL;
1315 dat->minimum = go_nan;
1316 dat->maximum = go_nan;
1317 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
1318 return;
1321 closure.date_conv = sheet_date_conv (mat->dep.sheet);
1323 if (dat->values == NULL)
1324 dat->values = g_new (double, size.rows * size.columns);
1325 vals = dat->values;
1326 switch (mat->val->v_any.type) {
1327 case VALUE_CELLRANGE:
1328 gnm_rangeref_normalize (&mat->val->v_range.cell,
1329 eval_pos_init_dep (&ep, &mat->dep),
1330 &start_sheet, &end_sheet, &r);
1332 /* In case the sheet is empty */
1333 if (r.start.col <= r.end.col && r.start.row <= r.end.row) {
1334 closure.maximum = - G_MAXDOUBLE;
1335 closure.minimum = G_MAXDOUBLE;
1336 closure.vals = dat->values;
1337 closure.first_row = closure.last_row = -1;
1338 closure.first_col = closure.last_col = -1;
1339 closure.row = closure.col = 0;
1340 closure.columns = dat->size.columns;
1341 sheet_foreach_cell_in_region (start_sheet, CELL_ITER_ALL,
1342 r.start.col, r.start.row,
1343 r.start.col + dat->size.columns - 1,
1344 r.start.row + dat->size.rows - 1,
1345 (CellIterFunc)cb_assign_matrix_val, &closure);
1346 #warning "Should we clip the matrix?"
1347 minimum = closure.minimum;
1348 maximum = closure.maximum;
1349 if (minimum > maximum)
1350 minimum = maximum = go_nan;
1351 } else
1352 minimum = maximum = vals[0] = go_nan;
1353 break;
1355 case VALUE_ARRAY:
1356 maximum = - G_MAXDOUBLE;
1357 minimum = G_MAXDOUBLE;
1358 for (col = 0; col < size.columns; col ++)
1359 for (row = 0; row < size.rows; row++) {
1360 v = mat->val->v_array.vals[col][row];
1361 cur = col * size.rows + row;
1362 if (VALUE_IS_EMPTY_OR_ERROR (v)) {
1363 vals[row * size.columns + col] = go_nan;
1364 continue;
1365 } else if (VALUE_IS_STRING (v)) {
1366 GnmValue *tmp = format_match_number
1367 (value_peek_string (v), NULL,
1368 closure.date_conv);
1369 if (tmp == NULL) {
1370 vals[cur] = go_nan;
1371 continue;
1373 vals[cur] = value_get_as_float (tmp);
1374 value_release (tmp);
1375 } else
1376 vals[cur] = value_get_as_float (v);
1377 if (minimum > vals[cur])
1378 minimum = vals[cur];
1379 if (maximum < vals[cur])
1380 maximum = vals[cur];
1382 if (minimum > maximum)
1383 minimum = maximum = go_nan;
1384 break;
1386 case VALUE_STRING:
1387 v = format_match_number (value_peek_string (mat->val),
1388 NULL,
1389 closure.date_conv);
1390 if (v != NULL) {
1391 vals[0] = value_get_as_float (v);
1392 minimum = maximum = go_nan;
1393 value_release (v);
1394 break;
1396 /* fall through to errors */
1398 case VALUE_EMPTY:
1399 case VALUE_ERROR:
1400 minimum = maximum = vals[0] = go_nan;
1401 break;
1402 default:
1403 vals[0] = value_get_as_float (mat->val);
1404 minimum = maximum = go_nan;
1405 break;
1408 dat->values = vals;
1409 dat->minimum = minimum;
1410 dat->maximum = maximum;
1411 dat->base.flags |= GO_DATA_CACHE_IS_VALID;
1414 static double
1415 gnm_go_data_matrix_get_value (GODataMatrix *dat, unsigned i, unsigned j)
1417 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1418 GnmValue *v;
1419 GnmEvalPos ep;
1420 gboolean valid;
1422 if (mat->val == NULL)
1423 gnm_go_data_matrix_load_size (dat);
1425 eval_pos_init_dep (&ep, &mat->dep);
1426 /* i is row and j is column */
1427 v = value_dup (value_area_get_x_y (mat->val, j, i, &ep));
1428 if (NULL == v)
1429 return go_nan;
1431 v = value_coerce_to_number (v, &valid, &ep);
1432 if (valid) {
1433 gnm_float res = value_get_as_float (v);
1434 value_release (v);
1435 return res;
1437 value_release (v);
1438 return go_nan;
1441 static char *
1442 gnm_go_data_matrix_get_str (GODataMatrix *dat, unsigned i, unsigned j)
1444 GnmGODataMatrix *mat = (GnmGODataMatrix *)dat;
1445 GnmEvalPos ep;
1446 GOFormat const *fmt = NULL;
1448 if (mat->val == NULL)
1449 gnm_go_data_matrix_load_size (dat);
1450 g_return_val_if_fail (mat->val != NULL, NULL);
1452 eval_pos_init_dep (&ep, &mat->dep);
1453 return render_val (mat->val, i, j, fmt, &ep);
1456 static void
1457 gnm_go_data_matrix_class_init (GObjectClass *gobject_klass)
1459 GODataClass *godata_klass = (GODataClass *) gobject_klass;
1460 GODataMatrixClass *matrix_klass = (GODataMatrixClass *) gobject_klass;
1462 matrix_parent_klass = g_type_class_peek_parent (gobject_klass);
1463 gobject_klass->finalize = gnm_go_data_matrix_finalize;
1464 godata_klass->dup = gnm_go_data_dup;
1465 godata_klass->eq = gnm_go_data_eq;
1466 godata_klass->preferred_fmt = gnm_go_data_preferred_fmt;
1467 godata_klass->date_conv = gnm_go_data_date_conv;
1468 godata_klass->serialize = gnm_go_data_serialize;
1469 godata_klass->unserialize = gnm_go_data_unserialize;
1470 matrix_klass->load_size = gnm_go_data_matrix_load_size;
1471 matrix_klass->load_values = gnm_go_data_matrix_load_values;
1472 matrix_klass->get_value = gnm_go_data_matrix_get_value;
1473 matrix_klass->get_str = gnm_go_data_matrix_get_str;
1476 static void
1477 gnm_go_data_matrix_debug_name (GnmDependent const *dep, GString *target)
1479 g_string_append_printf (target, "GraphMatrix%p", (void *)dep);
1481 static DEPENDENT_MAKE_TYPE (gnm_go_data_matrix, NULL)
1483 static void
1484 gnm_go_data_matrix_init (GObject *obj)
1486 GnmGODataMatrix *mat = (GnmGODataMatrix *)obj;
1487 mat->dep.flags = gnm_go_data_matrix_get_dep_type ();
1490 GSF_CLASS (GnmGODataMatrix, gnm_go_data_matrix,
1491 gnm_go_data_matrix_class_init, gnm_go_data_matrix_init,
1492 GO_TYPE_DATA_MATRIX)
1494 GOData *
1495 gnm_go_data_matrix_new_expr (Sheet *sheet, GnmExprTop const *texpr)
1497 GnmGODataMatrix *res = g_object_new (gnm_go_data_matrix_get_type (), NULL);
1498 res->dep.texpr = texpr;
1499 res->dep.sheet = sheet;
1500 return GO_DATA (res);
1503 /*******************************************************************************/
1505 static GnmDependent *
1506 gnm_go_data_get_dep (GOData const *dat)
1508 if (GNM_IS_GO_DATA_SCALAR (dat))
1509 return &((GnmGODataScalar *)dat)->dep;
1510 if (GNM_IS_GO_DATA_VECTOR (dat))
1511 return &((GnmGODataVector *)dat)->dep;
1512 if (GNM_IS_GO_DATA_MATRIX (dat))
1513 return &((GnmGODataMatrix *)dat)->dep;
1514 return NULL;