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