1 /*
2  * cell.c: Cell content and simple management.
3  *
4  * Author:
5  *    Jody Goldberg 2000-2006 (jody@gnome.org)
6  *    Miguel de Icaza 1998, 1999 (miguel@kernel.org)
7  *    Copyright (C) 2000-2009 Morten Welinder (terra@gnome.org)
8  */
9 #include <gnumeric-config.h>
10 #include <gnumeric.h>
11 #include <cell.h>
12 
13 #include <gutils.h>
14 #include <workbook.h>
15 #include <sheet.h>
16 #include <expr.h>
17 #include <rendered-value.h>
18 #include <value.h>
19 #include <style.h>
20 #include <ranges.h>
21 #include <gnm-format.h>
22 #include <number-match.h>
23 #include <sheet-style.h>
24 #include <parse-util.h>
25 #include <style-conditions.h>
26 
27 #include <goffice/goffice.h>
28 
29 /**
30  * gnm_cell_cleanout: (skip)
31  * @cell: The #GnmCell
32  *
33  *      Empty a cell's
34  *		- value.
35  *		- rendered_value.
36  *		- expression.
37  *		- parse format.
38  *
39  *      Clears the flags to
40  *		- not queued for recalc.
41  *		- has no expression.
42  *
43  *      Does NOT change
44  *		- Comments.
45  *		- Spans.
46  *		- unqueue a previously queued recalc.
47  *		- Mark sheet as dirty.
48  */
49 void
gnm_cell_cleanout(GnmCell * cell)50 gnm_cell_cleanout (GnmCell *cell)
51 {
52 	g_return_if_fail (cell != NULL);
53 
54 	/* A cell can have either an expression or entered text */
55 	if (gnm_cell_has_expr (cell)) {
56 		/* Clipboard cells, e.g., are not attached to a sheet.  */
57 		if (gnm_cell_expr_is_linked (cell))
58 			dependent_unlink (GNM_CELL_TO_DEP (cell));
59 		gnm_expr_top_unref (cell->base.texpr);
60 		cell->base.texpr = NULL;
61 	}
62 
63 	value_release (cell->value);
64 	cell->value = NULL;
65 
66 	gnm_cell_unrender (cell);
67 
68 	sheet_cell_queue_respan (cell);
69 }
70 
71 /****************************************************************************/
72 
73 /**
74  * gnm_cell_set_text: (skip)
75  * @cell: #GnmCell
76  * @text: New contents of cell
77  *
78  * Parses the supplied text for storage as a value or
79  *		expression.  It marks the sheet as dirty.
80  *
81  * If the text is an expression it IS queued for recalc.
82  *        the format preferred by the expression is stored for later use.
83  * If the text is a value it is rendered and spans are NOT calculated.
84  *        the format that matched the text is stored for later use.
85  *
86  * WARNING : This is an internal routine that does not queue redraws,
87  *           does not auto-resize, and does not calculate spans.
88  *
89  * NOTE : This DOES check for array partitioning.
90  */
91 void
gnm_cell_set_text(GnmCell * cell,char const * text)92 gnm_cell_set_text (GnmCell *cell, char const *text)
93 {
94 	GnmExprTop const *texpr;
95 	GnmValue      *val;
96 	GnmParsePos    pos;
97 
98 	g_return_if_fail (cell != NULL);
99 	g_return_if_fail (text != NULL);
100 	g_return_if_fail (!gnm_cell_is_nonsingleton_array (cell));
101 
102 	parse_text_value_or_expr (parse_pos_init_cell (&pos, cell),
103 		text, &val, &texpr);
104 
105 	if (val != NULL) {	/* String was a value */
106 		gnm_cell_cleanout (cell);
107 		cell->value = val;
108 	} else {		/* String was an expression */
109 		gnm_cell_set_expr (cell, texpr);
110 		gnm_expr_top_unref (texpr);
111 	}
112 }
113 
114 /**
115  * gnm_cell_assign_value: (skip)
116  * @cell: #GnmCell
117  * @v: (transfer full): #GnmValue
118  *
119  * Stores, without copying, the supplied value.
120  *    no changes are made to the expression or entered text.  This
121  *    is for use by routines that wish to store values directly such
122  *    as expression calculation or import for array formulas.
123  *
124  * WARNING : This is an internal routine that does not
125  *	- queue redraws,
126  *	- auto-resize
127  *	- calculate spans
128  *	- does not render.
129  *	- mark anything as dirty.
130  *
131  * NOTE : This DOES NOT check for array partitioning.
132  */
133 void
gnm_cell_assign_value(GnmCell * cell,GnmValue * v)134 gnm_cell_assign_value (GnmCell *cell, GnmValue *v)
135 {
136 	g_return_if_fail (cell);
137 	g_return_if_fail (v);
138 
139 	value_release (cell->value);
140 	cell->value = v;
141 }
142 
143 /**
144  * gnm_cell_set_value: (skip)
145  * @c: #GnmCell
146  * @v: (transfer full): #GnmValue
147  *
148  * WARNING : This is an internal routine that does not
149  *	- queue redraws,
150  *	- auto-resize
151  *	- calculate spans
152  *	- does not render.
153  *
154  * NOTE : This DOES check for array partitioning.
155  **/
156 void
gnm_cell_set_value(GnmCell * cell,GnmValue * v)157 gnm_cell_set_value (GnmCell *cell, GnmValue *v)
158 {
159 	g_return_if_fail (cell != NULL);
160 	g_return_if_fail (v != NULL);
161 	if (gnm_cell_is_nonsingleton_array (cell)) {
162 		value_release (v);
163 		g_return_if_fail (!gnm_cell_is_nonsingleton_array (cell));
164 	}
165 
166 	gnm_cell_cleanout (cell);
167 	cell->value = v;
168 }
169 
170 /**
171  * gnm_cell_set_expr_and_value: (skip)
172  * @cell: The #GnmCell
173  * @texpr: The #GnmExprTop
174  * @v: (transfer full): The #GnmValue.
175  * @link_expr: If %TRUE, link the expression.
176  *
177  * Stores, without copying, the supplied value, and
178  *        references the supplied expression and links it into the expression
179  *        list.  It marks the sheet as dirty. It is intended for use by import
180  *        routines or operations that do bulk assignment.
181  *
182  * WARNING : This is an internal routine that does not queue redraws,
183  *           does not auto-resize, does not calculate spans, and does
184  *           not render the value.
185  *
186  * NOTE : This DOES check for array partitioning.
187  */
188 void
gnm_cell_set_expr_and_value(GnmCell * cell,GnmExprTop const * texpr,GnmValue * v,gboolean link_expr)189 gnm_cell_set_expr_and_value (GnmCell *cell, GnmExprTop const *texpr,
190 			     GnmValue *v, gboolean link_expr)
191 {
192 	g_return_if_fail (cell != NULL);
193 	g_return_if_fail (texpr != NULL);
194 	if (gnm_cell_is_nonsingleton_array (cell)) {
195 		value_release (v);
196 		g_return_if_fail (!gnm_cell_is_nonsingleton_array (cell));
197 	}
198 
199 	/* Repeat after me.  Ref before unref. */
200 	gnm_expr_top_ref (texpr);
201 	gnm_cell_cleanout (cell);
202 
203 	cell->base.flags |= GNM_CELL_HAS_NEW_EXPR;
204 	cell->base.texpr = texpr;
205 	cell->value = v;
206 	if (link_expr)
207 		dependent_link (GNM_CELL_TO_DEP (cell));
208 }
209 
210 /**
211  * cell_set_expr_internal: (skip)
212  * @cell: the cell to set the expr for
213  * @expr: an expression
214  *
215  * A private internal utility to store an expression.
216  * Does NOT
217  *	- check for array subdivision
218  *	- queue recalcs.
219  *	- render value, calc dimension, compute spans
220  *	- link the expression into the master list.
221  */
222 static void
cell_set_expr_internal(GnmCell * cell,GnmExprTop const * texpr)223 cell_set_expr_internal (GnmCell *cell, GnmExprTop const *texpr)
224 {
225 	GnmValue *save_value;
226 
227 	gnm_expr_top_ref (texpr);
228 
229 	/* Don't touch the value.  */
230 	save_value = cell->value ? cell->value : value_new_empty ();
231 	cell->value = NULL;
232 	gnm_cell_cleanout (cell);
233 
234 	cell->base.flags |= GNM_CELL_HAS_NEW_EXPR;
235 	cell->base.texpr = texpr;
236 	cell->value = save_value;
237 }
238 
239 /**
240  * gnm_cell_set_expr_unsafe: (skip)
241  * @cell: The #GnmCell
242  * @texpr: The #GnmExprTop
243  *
244  * Stores and references the supplied expression.  It
245  *         marks the sheet as dirty.  Intended for use by import routines that
246  *         do bulk assignment.  The resulting cell is NOT linked into the
247  *         dependent list.  Nor marked for recalc.
248  *
249  * WARNING : This is an internal routine that does not queue redraws,
250  *           does not auto-resize, and does not calculate spans.
251  *           It also DOES NOT CHECK FOR ARRAY DIVISION.  Be very careful
252  *           using this.
253  */
254 void
gnm_cell_set_expr_unsafe(GnmCell * cell,GnmExprTop const * texpr)255 gnm_cell_set_expr_unsafe (GnmCell *cell, GnmExprTop const *texpr)
256 {
257 	g_return_if_fail (cell != NULL);
258 	g_return_if_fail (texpr != NULL);
259 
260 	cell_set_expr_internal (cell, texpr);
261 }
262 
263 /**
264  * gnm_cell_set_expr: (skip)
265  * @cell: The #GnmCell
266  * @texpr: (transfer none): The #GnmExprTop
267  *
268  * Stores and references the supplied expression
269  *         marks the sheet as dirty.  Intended for use by import routines that
270  *         do bulk assignment.  The resulting cell _is_ linked into the
271  *         dependent list, but NOT marked for recalc.
272  *
273  * WARNING : This is an internal routine that does not queue redraws,
274  *           does not auto-resize, and does not calculate spans.
275  *           Be very careful using this.
276  */
277 void
gnm_cell_set_expr(GnmCell * cell,GnmExprTop const * texpr)278 gnm_cell_set_expr (GnmCell *cell, GnmExprTop const *texpr)
279 {
280 	g_return_if_fail (!gnm_cell_is_nonsingleton_array (cell));
281 	g_return_if_fail (cell != NULL);
282 	g_return_if_fail (texpr != NULL);
283 
284 	cell_set_expr_internal (cell, texpr);
285 	dependent_link (GNM_CELL_TO_DEP (cell));
286 }
287 
288 /**
289  * gnm_cell_set_array_formula: (skip)
290  * @sheet:   The sheet to set the expr in.
291  * @cola:   The left column in the destination region.
292  * @rowa:   The top row in the destination region.
293  * @colb:   The right column in the destination region.
294  * @rowb:   The bottom row in the destination region.
295  * @texpr:   an expression (the inner expression, not a corner or element)
296  *
297  * Uses cell_set_expr_internal to store the expr as an
298  * 'array-formula'.  The supplied expression is wrapped in an array
299  * operator for each cell in the range and scheduled for recalc.
300  *
301  * NOTE : Does not add a reference to the expression.  It takes over the
302  *        caller's reference.
303  *
304  * Does not regenerate spans, dimensions or autosize cols/rows.
305  *
306  * DOES NOT CHECK for array partitioning.
307  */
308 void
gnm_cell_set_array_formula(Sheet * sheet,int col_a,int row_a,int col_b,int row_b,GnmExprTop const * texpr)309 gnm_cell_set_array_formula (Sheet *sheet,
310 			    int col_a, int row_a, int col_b, int row_b,
311 			    GnmExprTop const *texpr)
312 {
313 	int const num_rows = 1 + row_b - row_a;
314 	int const num_cols = 1 + col_b - col_a;
315 	int x, y;
316 	GnmCell *corner;
317 	GnmExprTop const *wrapper;
318 
319 	g_return_if_fail (sheet != NULL);
320 	g_return_if_fail (texpr != NULL);
321 	g_return_if_fail (0 <= col_a);
322 	g_return_if_fail (col_a <= col_b);
323 	g_return_if_fail (col_b < gnm_sheet_get_max_cols (sheet));
324 	g_return_if_fail (0 <= row_a);
325 	g_return_if_fail (row_a <= row_b);
326 	g_return_if_fail (row_b < gnm_sheet_get_max_rows (sheet));
327 
328 	corner = sheet_cell_fetch (sheet, col_a, row_a);
329 	g_return_if_fail (corner != NULL);
330 
331 	wrapper = gnm_expr_top_new_array_corner (num_cols, num_rows, gnm_expr_copy (texpr->expr));
332 	gnm_expr_top_unref (texpr);
333 	cell_set_expr_internal (corner, wrapper);
334 	gnm_expr_top_unref (wrapper);
335 
336 	for (x = 0; x < num_cols; ++x) {
337 		for (y = 0; y < num_rows; ++y) {
338 			GnmCell *cell;
339 			GnmExprTop const *te;
340 
341 			if (x == 0 && y == 0)
342 				continue;
343 
344 			cell = sheet_cell_fetch (sheet, col_a + x, row_a + y);
345 			te = gnm_expr_top_new_array_elem (x, y);
346 			cell_set_expr_internal (cell, te);
347 			dependent_link (GNM_CELL_TO_DEP (cell));
348 			gnm_expr_top_unref (te);
349 		}
350 	}
351 
352 	dependent_link (GNM_CELL_TO_DEP (corner));
353 }
354 
355 static void
gnm_cell_set_array_formula_cb(GnmSheetRange const * sr,GnmExprTop const * texpr)356 gnm_cell_set_array_formula_cb (GnmSheetRange const *sr, GnmExprTop const *texpr)
357 {
358 	sheet_region_queue_recalc (sr->sheet, &sr->range);
359 	gnm_expr_top_ref (texpr);
360 	gnm_cell_set_array_formula (sr->sheet,
361 				    sr->range.start.col, sr->range.start.row,
362 				    sr->range.end.col,   sr->range.end.row,
363 				    texpr);
364 	sheet_region_queue_recalc (sr->sheet, &sr->range);
365 	sheet_flag_status_update_range (sr->sheet, &sr->range);
366 	sheet_queue_respan (sr->sheet, sr->range.start.row, sr->range.end.row);
367 }
368 
369 /**
370  * gnm_cell_set_array_formula_undo:
371  * @sr:
372  * @texpr:
373  *
374  * Returns: (transfer full): the newly allocated #GOUndo.
375  **/
376 GOUndo *
gnm_cell_set_array_formula_undo(GnmSheetRange * sr,GnmExprTop const * texpr)377 gnm_cell_set_array_formula_undo (GnmSheetRange *sr, GnmExprTop const *texpr)
378 {
379 	gnm_expr_top_ref (texpr);
380 	return go_undo_binary_new (sr, (gpointer)texpr,
381 				   (GOUndoBinaryFunc) gnm_cell_set_array_formula_cb,
382 				   (GFreeFunc) gnm_sheet_range_free,
383 				   (GFreeFunc) gnm_expr_top_unref);
384 }
385 
386 /**
387  * gnm_cell_set_array:
388  * @sheet:   The sheet to set the array expression in.
389  * @r:       The range to set.
390  * @texpr:   an expression (the inner expression, not a corner or element)
391  *
392  * Set an array expression for a range.
393  * Uses cell_set_expr_internal to store the expr as an
394  * 'array-formula'.  The supplied expression is wrapped in an array
395  * operator for each cell in the range and scheduled for recalc.
396  *
397  * Returns: %TRUE if the operation succeeded.
398  *
399  * NOTE : This adds a reference to the expression.
400  *
401  * Does not regenerate spans, dimensions or autosize cols/rows.
402  *
403  * DOES CHECK for array partitioning.
404  */
405 
406 gboolean
gnm_cell_set_array(Sheet * sheet,const GnmRange * r,GnmExprTop const * texpr)407 gnm_cell_set_array (Sheet *sheet,
408 		    const GnmRange *r,
409 		    GnmExprTop const *texpr)
410 {
411 	g_return_val_if_fail (sheet != NULL, FALSE);
412 	g_return_val_if_fail (range_is_sane (r), FALSE);
413 	g_return_val_if_fail (r->end.row < gnm_sheet_get_max_rows (sheet), FALSE);
414 	g_return_val_if_fail (r->end.col < gnm_sheet_get_max_cols (sheet), FALSE);
415 	g_return_val_if_fail (texpr != NULL, FALSE);
416 
417 	if (sheet_range_splits_array (sheet, r, NULL, NULL, NULL))
418 		return FALSE;
419 
420 	gnm_expr_top_ref (texpr);
421 	gnm_cell_set_array_formula (sheet,
422 				    r->start.col, r->start.row,
423 				    r->end.col, r->end.row,
424 				    texpr);
425 	return TRUE;
426 }
427 
428 /***************************************************************************/
429 
430 /**
431  * gnm_cell_is_empty:
432  * @cell: (nullable): #GnmCell
433  *
434  * Returns: %TRUE, If the cell has not been created, or has VALUE_EMPTY.
435  **/
436 gboolean
gnm_cell_is_empty(GnmCell const * cell)437 gnm_cell_is_empty (GnmCell const *cell)
438 {
439 	return cell == NULL || VALUE_IS_EMPTY (cell->value);
440 }
441 
442 /**
443  * gnm_cell_is_blank:
444  * @cell: (nullable): #GnmCell
445  *
446  * Returns: %TRUE, if the cell has not been created, has VALUE_EMPTY,
447  * or has an empty VALUE_STRING.
448  **/
449 gboolean
gnm_cell_is_blank(GnmCell const * cell)450 gnm_cell_is_blank (GnmCell const * cell)
451 {
452 	return gnm_cell_is_empty (cell) ||
453 		(VALUE_IS_STRING (cell->value) &&
454 		 *value_peek_string (cell->value) == '\0');
455 }
456 
457 /**
458  * gnm_cell_is_error:
459  * @cell: #GnmCell
460  *
461  * Returns: (nullable) (transfer none): @cell's value if it is an error,
462  * or %NULL.
463  **/
464 GnmValue *
gnm_cell_is_error(GnmCell const * cell)465 gnm_cell_is_error (GnmCell const *cell)
466 {
467 	g_return_val_if_fail (cell != NULL, NULL);
468 	g_return_val_if_fail (cell->value != NULL, NULL);
469 
470 	if (VALUE_IS_ERROR (cell->value))
471 		return cell->value;
472 	return NULL;
473 }
474 
475 /**
476  * gnm_cell_is_number:
477  * @cell: #GnmCell
478  *
479  * Returns: %TRUE, if the cell contains a number.
480  **/
481 gboolean
gnm_cell_is_number(GnmCell const * cell)482 gnm_cell_is_number (GnmCell const *cell)
483 {
484 	/* FIXME : This does not handle arrays or ranges */
485 	return (cell->value && VALUE_IS_NUMBER (cell->value));
486 }
487 
488 /**
489  * gnm_cell_is_zero:
490  * @cell: #GnmCell
491  *
492  * Returns: %TRUE, if the cell contains zero.
493  **/
494 gboolean
gnm_cell_is_zero(GnmCell const * cell)495 gnm_cell_is_zero (GnmCell const *cell)
496 {
497 	GnmValue const * const v = cell->value;
498 	return v && VALUE_IS_NUMBER (v) && gnm_abs (value_get_as_float (v)) < 64 * GNM_EPSILON;
499 }
500 
501 /**
502  * gnm_cell_get_value:
503  * @cell: #GnmCell
504  *
505  * Returns: (transfer none): @cell's value
506  **/
507 GnmValue *
gnm_cell_get_value(GnmCell const * cell)508 gnm_cell_get_value (GnmCell const *cell)
509 {
510 	g_return_val_if_fail (cell != NULL, NULL);
511 	return cell->value;
512 }
513 
514 /**
515  * gnm_cell_array_bound:
516  * @cell: (nullable): #GnmCell
517  * @res: (out): The range containing an array cell
518  *
519  * Returns: %TRUE, if the cell is an array cell
520  **/
521 gboolean
gnm_cell_array_bound(GnmCell const * cell,GnmRange * res)522 gnm_cell_array_bound (GnmCell const *cell, GnmRange *res)
523 {
524 	GnmExprTop const *texpr;
525 	int x, y;
526 	int cols, rows;
527 
528 	range_init (res, 0, 0, 0, 0);
529 
530 	if (NULL == cell || !gnm_cell_has_expr (cell))
531 		return FALSE;
532 
533 	g_return_val_if_fail (res != NULL, FALSE);
534 
535 	texpr = cell->base.texpr;
536 	if (gnm_expr_top_is_array_elem (texpr, &x, &y)) {
537 		cell = sheet_cell_get (cell->base.sheet, cell->pos.col - x, cell->pos.row - y);
538 
539 		g_return_val_if_fail (cell != NULL, FALSE);
540 		g_return_val_if_fail (gnm_cell_has_expr (cell), FALSE);
541 
542 		texpr = cell->base.texpr;
543 	}
544 
545 	if (!gnm_expr_top_is_array_corner (texpr))
546 		return FALSE;
547 
548 	gnm_expr_top_get_array_size (texpr, &cols, &rows);
549 
550 	range_init (res, cell->pos.col, cell->pos.row,
551 		cell->pos.col + cols - 1,
552 		cell->pos.row + rows - 1);
553 	return TRUE;
554 }
555 
556 /**
557  * gnm_cell_is_array:
558  * @cell: #GnmCell
559  *
560  * Returns %TRUE is @cell is part of an array
561  **/
562 gboolean
gnm_cell_is_array(GnmCell const * cell)563 gnm_cell_is_array (GnmCell const *cell)
564 {
565 	return cell != NULL && gnm_cell_has_expr (cell) &&
566 		(gnm_expr_top_is_array_corner (cell->base.texpr) ||
567 		 gnm_expr_top_is_array_elem (cell->base.texpr, NULL, NULL));
568 }
569 
570 /**
571  * gnm_cell_is_nonsingleton_array:
572  * @cell: #GnmCell
573  *
574  * Returns: %TRUE is @cell is part of an array larger than 1x1
575  **/
576 gboolean
gnm_cell_is_nonsingleton_array(GnmCell const * cell)577 gnm_cell_is_nonsingleton_array (GnmCell const *cell)
578 {
579 	int cols, rows;
580 
581 	if ((cell == NULL) || !gnm_cell_has_expr (cell))
582 		return FALSE;
583 	if (gnm_expr_top_is_array_elem (cell->base.texpr, NULL, NULL))
584 		return TRUE;
585 
586 	if (!gnm_expr_top_is_array_corner (cell->base.texpr))
587 		return FALSE;
588 
589 	gnm_expr_top_get_array_size (cell->base.texpr, &cols, &rows);
590 	return cols > 1 || rows > 1;
591 }
592 
593 /***************************************************************************/
594 
595 /**
596  * gnm_cell_get_rendered_value: (skip)
597  * @cell: #GnmCell
598  *
599  * Returns: (transfer none): The #GnmRenderedValue for the cell.
600  **/
601 GnmRenderedValue *
gnm_cell_get_rendered_value(GnmCell const * cell)602 gnm_cell_get_rendered_value (GnmCell const *cell)
603 {
604 	g_return_val_if_fail (cell != NULL, NULL);
605 
606 	return gnm_rvc_query (cell->base.sheet->rendered_values, cell);
607 }
608 
609 /**
610  * gnm_cell_fetch_rendered_value: (skip)
611  * @cell: #GnmCell
612  *
613  * Returns:
614  **/
615 GnmRenderedValue *
gnm_cell_fetch_rendered_value(GnmCell const * cell,gboolean allow_variable_width)616 gnm_cell_fetch_rendered_value (GnmCell const *cell,
617 			       gboolean allow_variable_width)
618 {
619 	GnmRenderedValue *rv;
620 
621 	g_return_val_if_fail (cell != NULL, NULL);
622 
623 	rv = gnm_cell_get_rendered_value (cell);
624 	if (rv)
625 		return rv;
626 
627 	return gnm_cell_render_value (cell, allow_variable_width);
628 }
629 
630 void
gnm_cell_unrender(GnmCell const * cell)631 gnm_cell_unrender (GnmCell const *cell)
632 {
633 	gnm_rvc_remove (cell->base.sheet->rendered_values, cell);
634 }
635 
636 /**
637  * gnm_cell_render_value: (skip)
638  * @cell: The cell whose value needs to be rendered
639  * @allow_variable_width: Allow format to depend on column width.
640  *
641  * Returns: (transfer none): The newly #GnmRenderedValue.
642  */
643 GnmRenderedValue *
gnm_cell_render_value(GnmCell const * cell,gboolean allow_variable_width)644 gnm_cell_render_value (GnmCell const *cell, gboolean allow_variable_width)
645 {
646 	GnmRenderedValue *rv;
647 	Sheet *sheet;
648 
649 	g_return_val_if_fail (cell != NULL, NULL);
650 
651 	sheet = cell->base.sheet;
652 	rv = gnm_rendered_value_new (cell,
653 				     sheet->rendered_values->context,
654 				     allow_variable_width,
655 				     sheet->last_zoom_factor_used);
656 
657 	gnm_rvc_store (sheet->rendered_values, cell, rv);
658 
659 	return rv;
660 }
661 
662 /*
663  * gnm_cell_get_rendered_text:
664  *
665  * Warning: use this only when you really want what is displayed on the
666  * screen.  If the user has decided to display formulas instead of values
667  * then that is what you get.
668  */
669 char *
gnm_cell_get_rendered_text(GnmCell * cell)670 gnm_cell_get_rendered_text (GnmCell *cell)
671 {
672 	GnmRenderedValue *rv;
673 
674 	g_return_val_if_fail (cell != NULL, g_strdup ("ERROR"));
675 
676 	rv = gnm_cell_fetch_rendered_value (cell, TRUE);
677 
678 	return g_strdup (gnm_rendered_value_get_text (rv));
679 }
680 
681 /**
682  * gnm_cell_get_render_color:
683  * @cell: the cell from which we want to pull the color from
684  *
685  * Returns: A #GOColor used for foreground in @cell.
686  */
687 GOColor
gnm_cell_get_render_color(GnmCell const * cell)688 gnm_cell_get_render_color (GnmCell const *cell)
689 {
690 	GnmRenderedValue *rv;
691 
692 	g_return_val_if_fail (cell != NULL, GO_COLOR_BLACK);
693 
694 	rv = gnm_cell_fetch_rendered_value (cell, TRUE);
695 
696 	return gnm_rendered_value_get_color (rv);
697 }
698 
699 /**
700  * gnm_cell_get_entered_text:
701  * @cell: the cell from which we want to pull the content from
702  *
703  * This returns a g_malloc()ed region of memory with a text representation
704  * of the cell contents.
705  *
706  * Returns: (transfer full): a text expression if the cell contains a
707  * formula, or a string representation of the value.
708  */
709 char *
gnm_cell_get_entered_text(GnmCell const * cell)710 gnm_cell_get_entered_text (GnmCell const *cell)
711 {
712 	GnmValue const *v;
713 	Sheet *sheet;
714 
715 	g_return_val_if_fail (cell != NULL, NULL);
716 
717 	sheet = cell->base.sheet;
718 
719 	if (gnm_cell_has_expr (cell)) {
720 		GnmParsePos pp;
721 		GnmConventionsOut out;
722 
723 		out.accum = g_string_new ("=");
724 		out.pp = parse_pos_init_cell (&pp, cell);
725 		out.convs = sheet->convs;
726 
727 		gnm_expr_top_as_gstring (cell->base.texpr, &out);
728 		return g_string_free (out.accum, FALSE);
729 	}
730 
731 	v = cell->value;
732 	if (v != NULL) {
733 		GODateConventions const *date_conv =
734 			sheet_date_conv (sheet);
735 
736 		if (VALUE_IS_STRING (v)) {
737 			/* Try to be reasonably smart about adding a leading quote */
738 			char const *tmp = value_peek_string (v);
739 
740 			if (tmp[0] != '\'' &&
741 			    tmp[0] != 0 &&
742 			    !gnm_expr_char_start_p (tmp)) {
743 				GnmValue *val = format_match_number
744 					(tmp,
745 					 gnm_cell_get_format (cell),
746 					 date_conv);
747 				if (val == NULL)
748 					return g_strdup (tmp);
749 				value_release (val);
750 			}
751 			return g_strconcat ("\'", tmp, NULL);
752 		} else {
753 			GOFormat const *fmt = gnm_cell_get_format (cell);
754 			return format_value (fmt, v, -1, date_conv);
755 		}
756 	}
757 
758 	g_warning ("A cell with no expression, and no value ??");
759 	return g_strdup ("<ERROR>");
760 }
761 
762 static gboolean
close_to_int(gnm_float x,gnm_float eps)763 close_to_int (gnm_float x, gnm_float eps)
764 {
765 	return gnm_abs (x - gnm_fake_round (x)) < eps;
766 }
767 
768 static GOFormat *
guess_time_format(const char * prefix,gnm_float f)769 guess_time_format (const char *prefix, gnm_float f)
770 {
771 	int decs = 0;
772 	gnm_float eps = 1e-6;
773 	static int maxdecs = 6;
774 	GString *str = g_string_new (prefix);
775 	GOFormat *fmt;
776 
777 	if (f >= 0 && f < 1)
778 		g_string_append (str, "hh:mm");
779 	else
780 		g_string_append (str, "[h]:mm");
781 	f *= 24 * 60;
782 	if (!close_to_int (f, eps / 60)) {
783 		g_string_append (str, ":ss");
784 		f *= 60;
785 		if (!close_to_int (f, eps)) {
786 			g_string_append_c (str, '.');
787 			while (decs < maxdecs) {
788 				decs++;
789 				g_string_append_c (str, '0');
790 				f *= 10;
791 				if (close_to_int (f, eps))
792 					break;
793 			}
794 		}
795 	}
796 
797 	while (go_format_is_invalid ((fmt = go_format_new_from_XL (str->str))) && decs > 0) {
798 		/* We don't know how many decimals GOFormat allows.  */
799 		go_format_unref (fmt);
800 		maxdecs = --decs;
801 		g_string_truncate (str, str->len - 1);
802 	}
803 
804 	g_string_free (str, TRUE);
805 	return fmt;
806 }
807 
808 static void
render_percentage(GString * str,gnm_float f)809 render_percentage (GString *str, gnm_float f)
810 {
811 	gnm_float f100 = 100 * f;
812 	gboolean qneg = (f < 0);
813 	gnm_float f2;
814 
815 	// Render slightly narrow
816 	gnm_render_general (NULL, str, go_format_measure_strlen,
817 			    go_font_metrics_unit, f100,
818 			    12 + qneg, FALSE, 0, 0);
819 	// Explicit cast to drop excess precision
820 	f2 = (gnm_float)(gnm_strto (str->str, NULL) / 100);
821 	if (f2 == f)
822 		return;
823 
824 	// No good -- rerender unconstrained.
825 	gnm_render_general (NULL, str, go_format_measure_zero,
826 			    go_font_metrics_unit, f100,
827 			    -1, FALSE, 0, 0);
828 }
829 
830 /**
831  * gnm_cell_get_text_for_editing:
832  * @cell: the cell from which we want to pull the content from
833  * @quoted: (out) (optional): Whether a single quote was used to force
834  * string interpretation
835  * @cursor_pos: (out) (optional): Desired initial cursor position
836  *
837  * Returns: (transfer full): A string suitable for editing
838  *
839  * Primary user of this function is the formula entry.
840  * This function should return the value most appropriate for
841  * editing
842  */
843 char *
gnm_cell_get_text_for_editing(GnmCell const * cell,gboolean * quoted,int * cursor_pos)844 gnm_cell_get_text_for_editing (GnmCell const * cell,
845 			       gboolean *quoted, int *cursor_pos)
846 {
847 	GODateConventions const *date_conv;
848 	gchar *text = NULL;
849 
850 	g_return_val_if_fail (cell != NULL, NULL);
851 
852 	if (quoted)
853 		*quoted = FALSE;
854 
855 	date_conv = sheet_date_conv (cell->base.sheet);
856 
857 	if (!gnm_cell_is_array (cell) &&
858 	    !gnm_cell_has_expr (cell) && VALUE_IS_FLOAT (cell->value)) {
859 		GOFormat const *fmt = gnm_cell_get_format (cell);
860 		gnm_float f = value_get_as_float (cell->value);
861 
862 		switch (go_format_get_family (fmt)) {
863 		case GO_FORMAT_FRACTION:
864 			text = gnm_cell_get_entered_text (cell);
865 			g_strchug (text);
866 			g_strchomp (text);
867 			break;
868 
869 		case GO_FORMAT_PERCENTAGE: {
870 			GString *new_str = g_string_new (NULL);
871 			render_percentage (new_str, f);
872 			if (cursor_pos)
873 				*cursor_pos = g_utf8_strlen (new_str->str, -1);
874 			g_string_append_c (new_str, '%');
875 			text = g_string_free (new_str, FALSE);
876 			break;
877 		}
878 
879 		case GO_FORMAT_NUMBER:
880 		case GO_FORMAT_SCIENTIFIC:
881 		case GO_FORMAT_CURRENCY:
882 		case GO_FORMAT_ACCOUNTING: {
883 			GString *new_str = g_string_new (NULL);
884 			gnm_render_general (NULL, new_str, go_format_measure_zero,
885 					    go_font_metrics_unit, f,
886 					    -1, FALSE, 0, 0);
887 			text = g_string_free (new_str, FALSE);
888 			break;
889 		}
890 
891 		case GO_FORMAT_DATE: {
892 			GOFormat *new_fmt;
893 
894 			new_fmt = gnm_format_for_date_editing (cell);
895 
896 			if (!close_to_int (f, 1e-6 / (24 * 60 * 60))) {
897 				GString *fstr = g_string_new (go_format_as_XL (new_fmt));
898 				go_format_unref (new_fmt);
899 
900 				g_string_append_c (fstr, ' ');
901 				new_fmt = guess_time_format
902 					(fstr->str,
903 					 f - gnm_floor (f));
904 				g_string_free (fstr, TRUE);
905 			}
906 
907 			text = format_value (new_fmt, cell->value,
908 					     -1, date_conv);
909 			if (!text || text[0] == 0) {
910 				g_free (text);
911 				text = format_value (go_format_general (),
912 						     cell->value,
913 						     -1,
914 						     date_conv);
915 			}
916 			go_format_unref (new_fmt);
917 			break;
918 		}
919 
920 		case GO_FORMAT_TIME: {
921 			GOFormat *new_fmt = guess_time_format (NULL, f);
922 
923 			text = format_value (new_fmt, cell->value, -1,
924 					     date_conv);
925 			go_format_unref (new_fmt);
926 			break;
927 		}
928 
929 		default:
930 			break;
931 		}
932 	}
933 
934 	if (!text) {
935 		text = gnm_cell_get_entered_text (cell);
936 		if (quoted)
937 			*quoted = (text[0] == '\'');
938 	}
939 
940 	return text;
941 }
942 
943 
944 
945 /*
946  * Return the height of the rendered layout after rotation.
947  */
948 int
gnm_cell_rendered_height(GnmCell const * cell)949 gnm_cell_rendered_height (GnmCell const *cell)
950 {
951 	const GnmRenderedValue *rv;
952 
953 	g_return_val_if_fail (cell != NULL, 0);
954 
955 	rv = gnm_cell_get_rendered_value (cell);
956 	return rv
957 		? PANGO_PIXELS (rv->layout_natural_height)
958 		: 0;
959 }
960 
961 /*
962  * Return the width of the rendered layout after rotation.
963  */
964 int
gnm_cell_rendered_width(GnmCell const * cell)965 gnm_cell_rendered_width (GnmCell const *cell)
966 {
967 	const GnmRenderedValue *rv;
968 
969 	g_return_val_if_fail (cell != NULL, 0);
970 
971 	rv = gnm_cell_get_rendered_value (cell);
972 	return rv
973 		? PANGO_PIXELS (rv->layout_natural_width)
974 		: 0;
975 }
976 
977 int
gnm_cell_rendered_offset(GnmCell const * cell)978 gnm_cell_rendered_offset (GnmCell const * cell)
979 {
980 	const GnmRenderedValue *rv;
981 
982 	g_return_val_if_fail (cell != NULL, 0);
983 
984 	rv = gnm_cell_get_rendered_value (cell);
985 	return rv
986 		? rv->indent_left + rv->indent_right
987 		: 0;
988 }
989 
990 /**
991  * gnm_cell_get_style:
992  * @cell: #GnmCell to query
993  *
994  * Returns: (transfer none): the fully qualified style for @cell.
995  */
996 GnmStyle const *
gnm_cell_get_style(GnmCell const * cell)997 gnm_cell_get_style (GnmCell const *cell)
998 {
999 	g_return_val_if_fail (cell != NULL, NULL);
1000 	return sheet_style_get (cell->base.sheet,
1001 				cell->pos.col,
1002 				cell->pos.row);
1003 }
1004 
1005 /**
1006  * gnm_cell_get_effective_style:
1007  * @cell: #GnmCell to query
1008  *
1009  * Returns: (transfer none): the fully qualified style for @cell, taking any
1010  * conditional formats into account.
1011  */
1012 GnmStyle const *
gnm_cell_get_effective_style(GnmCell const * cell)1013 gnm_cell_get_effective_style (GnmCell const *cell)
1014 {
1015 	GnmStyleConditions *conds;
1016 	GnmStyle const *mstyle;
1017 
1018 	g_return_val_if_fail (cell != NULL, NULL);
1019 
1020 	mstyle = gnm_cell_get_style (cell);
1021 	conds = gnm_style_get_conditions (mstyle);
1022 	if (conds) {
1023 		GnmEvalPos ep;
1024 		int res;
1025 		eval_pos_init_cell (&ep, cell);
1026 
1027 		res = gnm_style_conditions_eval (conds, &ep);
1028 		if (res >= 0)
1029 			mstyle = gnm_style_get_cond_style (mstyle, res);
1030 	}
1031 	return mstyle;
1032 }
1033 
1034 
1035 /**
1036  * gnm_cell_get_format_given_style: (skip)
1037  * @cell: #GnmCell to query
1038  * @style: (nullable): #GnmStyle for @cell.
1039  *
1040  * Returns: (transfer none): the effective format for the cell, i.e., @style's
1041  * format unless that is General and the cell value has a format.
1042  **/
1043 GOFormat const *
gnm_cell_get_format_given_style(GnmCell const * cell,GnmStyle const * style)1044 gnm_cell_get_format_given_style (GnmCell const *cell, GnmStyle const *style)
1045 {
1046 	GOFormat const *fmt;
1047 
1048 	g_return_val_if_fail (cell != NULL, go_format_general ());
1049 
1050 	if (style == NULL)
1051 		style = gnm_cell_get_effective_style (cell);
1052 
1053 	fmt = gnm_style_get_format (style);
1054 
1055 	g_return_val_if_fail (fmt != NULL, go_format_general ());
1056 
1057 	if (go_format_is_general (fmt) &&
1058 	    cell->value != NULL && VALUE_FMT (cell->value))
1059 		fmt = VALUE_FMT (cell->value);
1060 
1061 	return fmt;
1062 }
1063 
1064 /**
1065  * gnm_cell_get_format:
1066  * @cell: #GnmCell to query
1067  *
1068  * Returns: (transfer none): the effective format for the cell, i.e., the
1069  * cell style's format unless that is General and the cell value has a format.
1070  **/
1071 GOFormat const *
gnm_cell_get_format(GnmCell const * cell)1072 gnm_cell_get_format (GnmCell const *cell)
1073 {
1074 	GnmStyle const *mstyle = gnm_cell_get_effective_style (cell);
1075 	return gnm_cell_get_format_given_style (cell, mstyle);
1076 }
1077 
1078 static GnmValue *
cb_set_array_value(GnmCellIter const * iter,gpointer user)1079 cb_set_array_value (GnmCellIter const *iter, gpointer user)
1080 {
1081 	GnmValue const *value = user;
1082 	GnmCell *cell = iter->cell;
1083 	int x, y;
1084 
1085 	/* Clipboard cells, e.g., are not attached to a sheet.  */
1086 	if (gnm_cell_expr_is_linked (cell))
1087 		dependent_unlink (GNM_CELL_TO_DEP (cell));
1088 
1089 	if (!gnm_expr_top_is_array_elem (cell->base.texpr, &x, &y))
1090 		return NULL;
1091 
1092 	gnm_expr_top_unref (cell->base.texpr);
1093 	cell->base.texpr = NULL;
1094 	value_release (cell->value);
1095 	cell->value = value_dup (value_area_get_x_y (value, x, y, NULL));
1096 
1097 	return NULL;
1098 }
1099 
1100 /**
1101  * gnm_cell_convert_expr_to_value:
1102  * @cell: #GnmCell
1103  * drops the expression keeps its value.  Then uses the formatted
1104  *      result as if that had been entered.
1105  *
1106  * NOTE : the cell's expression cannot be linked into the expression * list.
1107  *
1108  * The cell is rendered but spans are not calculated,  the cell is NOT marked for
1109  * recalc.
1110  *
1111  * WARNING : This is an internal routine that does not queue redraws,
1112  *           does not auto-resize, and does not calculate spans.
1113  */
1114 void
gnm_cell_convert_expr_to_value(GnmCell * cell)1115 gnm_cell_convert_expr_to_value (GnmCell *cell)
1116 {
1117 	GnmExprTop const *texpr;
1118 
1119 	g_return_if_fail (cell != NULL);
1120 	g_return_if_fail (gnm_cell_has_expr (cell));
1121 
1122 	/* Clipboard cells, e.g., are not attached to a sheet.  */
1123 	if (gnm_cell_expr_is_linked (cell))
1124 		dependent_unlink (GNM_CELL_TO_DEP (cell));
1125 
1126 	texpr = cell->base.texpr;
1127 	if (gnm_expr_top_is_array_corner (texpr)) {
1128 		int rows, cols;
1129 
1130 		gnm_expr_top_get_array_size (texpr, &cols, &rows);
1131 
1132 		sheet_foreach_cell_in_region (cell->base.sheet, CELL_ITER_ALL,
1133 					     cell->pos.col, cell->pos.row,
1134 					     cell->pos.col + cols - 1,
1135 					     cell->pos.row + rows - 1,
1136 					     cb_set_array_value,
1137 					     gnm_expr_top_get_array_value (texpr));
1138 	} else {
1139 		g_return_if_fail (!gnm_cell_is_array (cell));
1140 	}
1141 
1142 	gnm_expr_top_unref (texpr);
1143 	cell->base.texpr = NULL;
1144 }
1145 
cell_boxed_copy(gpointer c)1146 static gpointer cell_boxed_copy (gpointer c) { return c; }
cell_boxed_free(gpointer c)1147 static void cell_boxed_free (gpointer c) { }
1148 
1149 GType
gnm_cell_get_type(void)1150 gnm_cell_get_type (void)
1151 {
1152     static GType type_cell = 0;
1153 
1154     if (!type_cell)
1155 	type_cell = g_boxed_type_register_static
1156 	    ("GnmCell",
1157 	     cell_boxed_copy,
1158 	     cell_boxed_free);
1159 
1160     return type_cell;
1161 }
1162 
1163 // Provide the external version of inline functions, used mainly for
1164 // introspection
1165 
1166 /**
1167  * gnm_cell_has_expr:
1168  * @cell: #GnmCell
1169  *
1170  * Returns: %TRUE if @cell has an expression or %FALSE if it is empty
1171  * or contains a value.
1172  */
1173 extern inline gboolean gnm_cell_has_expr (GnmCell const *cell);
1174