Compilation: kill warning.
[gnumeric.git] / src / cell.c
blob40515161033ea030b0b04328fe9b74d89f98c854
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * cell.c: Cell content and simple management.
5 * Author:
6 * Jody Goldberg 2000-2006 (jody@gnome.org)
7 * Miguel de Icaza 1998, 1999 (miguel@kernel.org)
8 * Copyright (C) 2000-2009 Morten Welinder (terra@gnome.org)
9 */
10 #include <gnumeric-config.h>
11 #include "gnumeric.h"
12 #include "cell.h"
14 #include "gutils.h"
15 #include "workbook.h"
16 #include "sheet.h"
17 #include "expr.h"
18 #include "expr-impl.h"
19 #include "rendered-value.h"
20 #include "value.h"
21 #include "style.h"
22 #include "ranges.h"
23 #include "gnm-format.h"
24 #include "number-match.h"
25 #include "sheet-style.h"
26 #include "parse-util.h"
28 #include <goffice/goffice.h>
30 /**
31 * gnm_cell_cleanout:
32 * Empty a cell's
33 * - value.
34 * - rendered_value.
35 * - expression.
36 * - parse format.
38 * Clears the flags to
39 * - not queued for recalc.
40 * - has no expression.
42 * Does NOT change
43 * - Comments.
44 * - Spans.
45 * - unqueue a previously queued recalc.
46 * - Mark sheet as dirty.
48 void
49 gnm_cell_cleanout (GnmCell *cell)
51 g_return_if_fail (cell != NULL);
53 /* A cell can have either an expression or entered text */
54 if (gnm_cell_has_expr (cell)) {
55 /* Clipboard cells, e.g., are not attached to a sheet. */
56 if (gnm_cell_expr_is_linked (cell))
57 dependent_unlink (GNM_CELL_TO_DEP (cell));
58 gnm_expr_top_unref (cell->base.texpr);
59 cell->base.texpr = NULL;
62 value_release (cell->value);
63 cell->value = NULL;
65 gnm_cell_unrender (cell);
67 sheet_cell_queue_respan (cell);
70 /****************************************************************************/
73 * gnm_cell_set_text: Parses the supplied text for storage as a value or
74 * expression. It marks the sheet as dirty.
76 * If the text is an expression it IS queued for recalc.
77 * the format prefered by the expression is stored for later use.
78 * If the text is a value it is rendered and spans are NOT calculated.
79 * the format that matched the text is stored for later use.
81 * WARNING : This is an internal routine that does not queue redraws,
82 * does not auto-resize, and does not calculate spans.
84 * NOTE : This DOES check for array partitioning.
86 void
87 gnm_cell_set_text (GnmCell *cell, char const *text)
89 GnmExprTop const *texpr;
90 GnmValue *val;
91 GnmParsePos pos;
93 g_return_if_fail (cell != NULL);
94 g_return_if_fail (text != NULL);
95 g_return_if_fail (!gnm_cell_is_nonsingleton_array (cell));
97 parse_text_value_or_expr (parse_pos_init_cell (&pos, cell),
98 text, &val, &texpr);
100 if (val != NULL) { /* String was a value */
101 gnm_cell_cleanout (cell);
102 cell->value = val;
103 } else { /* String was an expression */
104 gnm_cell_set_expr (cell, texpr);
105 gnm_expr_top_unref (texpr);
110 * gnm_cell_assign_value: Stores (WITHOUT COPYING) the supplied value.
111 * no changes are made to the expression or entered text. This
112 * is for use by routines that wish to store values directly such
113 * as expression calculation or import for array formulas.
115 * WARNING : This is an internal routine that does not
116 * - queue redraws,
117 * - auto-resize
118 * - calculate spans
119 * - does not render.
120 * - mark anything as dirty.
122 * NOTE : This DOES NOT check for array partitioning.
124 void
125 gnm_cell_assign_value (GnmCell *cell, GnmValue *v)
127 g_return_if_fail (cell);
128 g_return_if_fail (v);
130 value_release (cell->value);
131 cell->value = v;
135 * gnm_cell_set_value:
136 * @c: #GnmCell
137 * @v: #GnmValue
138 * Stores (WITHOUT COPYING) the supplied value. It marks the
139 * sheet as dirty.
141 * WARNING : This is an internal routine that does not
142 * - queue redraws,
143 * - auto-resize
144 * - calculate spans
145 * - does not render.
147 * NOTE : This DOES check for array partitioning.
149 void
150 gnm_cell_set_value (GnmCell *cell, GnmValue *v)
152 g_return_if_fail (cell != NULL);
153 g_return_if_fail (v != NULL);
154 if (gnm_cell_is_nonsingleton_array (cell)) {
155 value_release (v);
156 g_return_if_fail (!gnm_cell_is_nonsingleton_array (cell));
159 gnm_cell_cleanout (cell);
160 cell->value = v;
164 * gnm_cell_set_expr_and_value: Stores (WITHOUT COPYING) the supplied value, and
165 * references the supplied expression and links it into the expression
166 * list. It marks the sheet as dirty. It is intended for use by import
167 * routines or operations that do bulk assignment.
169 * WARNING : This is an internal routine that does not queue redraws,
170 * does not auto-resize, does not calculate spans, and does
171 * not render the value.
173 * NOTE : This DOES check for array partitioning.
175 void
176 gnm_cell_set_expr_and_value (GnmCell *cell, GnmExprTop const *texpr, GnmValue *v,
177 gboolean link_expr)
179 g_return_if_fail (cell != NULL);
180 g_return_if_fail (texpr != NULL);
181 if (gnm_cell_is_nonsingleton_array (cell)) {
182 value_release (v);
183 g_return_if_fail (!gnm_cell_is_nonsingleton_array (cell));
186 /* Repeat after me. Ref before unref. */
187 gnm_expr_top_ref (texpr);
188 gnm_cell_cleanout (cell);
190 cell->base.flags |= GNM_CELL_HAS_NEW_EXPR;
191 cell->base.texpr = texpr;
192 cell->value = v;
193 if (link_expr)
194 dependent_link (GNM_CELL_TO_DEP (cell));
198 * cell_set_expr_internal:
199 * @cell: the cell to set the expr for
200 * @expr: an expression
202 * A private internal utility to store an expression.
203 * Does NOT
204 * - check for array subdivision
205 * - queue recalcs.
206 * - render value, calc dimension, compute spans
207 * - link the expression into the master list.
209 static void
210 cell_set_expr_internal (GnmCell *cell, GnmExprTop const *texpr)
212 GnmValue *save_value;
214 gnm_expr_top_ref (texpr);
216 /* Don't touch the value. */
217 save_value = cell->value ? cell->value : value_new_empty ();
218 cell->value = NULL;
219 gnm_cell_cleanout (cell);
221 cell->base.flags |= GNM_CELL_HAS_NEW_EXPR;
222 cell->base.texpr = texpr;
223 cell->value = save_value;
227 * gnm_cell_set_expr_unsafe: Stores and references the supplied expression. It
228 * marks the sheet as dirty. Intented for use by import routines that
229 * do bulk assignment. The resulting cell is NOT linked into the
230 * dependent list. Nor marked for recalc.
232 * WARNING : This is an internal routine that does not queue redraws,
233 * does not auto-resize, and does not calculate spans.
234 * It also DOES NOT CHECK FOR ARRAY DIVISION. Be very careful
235 * using this.
237 void
238 gnm_cell_set_expr_unsafe (GnmCell *cell, GnmExprTop const *texpr)
240 g_return_if_fail (cell != NULL);
241 g_return_if_fail (texpr != NULL);
243 cell_set_expr_internal (cell, texpr);
247 * gnm_cell_set_expr: Stores and references the supplied expression
248 * marks the sheet as dirty. Intented for use by import routines that
249 * do bulk assignment. The resulting cell _is_ linked into the
250 * dependent list, but NOT marked for recalc.
252 * WARNING : This is an internal routine that does not queue redraws,
253 * does not auto-resize, and does not calculate spans.
254 * Be very careful using this.
256 void
257 gnm_cell_set_expr (GnmCell *cell, GnmExprTop const *texpr)
259 g_return_if_fail (!gnm_cell_is_nonsingleton_array (cell));
260 g_return_if_fail (cell != NULL);
261 g_return_if_fail (texpr != NULL);
263 cell_set_expr_internal (cell, texpr);
264 dependent_link (GNM_CELL_TO_DEP (cell));
268 * gnm_cell_set_array_formula:
269 * @sheet: The sheet to set the expr in.
270 * @cola: The left column in the destination region.
271 * @rowa: The top row in the destination region.
272 * @colb: The right column in the destination region.
273 * @rowb: The bottom row in the destination region.
274 * @texpr: an expression (the inner expression, not a corner or element)
276 * Uses cell_set_expr_internal to store the expr as an
277 * 'array-formula'. The supplied expression is wrapped in an array
278 * operator for each cell in the range and scheduled for recalc.
280 * NOTE : Does not add a reference to the expression. It takes over the
281 * caller's reference.
283 * Does not regenerate spans, dimensions or autosize cols/rows.
285 * DOES NOT CHECK for array partitioning.
287 void
288 gnm_cell_set_array_formula (Sheet *sheet,
289 int col_a, int row_a, int col_b, int row_b,
290 GnmExprTop const *texpr)
292 int const num_rows = 1 + row_b - row_a;
293 int const num_cols = 1 + col_b - col_a;
294 int x, y;
295 GnmCell *corner;
296 GnmExprTop const *wrapper;
298 g_return_if_fail (sheet != NULL);
299 g_return_if_fail (texpr != NULL);
300 g_return_if_fail (0 <= col_a);
301 g_return_if_fail (col_a <= col_b);
302 g_return_if_fail (col_b < gnm_sheet_get_max_cols (sheet));
303 g_return_if_fail (0 <= row_a);
304 g_return_if_fail (row_a <= row_b);
305 g_return_if_fail (row_b < gnm_sheet_get_max_rows (sheet));
307 corner = sheet_cell_fetch (sheet, col_a, row_a);
308 g_return_if_fail (corner != NULL);
310 wrapper = gnm_expr_top_new_array_corner (num_cols, num_rows, gnm_expr_copy (texpr->expr));
311 gnm_expr_top_unref (texpr);
312 cell_set_expr_internal (corner, wrapper);
313 gnm_expr_top_unref (wrapper);
315 for (x = 0; x < num_cols; ++x) {
316 for (y = 0; y < num_rows; ++y) {
317 GnmCell *cell;
318 GnmExprTop const *te;
320 if (x == 0 && y == 0)
321 continue;
323 cell = sheet_cell_fetch (sheet, col_a + x, row_a + y);
324 te = gnm_expr_top_new_array_elem (x, y);
325 cell_set_expr_internal (cell, te);
326 dependent_link (GNM_CELL_TO_DEP (cell));
327 gnm_expr_top_unref (te);
331 dependent_link (GNM_CELL_TO_DEP (corner));
334 static void
335 gnm_cell_set_array_formula_cb (GnmSheetRange const *sr, GnmExprTop const *texpr)
337 sheet_region_queue_recalc (sr->sheet, &sr->range);
338 gnm_expr_top_ref (texpr);
339 gnm_cell_set_array_formula (sr->sheet,
340 sr->range.start.col, sr->range.start.row,
341 sr->range.end.col, sr->range.end.row,
342 texpr);
343 sheet_region_queue_recalc (sr->sheet, &sr->range);
344 sheet_flag_status_update_range (sr->sheet, &sr->range);
345 sheet_queue_respan (sr->sheet, sr->range.start.row, sr->range.end.row);
349 * gnm_cell_set_array_formula_undo:
350 * @sr:
351 * @texpr:
353 * Returns: (transfer full): the newly allocated #GOUndo.
355 GOUndo *
356 gnm_cell_set_array_formula_undo (GnmSheetRange *sr, GnmExprTop const *texpr)
358 gnm_expr_top_ref (texpr);
359 return go_undo_binary_new (sr, (gpointer)texpr,
360 (GOUndoBinaryFunc) gnm_cell_set_array_formula_cb,
361 (GFreeFunc) gnm_sheet_range_free,
362 (GFreeFunc) gnm_expr_top_unref);
366 * gnm_cell_set_array:
367 * @sheet: The sheet to set the expr in.
368 * @r: The range to set.
369 * @texpr: an expression (the inner expression, not a corner or element)
371 * Set an array expression for a range.
372 * Uses cell_set_expr_internal to store the expr as an
373 * 'array-formula'. The supplied expression is wrapped in an array
374 * operator for each cell in the range and scheduled for recalc.
376 * Returns: TRUE if the operation succeded.
378 * NOTE : This adds a reference to the expression.
380 * Does not regenerate spans, dimensions or autosize cols/rows.
382 * DOES CHECK for array partitioning.
385 gboolean
386 gnm_cell_set_array (Sheet *sheet,
387 const GnmRange *r,
388 GnmExprTop const *texpr)
390 g_return_val_if_fail (sheet != NULL, FALSE);
391 g_return_val_if_fail (range_is_sane (r), FALSE);
392 g_return_val_if_fail (r->end.row < gnm_sheet_get_max_rows (sheet), FALSE);
393 g_return_val_if_fail (r->end.col < gnm_sheet_get_max_cols (sheet), FALSE);
394 g_return_val_if_fail (texpr != NULL, FALSE);
396 if (sheet_range_splits_array (sheet, r, NULL, NULL, NULL))
397 return FALSE;
399 gnm_expr_top_ref (texpr);
400 gnm_cell_set_array_formula (sheet,
401 r->start.col, r->start.row,
402 r->end.col, r->end.row,
403 texpr);
404 return TRUE;
407 /***************************************************************************/
410 * gnm_cell_is_empty:
411 * @cell: #GnmCell
413 * If the cell has not been created, or has VALUE_EMPTY.
415 gboolean
416 gnm_cell_is_empty (GnmCell const * cell)
418 return cell == NULL || VALUE_IS_EMPTY (cell->value);
422 * gnm_cell_is_blank:
423 * @cell: #GnmCell
425 * If the cell has not been created, has VALUE_EMPTY, or has a VALUE_STRING == ""
427 gboolean
428 gnm_cell_is_blank (GnmCell const * cell)
430 return gnm_cell_is_empty (cell) ||
431 (VALUE_IS_STRING (cell->value) &&
432 *value_peek_string (cell->value) == '\0');
435 GnmValue *
436 gnm_cell_is_error (GnmCell const * cell)
438 g_return_val_if_fail (cell != NULL, NULL);
439 g_return_val_if_fail (cell->value != NULL, NULL);
441 if (VALUE_IS_ERROR (cell->value))
442 return cell->value;
443 return NULL;
446 gboolean
447 gnm_cell_is_number (GnmCell const *cell)
449 /* FIXME : This does not handle arrays or ranges */
450 return (cell->value && VALUE_IS_NUMBER (cell->value));
453 gboolean
454 gnm_cell_is_zero (GnmCell const *cell)
456 GnmValue const * const v = cell->value;
457 return v && VALUE_IS_NUMBER (v) && gnm_abs (value_get_as_float (v)) < 64 * GNM_EPSILON;
460 gboolean
461 gnm_cell_array_bound (GnmCell const *cell, GnmRange *res)
463 GnmExprTop const *texpr;
464 GnmExprArrayCorner const *array;
465 int x, y;
467 if (NULL == cell || !gnm_cell_has_expr (cell))
468 return FALSE;
470 g_return_val_if_fail (res != NULL, FALSE);
472 texpr = cell->base.texpr;
473 if (gnm_expr_top_is_array_elem (texpr, &x, &y)) {
474 cell = sheet_cell_get (cell->base.sheet, cell->pos.col - x, cell->pos.row - y);
476 g_return_val_if_fail (cell != NULL, FALSE);
477 g_return_val_if_fail (gnm_cell_has_expr (cell), FALSE);
479 texpr = cell->base.texpr;
482 array = gnm_expr_top_get_array_corner (texpr);
483 if (!array)
484 return FALSE;
486 range_init (res, cell->pos.col, cell->pos.row,
487 cell->pos.col + array->cols - 1,
488 cell->pos.row + array->rows - 1);
489 return TRUE;
492 GnmExprArrayCorner const *
493 gnm_cell_is_array_corner (GnmCell const *cell)
495 return cell && gnm_cell_has_expr (cell)
496 ? gnm_expr_top_get_array_corner (cell->base.texpr)
497 : NULL;
501 * gnm_cell_is_array:
502 * @cell: #GnmCell const *
504 * Return TRUE is @cell is part of an array
506 gboolean
507 gnm_cell_is_array (GnmCell const *cell)
509 return cell != NULL && gnm_cell_has_expr (cell) &&
510 (gnm_expr_top_is_array_corner (cell->base.texpr) ||
511 gnm_expr_top_is_array_elem (cell->base.texpr, NULL, NULL));
515 * gnm_cell_is_nonsingleton_array:
516 * @cell: #GnmCell const *
518 * Return TRUE is @cell is part of an array larger than 1x1
520 gboolean
521 gnm_cell_is_nonsingleton_array (GnmCell const *cell)
523 GnmExprArrayCorner const *corner;
525 if ((cell == NULL) || !gnm_cell_has_expr (cell))
526 return FALSE;
527 if (gnm_expr_top_is_array_elem (cell->base.texpr, NULL, NULL))
528 return TRUE;
530 corner = gnm_expr_top_get_array_corner (cell->base.texpr);
531 return corner && (corner->cols > 1 || corner->rows > 1);
534 /***************************************************************************/
537 * gnm_cell_get_rendered_value: (skip)
538 * @cell: #GnmCell
540 * Returns:
542 GnmRenderedValue *
543 gnm_cell_get_rendered_value (GnmCell const *cell)
545 g_return_val_if_fail (cell != NULL, NULL);
547 return gnm_rvc_query (cell->base.sheet->rendered_values, cell);
551 * gnm_cell_fetch_rendered_value: (skip)
552 * @cell: #GnmCell
554 * Returns:
556 GnmRenderedValue *
557 gnm_cell_fetch_rendered_value (GnmCell const *cell,
558 gboolean allow_variable_width)
560 GnmRenderedValue *rv;
562 g_return_val_if_fail (cell != NULL, NULL);
564 rv = gnm_cell_get_rendered_value (cell);
565 if (rv)
566 return rv;
568 return gnm_cell_render_value (cell, allow_variable_width);
571 void
572 gnm_cell_unrender (GnmCell const *cell)
574 gnm_rvc_remove (cell->base.sheet->rendered_values, cell);
578 * gnm_cell_render_value: (skip)
579 * @cell: The cell whose value needs to be rendered
580 * @allow_variable_width: Allow format to depend on column width.
582 GnmRenderedValue *
583 gnm_cell_render_value (GnmCell const *cell, gboolean allow_variable_width)
585 GnmRenderedValue *rv;
586 Sheet *sheet;
588 g_return_val_if_fail (cell != NULL, NULL);
590 sheet = cell->base.sheet;
591 rv = gnm_rendered_value_new (cell,
592 sheet->rendered_values->context,
593 allow_variable_width,
594 sheet->last_zoom_factor_used);
596 gnm_rvc_store (sheet->rendered_values, cell, rv);
598 return rv;
602 * gnm_cell_get_rendered_text:
604 * Warning: use this only when you really want what is displayed on the
605 * screen. If the user has decided to display formulas instead of values
606 * then that is what you get.
608 char *
609 gnm_cell_get_rendered_text (GnmCell *cell)
611 GnmRenderedValue *rv;
613 g_return_val_if_fail (cell != NULL, g_strdup ("ERROR"));
615 rv = gnm_cell_fetch_rendered_value (cell, TRUE);
617 return g_strdup (gnm_rendered_value_get_text (rv));
621 * gnm_cell_get_render_color:
622 * @cell: the cell from which we want to pull the color from
624 * The returned value is a pointer to a PangoColor describing
625 * the foreground colour.
627 GOColor
628 gnm_cell_get_render_color (GnmCell const *cell)
630 GnmRenderedValue *rv;
632 g_return_val_if_fail (cell != NULL, GO_COLOR_BLACK);
634 rv = gnm_cell_fetch_rendered_value (cell, TRUE);
636 return gnm_rendered_value_get_color (rv);
640 * gnm_cell_get_entered_text:
641 * @cell: the cell from which we want to pull the content from
643 * This returns a g_malloc()ed region of memory with a text representation
644 * of the cell contents.
646 * This will return a text expression if the cell contains a formula, or
647 * a string representation of the value.
649 char *
650 gnm_cell_get_entered_text (GnmCell const *cell)
652 GnmValue const *v;
653 Sheet *sheet;
655 g_return_val_if_fail (cell != NULL, NULL);
657 sheet = cell->base.sheet;
659 if (gnm_cell_has_expr (cell)) {
660 GnmParsePos pp;
661 GnmConventionsOut out;
663 out.accum = g_string_new ("=");
664 out.pp = parse_pos_init_cell (&pp, cell);
665 out.convs = sheet->convs;
667 gnm_expr_top_as_gstring (cell->base.texpr, &out);
668 return g_string_free (out.accum, FALSE);
671 v = cell->value;
672 if (v != NULL) {
673 GODateConventions const *date_conv =
674 workbook_date_conv (sheet->workbook);
676 if (VALUE_IS_STRING (v)) {
677 /* Try to be reasonably smart about adding a leading quote */
678 char const *tmp = value_peek_string (v);
680 if (tmp[0] != '\'' &&
681 tmp[0] != 0 &&
682 !gnm_expr_char_start_p (tmp)) {
683 GnmValue *val = format_match_number
684 (tmp,
685 gnm_cell_get_format (cell),
686 date_conv);
687 if (val == NULL)
688 return g_strdup (tmp);
689 value_release (val);
691 return g_strconcat ("\'", tmp, NULL);
692 } else {
693 GOFormat const *fmt = gnm_cell_get_format (cell);
694 return format_value (fmt, v, -1, date_conv);
698 g_warning ("A cell with no expression, and no value ??");
699 return g_strdup ("<ERROR>");
702 static gboolean
703 close_to_int (gnm_float x, gnm_float eps)
705 return gnm_abs (x - gnm_fake_round (x)) < eps;
708 static GOFormat *
709 guess_time_format (const char *prefix, gnm_float f)
711 int decs = 0;
712 gnm_float eps = 1e-6;
713 static int maxdecs = 6;
714 GString *str = g_string_new (prefix);
715 GOFormat *fmt;
717 if (f >= 0 && f < 1)
718 g_string_append (str, "hh:mm");
719 else
720 g_string_append (str, "[h]:mm");
721 f *= 24 * 60;
722 if (!close_to_int (f, eps / 60)) {
723 g_string_append (str, ":ss");
724 f *= 60;
725 if (!close_to_int (f, eps)) {
726 g_string_append_c (str, '.');
727 while (decs < maxdecs) {
728 decs++;
729 g_string_append_c (str, '0');
730 f *= 10;
731 if (close_to_int (f, eps))
732 break;
737 while (go_format_is_invalid ((fmt = go_format_new_from_XL (str->str))) && decs > 0) {
738 /* We don't know how many decimals GOFormat allows. */
739 go_format_unref (fmt);
740 maxdecs = --decs;
741 g_string_truncate (str, str->len - 1);
744 g_string_free (str, TRUE);
745 return fmt;
749 * gnm_cell_get_text_for_editing:
750 * @cell: the cell from which we want to pull the content from
752 * The returned value should be g_free'd
754 * Primary user of this function is the formula entry.
755 * This function should return the value most appropriate for
756 * editing
760 char *
761 gnm_cell_get_text_for_editing (GnmCell const * cell, Sheet *sheet,
762 gboolean *quoted, int *cursor_pos)
764 GODateConventions const *date_conv;
765 gchar *text = NULL;
767 g_return_val_if_fail (cell != NULL, NULL);
768 g_return_val_if_fail (sheet != NULL, NULL);
770 if (quoted)
771 *quoted = FALSE;
773 date_conv = workbook_date_conv (sheet->workbook);
775 if (!gnm_cell_is_array (cell) &&
776 !gnm_cell_has_expr (cell) && VALUE_IS_FLOAT (cell->value)) {
777 GOFormat const *fmt = gnm_cell_get_format (cell);
778 gnm_float f = value_get_as_float (cell->value);
780 switch (go_format_get_family (fmt)) {
781 case GO_FORMAT_FRACTION:
782 text = gnm_cell_get_entered_text (cell);
783 g_strchug (text);
784 g_strchomp (text);
785 break;
787 case GO_FORMAT_PERCENTAGE: {
788 GString *new_str = g_string_new (NULL);
789 gnm_render_general (NULL, new_str, go_format_measure_zero,
790 go_font_metrics_unit, f * 100,
791 -1, FALSE, 0, 0);
792 if (cursor_pos)
793 *cursor_pos = g_utf8_strlen (new_str->str, -1);
794 g_string_append_c (new_str, '%');
795 text = g_string_free (new_str, FALSE);
796 break;
799 case GO_FORMAT_NUMBER:
800 case GO_FORMAT_SCIENTIFIC:
801 case GO_FORMAT_CURRENCY:
802 case GO_FORMAT_ACCOUNTING: {
803 GString *new_str = g_string_new (NULL);
804 gnm_render_general (NULL, new_str, go_format_measure_zero,
805 go_font_metrics_unit, f,
806 -1, FALSE, 0, 0);
807 text = g_string_free (new_str, FALSE);
808 break;
811 case GO_FORMAT_DATE: {
812 GOFormat *new_fmt;
814 new_fmt = gnm_format_for_date_editing (cell);
816 if (!close_to_int (f, 1e-6 / (24 * 60 * 60))) {
817 GString *fstr = g_string_new (go_format_as_XL (new_fmt));
818 go_format_unref (new_fmt);
820 g_string_append_c (fstr, ' ');
821 new_fmt = guess_time_format
822 (fstr->str,
823 f - gnm_floor (f));
824 g_string_free (fstr, TRUE);
827 text = format_value (new_fmt, cell->value,
828 -1, date_conv);
829 if (!text || text[0] == 0) {
830 g_free (text);
831 text = format_value (go_format_general (),
832 cell->value,
834 date_conv);
836 go_format_unref (new_fmt);
837 break;
840 case GO_FORMAT_TIME: {
841 GOFormat *new_fmt = guess_time_format (NULL, f);
843 text = format_value (new_fmt, cell->value, -1,
844 date_conv);
845 go_format_unref (new_fmt);
846 break;
849 default:
850 break;
854 if (!text) {
855 text = gnm_cell_get_entered_text (cell);
856 if (quoted)
857 *quoted = (text[0] == '\'');
860 return text;
866 * Return the height of the rendered layout after rotation.
869 gnm_cell_rendered_height (GnmCell const *cell)
871 const GnmRenderedValue *rv;
873 g_return_val_if_fail (cell != NULL, 0);
875 rv = gnm_cell_get_rendered_value (cell);
876 return rv
877 ? PANGO_PIXELS (rv->layout_natural_height)
878 : 0;
882 * Return the width of the rendered layout after rotation.
885 gnm_cell_rendered_width (GnmCell const *cell)
887 const GnmRenderedValue *rv;
889 g_return_val_if_fail (cell != NULL, 0);
891 rv = gnm_cell_get_rendered_value (cell);
892 return rv
893 ? PANGO_PIXELS (rv->layout_natural_width)
894 : 0;
898 gnm_cell_rendered_offset (GnmCell const * cell)
900 const GnmRenderedValue *rv;
902 g_return_val_if_fail (cell != NULL, 0);
904 rv = gnm_cell_get_rendered_value (cell);
905 return rv
906 ? rv->indent_left + rv->indent_right
907 : 0;
910 GnmStyle const *
911 gnm_cell_get_style (GnmCell const *cell)
913 g_return_val_if_fail (cell != NULL, NULL);
914 return sheet_style_get (cell->base.sheet,
915 cell->pos.col,
916 cell->pos.row);
920 * gnm_cell_get_format_given_style:
921 * @cell:
922 * @style:
924 * Get the display format. If the assigned format is General,
925 * the format of the value will be used.
927 GOFormat const *
928 gnm_cell_get_format_given_style (GnmCell const *cell, GnmStyle const *style)
930 GOFormat const *fmt;
932 g_return_val_if_fail (cell != NULL, go_format_general ());
934 if (style == NULL)
935 style = gnm_cell_get_style (cell);
937 fmt = gnm_style_get_format (style);
939 g_return_val_if_fail (fmt != NULL, go_format_general ());
941 if (go_format_is_general (fmt) &&
942 cell->value != NULL && VALUE_FMT (cell->value))
943 fmt = VALUE_FMT (cell->value);
945 return fmt;
949 * gnm_cell_get_format:
950 * @cell:
952 * Get the display format. If the assigned format is General,
953 * the format of the value will be used.
955 GOFormat const *
956 gnm_cell_get_format (GnmCell const *cell)
958 return gnm_cell_get_format_given_style (cell, NULL);
962 * gnm_cell_set_format:
964 * Changes the format for CELL to be FORMAT. FORMAT should be
965 * a number display format as specified on the manual
967 * Does not render, redraw, or respan.
969 void
970 gnm_cell_set_format (GnmCell *cell, char const *format)
972 GnmRange r;
973 GnmStyle *mstyle;
975 g_return_if_fail (cell != NULL);
976 g_return_if_fail (format != NULL);
978 mstyle = gnm_style_new ();
979 gnm_style_set_format_text (mstyle, format);
981 r.start = r.end = cell->pos;
982 sheet_style_apply_range (cell->base.sheet, &r, mstyle);
985 static GnmValue *
986 cb_set_array_value (GnmCellIter const *iter, gpointer user)
988 GnmValue const *value = user;
989 GnmCell *cell = iter->cell;
990 int x, y;
992 /* Clipboard cells, e.g., are not attached to a sheet. */
993 if (gnm_cell_expr_is_linked (cell))
994 dependent_unlink (GNM_CELL_TO_DEP (cell));
996 if (!gnm_expr_top_is_array_elem (cell->base.texpr, &x, &y))
997 return NULL;
999 gnm_expr_top_unref (cell->base.texpr);
1000 cell->base.texpr = NULL;
1001 value_release (cell->value);
1002 cell->value = value_dup (value_area_get_x_y (value, x, y, NULL));
1004 return NULL;
1008 * gnm_cell_convert_expr_to_value:
1009 * @cell: #GnmCell
1010 * drops the expression keeps its value. Then uses the formatted
1011 * result as if that had been entered.
1013 * NOTE : the cell's expression cannot be linked into the expression * list.
1015 * The cell is rendered but spans are not calculated, the cell is NOT marked for
1016 * recalc.
1018 * WARNING : This is an internal routine that does not queue redraws,
1019 * does not auto-resize, and does not calculate spans.
1021 void
1022 gnm_cell_convert_expr_to_value (GnmCell *cell)
1024 GnmExprArrayCorner const *array;
1026 g_return_if_fail (cell != NULL);
1027 g_return_if_fail (gnm_cell_has_expr (cell));
1029 /* Clipboard cells, e.g., are not attached to a sheet. */
1030 if (gnm_cell_expr_is_linked (cell))
1031 dependent_unlink (GNM_CELL_TO_DEP (cell));
1033 array = gnm_expr_top_get_array_corner (cell->base.texpr);
1034 if (array) {
1035 sheet_foreach_cell_in_range (cell->base.sheet, CELL_ITER_ALL,
1036 cell->pos.col, cell->pos.row,
1037 cell->pos.col + array->cols - 1,
1038 cell->pos.row + array->rows - 1,
1039 cb_set_array_value,
1040 array->value);
1041 } else {
1042 g_return_if_fail (!gnm_cell_is_array (cell));
1045 gnm_expr_top_unref (cell->base.texpr);
1046 cell->base.texpr = NULL;
1049 static gpointer cell_boxed_copy (gpointer c) { return c; }
1050 static void cell_boxed_free (gpointer c) { }
1052 GType
1053 gnm_cell_get_type (void)
1055 static GType type_cell = 0;
1057 if (!type_cell)
1058 type_cell = g_boxed_type_register_static
1059 ("GnmCell",
1060 cell_boxed_copy,
1061 cell_boxed_free);
1063 return type_cell;