cell.c 19.7 KB
Newer Older
1
2
3
4
/*
 * cell.c: Cell management of the Gnumeric spreadsheet.
 *
 * Author:
5
 *    Jdy Goldberg 2000 (jgoldberg@home.com)
6
 *    Miguel de Icaza 1998, 1999 (miguel@kernel.org)
7
 */
8
#include "config.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
9
#include "gnumeric.h"
10
#include "cell.h"
11
#include "sheet.h"
12
#include "expr.h"
13
#include "rendered-value.h"
14
#include "value.h"
15
#include "style.h"
Jody Goldberg's avatar
Jody Goldberg committed
16
#include "format.h"
17
#include "sheet-object-cell-comment.h"
18
19
#include "eval.h"
#include "sheet-style.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
20

21
22
extern int dependency_debugging;

23
24
25
26
27
28
/**
 * cell_dirty : Mark the sheet containing the cell as being dirty.
 * @cell : the dirty cell.
 *
 * INTERNAL.
 */
29
static inline void
30
cell_dirty (Cell *cell)
31
{
32
	Sheet *sheet = cell->base.sheet;
33
34
35

	/* Cells from the clipboard do not have a sheet attached */
	if (sheet)
36
		sheet_set_dirty(sheet, TRUE);
37
38
}

39
40
41
42
43
/**
 * cell_cleanout :
 *      Empty a cell's
 *      	- value.
 *      	- rendered_value.
44
45
 *      	- expression.
 *      	- parse format.
46
 *
47
48
49
 *      Clears the flags to
 *      	- not queued for recalc.
 *      	- has no expression.
50
 *
51
52
53
54
55
56
 *      Does NOT change
 *      	- Comments.
 *      	- Spans.
 *      	- unqueue a previously queued recalc.
 *      	- Mark sheet as dirty.
 */
Jody Goldberg's avatar
typo.    
Jody Goldberg committed
57
static void
58
59
cell_cleanout (Cell *cell)
{
60
61
	/* A cell can have either an expression or entered text */
	if (cell_has_expr (cell)) {
62
		/* Clipboard cells, e.g., are not attached to a sheet.  */
63
		if (cell_expr_is_linked (cell))
64
65
66
			dependent_unlink (CELL_TO_DEP (cell), &cell->pos);
		expr_tree_unref (cell->base.expression);
		cell->base.expression = NULL;
67
68
69
70
71
72
	}

	if (cell->value) {
		value_release (cell->value);
		cell->value = NULL;
	}
73
74
75
76
77
78
79
	if (cell->rendered_value) {
		rendered_value_destroy (cell->rendered_value);
		cell->rendered_value = NULL;
	}
	if (cell->format) {
		style_format_unref (cell->format);
		cell->format = NULL;
80
	}
81

Jody Goldberg's avatar
Jody Goldberg committed
82
	cell->base.flags &= ~(CELL_HAS_EXPRESSION|DEPENDENT_IN_RECALC_QUEUE|DEPENDENT_NEEDS_RECALC);
83
84
}

85
86
87
88
89
/**
 * cell_copy:
 * @cell: existing cell to duplicate
 *
 * Makes a copy of a Cell.
Michael Meeks's avatar
Michael Meeks committed
90
 *
91
 * Returns a copy of the cell.
Michael Meeks's avatar
Michael Meeks committed
92
 */
93
Cell *
94
cell_copy (Cell const *cell)
Michael Meeks's avatar
Michael Meeks committed
95
{
96
	Cell *new_cell;
Michael Meeks's avatar
Michael Meeks committed
97

98
	g_return_val_if_fail (cell != NULL, NULL);
99

100
	new_cell = g_new (Cell, 1);
101

102
103
	/* bitmap copy first */
	*new_cell = *cell;
104

105
	/* The new cell is not linked into any of the major management structures */
106
	new_cell->base.sheet = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
107
	new_cell->base.flags &= ~(DEPENDENT_IN_RECALC_QUEUE|DEPENDENT_NEEDS_RECALC|CELL_IN_SHEET_LIST|DEPENDENT_IN_EXPR_LIST);
Morten Welinder's avatar
Morten Welinder committed
108

109
110
	/* now copy properly the rest */
	if (cell_has_expr (new_cell))
111
		expr_tree_ref (new_cell->base.expression);
112

113
	new_cell->rendered_value = NULL;
114

115
	new_cell->value = (new_cell->value)
116
117
		? value_duplicate (new_cell->value)
		: value_new_empty ();
Morten Welinder's avatar
Morten Welinder committed
118

119
120
121
	if (cell->format)
		style_format_ref (cell->format);

122
	return new_cell;
Arturo Espinosa's avatar
Arturo Espinosa committed
123
}
Arturo Espinosa's avatar
Arturo Espinosa committed
124

125
126
127
128
129
130
/**
 * cell_destroy: Frees all resources allocated to the cell's content and marks the
 *     Cell's container as dirty.
 *
 * @cell : The cell to destroy
 */
131
void
132
cell_destroy (Cell *cell)
133
134
135
{
	g_return_if_fail (cell != NULL);

136
137
138
	cell_dirty (cell);
	cell_cleanout (cell);
	g_free (cell);
139
}
140

141
/**
142
143
 * cell_eval_content:
 * @cell: the cell to evaluate.
144
 *
145
146
147
148
 * This function evaluates the contents of the cell,
 * it should not be used by anyone. It is an internal
 * function.
 **/
149
gboolean
150
151
152
153
cell_eval_content (Cell *cell)
{
	Value   *v;
	EvalPos	 pos;
154
	int	 max_iterate = 100;
155
156

	if (!cell_has_expr (cell))
157
		return TRUE;
158
159
160
161
162
163
164
165
166
167
168
169

#ifdef DEBUG_EVALUATION
	if (dependency_debugging > 1) {
		ParsePos pp;

		char *exprtxt = expr_decode_tree
			(cell->base.expression, parse_pos_init_cell (&pp, cell));
		printf ("Evaluating %s: %s ->\n", cell_name (cell), exprtxt);
		g_free (exprtxt);
	}
#endif

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
	if (cell->base.flags & DEPENDENT_BEING_CALCULATED) {
		/* Init to 0 */
		if (cell->value->type == VALUE_ERROR) {
			value_release (cell->value);
			cell->value = value_new_int (0);
		} else if (cell->value == NULL)
			cell->value = value_new_int (0);
		cell->base.flags &= ~DEPENDENT_BEING_CALCULATED;
		puts ("bottom iterate");
		return FALSE;
	}

	eval_pos_init_cell (&pos, cell);
iterate :
	cell->base.flags |= DEPENDENT_BEING_CALCULATED;
	v = eval_expr (&pos, cell->base.expression, EVAL_STRICT);

	if (cell->base.flags & DEPENDENT_BEING_CALCULATED)
		cell->base.flags &= ~DEPENDENT_BEING_CALCULATED;
	else if (max_iterate-- > 0) {
		printf ("start iterate %d\n", max_iterate);
		goto iterate;
	}
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208

#ifdef DEBUG_EVALUATION
	if (dependency_debugging > 1) {
		char *valtxt = v
			? value_get_as_string (v)
			: g_strdup ("NULL");
		printf ("Evaluating %s: -> %s\n", cell_name (cell), valtxt);
		g_free (valtxt);
	}
#endif

	if (v == NULL)
		v = value_new_error (&pos, "Internal error");

	cell_assign_value (cell, v, NULL);
	sheet_redraw_cell (cell);
209
	return TRUE;
210
211
}

212
213
/*
 * cell_relocate:
Jody Goldberg's avatar
Jody Goldberg committed
214
215
 * @cell   : The cell that is changing position
 * @rwinfo : An OPTIONAL pointer to allow for bounds checking and relocation
216
217
218
219
220
221
 *
 * This routine is used to move a cell to a different location:
 *
 * Auxiliary items canvas items attached to the cell are moved.
 */
void
Jody Goldberg's avatar
Jody Goldberg committed
222
cell_relocate (Cell *cell, ExprRewriteInfo *rwinfo)
223
{
224
	g_return_if_fail (cell != NULL);
225

226
227
	/* 1. Tag the cell as dirty */
	cell_dirty (cell);
228

229
230
	/* 2. If the cell contains a formula, relocate the formula */
	if (cell_has_expr (cell)) {
231
		ExprTree *expr = cell->base.expression;
Jody Goldberg's avatar
Jody Goldberg committed
232

233
		if (cell_expr_is_linked (cell))
234
			dependent_unlink (CELL_TO_DEP (cell), &cell->pos);
235

Jody Goldberg's avatar
Jody Goldberg committed
236
237
238
		/* bounds check, and adjust local references from the cell */
		if (rwinfo != NULL) {
			expr = expr_rewrite (expr, rwinfo);
239

240
			if (expr != NULL) {
241
				/* expression was unlinked above */
242
243
				expr_tree_unref (cell->base.expression);
				cell->base.expression = expr;
244
245
			}
		}
246

247
		/* Relink the expression.  */
248
		dependent_changed (CELL_TO_DEP (cell), &cell->pos, TRUE);
249
250
251
	}
}

252
253
254
/****************************************************************************/

/*
255
256
 * cell_set_text : Parses the supplied text for storage as a value or
 * 		expression.  It marks the sheet as dirty.
257
258
259
 *
 * If the text is an expression it IS queued for recalc.
 *        the format prefered by the expression is stored for later use.
260
 * If the text is a value it is NOT rendered and spans are NOT calculated.
261
262
263
264
265
266
267
 *        the format that matched the text is stored for later use.
 *
 * WARNING : This is an internal routine that does not queue redraws,
 *           does not auto-resize, and does not calculate spans.
 *
 * NOTE : This DOES check for array partitioning.
 */
268
void
269
cell_set_text (Cell *cell, char const *text)
270
{
271
	StyleFormat *format;
272
273
	Value *val;
	ExprTree *expr;
274
	EvalPos pos;
275
276
	MStyle *mstyle;
	StyleFormat *cformat;
277

278
	g_return_if_fail (cell != NULL);
279
280
	g_return_if_fail (text != NULL);
	g_return_if_fail (!cell_is_partial_array (cell));
281

282
283
	mstyle = cell_get_mstyle (cell);
	cformat = mstyle_get_format (mstyle);
284
	format = parse_text_value_or_expr (eval_pos_init_cell (&pos, cell),
285
					   text, &val, &expr, cformat);
286

287
288
	if (val != NULL) {	/* String was a value */
		cell_cleanout (cell);
289

290
		cell->base.flags &= ~CELL_HAS_EXPRESSION;
291
		cell->value = val;
292
		cell->format = format;
293
		cell_render_value (cell, TRUE);
294
	} else {		/* String was an expression */
Jody Goldberg's avatar
Jody Goldberg committed
295
		cell_set_expr (cell, expr, format);
296
		if (format) style_format_unref (format);
297
		expr_tree_unref (expr);
298
	}
299
	cell_dirty (cell);
300
301
}

Michael Meeks's avatar
Michael Meeks committed
302
/*
303
304
305
306
 * cell_assign_value : Stores (WITHOUT COPYING) the supplied value.
 *    no changes are made to the expression or entered text.  This
 *    is for use by routines that wish to store values directly such
 *    as expression calculation or import for array formulas.
Michael Meeks's avatar
Michael Meeks committed
307
 *
308
 * The value is rendered but spans are not calculated.
Michael Meeks's avatar
Michael Meeks committed
309
 *
310
 * If an optional format is supplied it is stored for later use.
Michael Meeks's avatar
Michael Meeks committed
311
 *
312
313
314
315
316
 * WARNING : This is an internal routine that does not queue redraws,
 *           does not auto-resize, does not calculate spans, does
 *           not mark anything as dirty.
 *
 * NOTE : This DOES NOT check for array partitioning.
Michael Meeks's avatar
Michael Meeks committed
317
318
 */
void
Jody Goldberg's avatar
Jody Goldberg committed
319
cell_assign_value (Cell *cell, Value *v, StyleFormat *opt_fmt)
Michael Meeks's avatar
Michael Meeks committed
320
321
322
323
{
	g_return_if_fail (cell);
	g_return_if_fail (v);

Jody Goldberg's avatar
Jody Goldberg committed
324
325
326
327
328
	if (cell->format)
		style_format_unref (cell->format);
	if (opt_fmt)
		style_format_ref (opt_fmt);
	cell->format = opt_fmt;
329
330
331

	if (cell->value != NULL)
		value_release (cell->value);
Michael Meeks's avatar
Michael Meeks committed
332
	cell->value = v;
333
	cell_render_value (cell, TRUE);
Michael Meeks's avatar
Michael Meeks committed
334
335
336
}

/*
337
338
339
340
341
 * cell_set_value : Stores (WITHOUT COPYING) the supplied value.  It marks the
 *          sheet as dirty.
 *
 * The value is rendered but spans are not calculated, then the rendered string
 * is stored as if that is what the user had entered.
Michael Meeks's avatar
Michael Meeks committed
342
 *
343
344
345
346
347
 * If an optional format is supplied it is stored for later use.
 *
 * WARNING : This is an internal routine that does not queue redraws,
 *           does not auto-resize, and does not calculate spans.
 *
348
349
350
351
 * FIXME FIXME FIXME : The current format code only checks against the list of
 * canned formats.  Therefore the rendered string MAY NOT BE PARSEABLE!! if the
 * user has assigned a non-std format.  We need to improve the parser to handle
 * all formats that exist within the workbook.
352
353
 *
 * NOTE : This DOES check for array partitioning.
Michael Meeks's avatar
Michael Meeks committed
354
355
 */
void
Jody Goldberg's avatar
Jody Goldberg committed
356
cell_set_value (Cell *cell, Value *v, StyleFormat *opt_fmt)
Michael Meeks's avatar
Michael Meeks committed
357
358
359
{
	g_return_if_fail (cell);
	g_return_if_fail (v);
360
	g_return_if_fail (!cell_is_partial_array (cell));
361

Jody Goldberg's avatar
Jody Goldberg committed
362
363
364
	if (opt_fmt)
		style_format_ref (opt_fmt);

365
366
	cell_dirty (cell);
	cell_cleanout (cell);
Michael Meeks's avatar
Michael Meeks committed
367

368
	/* TODO : It would be nice to standardize on NULL == General */
369
370
	cell->format = (opt_fmt == NULL || style_format_is_general (opt_fmt))
		? NULL : opt_fmt;
371
	cell->value = v;
Michael Meeks's avatar
Michael Meeks committed
372
373
}

374
/*
375
 * cell_set_expr_and_value : Stores (WITHOUT COPYING) the supplied value, and
376
377
378
 *        references the supplied expression and links it into the expression
 *        list.  It marks the sheet as dirty. It is intended for use by import
 *        routines or operations that do bulk assignment.
379
 *
380
 * If an optional format is supplied it is stored for later use.
381
 *
382
 * WARNING : This is an internal routine that does not queue redraws,
383
384
 *           does not auto-resize, does not calculate spans, and does
 *           not render the value.
Jody Goldberg's avatar
Jody Goldberg committed
385
 *
386
 * NOTE : This DOES check for array partitioning.
387
 */
388
void
389
cell_set_expr_and_value (Cell *cell, ExprTree *expr, Value *v,
390
			 StyleFormat *opt_fmt, gboolean link_expr)
391
{
Arturo Espinosa's avatar
Arturo Espinosa committed
392
	g_return_if_fail (cell != NULL);
393
394
395
396
397
	g_return_if_fail (expr != NULL);
	g_return_if_fail (!cell_is_partial_array (cell));

	/* Repeat after me.  Ref before unref. */
	expr_tree_ref (expr);
398
399
	if (opt_fmt != NULL)
		style_format_ref (opt_fmt);
Arturo Espinosa's avatar
Arturo Espinosa committed
400

401
	cell_dirty (cell);
402
	cell_cleanout (cell);
403

404
	cell->format = opt_fmt;
405
	cell->base.expression = expr;
406
	cell->base.flags |= CELL_HAS_EXPRESSION;
407
	cell->value = v;
408
409
	if (link_expr)
		dependent_link (CELL_TO_DEP (cell), &cell->pos);
410
}
411

412
413
/**
 * cell_set_expr_internal:
414
 * @cell: the cell to set the formula to
415
 * @expr: an expression tree with the formula
416
 * opt_fmt: an optional format to apply to the cell.
417
418
419
420
421
422
 *
 * A private internal utility to store an expression.
 * Does NOT
 * 	- check for array subdivision
 * 	- queue recalcs.
 * 	- render value, calc dimension, compute spans
423
 * 	- link the expression into the master list.
424
 */
Jody Goldberg's avatar
Jody Goldberg committed
425
static void
Jody Goldberg's avatar
Jody Goldberg committed
426
cell_set_expr_internal (Cell *cell, ExprTree *expr, StyleFormat *opt_fmt)
427
{
428
	expr_tree_ref (expr);
Jody Goldberg's avatar
Jody Goldberg committed
429
430
	if (opt_fmt != NULL)
		style_format_ref (opt_fmt);
431

432
433
	cell_dirty (cell);
	cell_cleanout (cell);
434

Jody Goldberg's avatar
Jody Goldberg committed
435
	cell->format = opt_fmt;
436
	cell->base.expression = expr;
437
	cell->base.flags |= CELL_HAS_EXPRESSION;
438

439
440
	/* Until the value is recomputed, we put in this value.  */
	cell->value = value_new_error (NULL, gnumeric_err_RECALC);
441
442
443
}

/*
Jody Goldberg's avatar
Jody Goldberg committed
444
445
446
 * cell_set_expr_unsafe : Stores and references the supplied expression.  It
 *         marks the sheet as dirty.  Intented for use by import routines that
 *         do bulk assignment.
447
448
449
450
451
452
453
 *
 * The cell IS marked for recalc.
 *
 * If an optional format is supplied it is stored for later use.
 *
 * WARNING : This is an internal routine that does not queue redraws,
 *           does not auto-resize, and does not calculate spans.
Jody Goldberg's avatar
Jody Goldberg committed
454
455
 *           It also DOES NOT CHECK FOR ARRAY DIVISION.  Be very careful
 *           using this.
456
457
 */
void
Jody Goldberg's avatar
Jody Goldberg committed
458
cell_set_expr_unsafe (Cell *cell, ExprTree *expr, StyleFormat *opt_fmt)
459
460
{
	g_return_if_fail (cell != NULL);
461
	g_return_if_fail (expr != NULL);
462

Jody Goldberg's avatar
Jody Goldberg committed
463
	cell_set_expr_internal (cell, expr, opt_fmt);
464
	dependent_changed (CELL_TO_DEP (cell), &cell->pos, TRUE);
465
466
}

Jody Goldberg's avatar
Jody Goldberg committed
467
468
469
470
471
/**
 * cell_set_expr : A utility wrapper for cell_set_expr_unsafe.  That adds
 *      checks for array subdivision.
 */
void
Jody Goldberg's avatar
Jody Goldberg committed
472
cell_set_expr (Cell *cell, ExprTree *expr, StyleFormat *opt_fmt)
Jody Goldberg's avatar
Jody Goldberg committed
473
474
475
{
	g_return_if_fail (!cell_is_partial_array (cell));

Jody Goldberg's avatar
Jody Goldberg committed
476
	cell_set_expr_unsafe (cell, expr, opt_fmt);
Jody Goldberg's avatar
Jody Goldberg committed
477
478
}

479
480
481
482
483
484
485
486
/**
 * cell_set_array_formula:
 * @sheet:   The sheet to set the formula to.
 * @row_a:   The top row in the destination region.
 * @col_a:   The left column in the destination region.
 * @row_b:   The bottom row in the destination region.
 * @col_b:   The right column in the destination region.
 * @formula: an expression tree with the formula
487
488
 * @queue_recalc : A flag that if true indicates that the cells should be
 *                 queued for recalc.
489
 *
490
 * Uses cell_set_expr_internal to store the formula as an
491
492
493
 * 'array-formula'.  The supplied expression is wrapped in an array
 * operator for each cell in the range and scheduled for recalc.  The
 * upper left corner is handled as a special case and care is taken to
494
495
 * put it at the head of the recalc queue if recalcs are requested.
 *
Jody Goldberg's avatar
Jody Goldberg committed
496
497
498
 * NOTE : Does not add a reference to the expression.  It takes over the callers
 *        reference.
 *
499
500
501
 * Does not regenerate spans, dimensions or autosize cols/rows.
 *
 * DOES NOT CHECK for array partitioning.
502
503
504
505
 */
void
cell_set_array_formula (Sheet *sheet,
			int row_a, int col_a, int row_b, int col_b,
506
			ExprTree *formula,
507
			gboolean queue_recalc)
508
509
510
511
512
{
	int const num_rows = 1 + row_b - row_a;
	int const num_cols = 1 + col_b - col_a;
	int x, y;
	Cell * const corner = sheet_cell_fetch (sheet, col_a, row_a);
513
	ExprTree *wrapper;
514
515
516
517
518

	g_return_if_fail (num_cols > 0);
	g_return_if_fail (num_rows > 0);
	g_return_if_fail (formula != NULL);
	g_return_if_fail (corner != NULL);
Jody Goldberg's avatar
Jody Goldberg committed
519
520
	g_return_if_fail (col_a <= col_b);
	g_return_if_fail (row_a <= row_b);
521

522
	wrapper = expr_tree_new_array (0, 0, num_rows, num_cols);
523
524
	wrapper->array.corner.value = NULL;
	wrapper->array.corner.expr = formula;
525
	cell_set_expr_internal (corner, wrapper, NULL);
526
	expr_tree_unref (wrapper);
527
528

	for (x = 0; x < num_cols; ++x)
529
		for (y = 0; y < num_rows; ++y) {
530
531
			Cell *cell;

532
533
			if (x == 0 && y == 0)
				continue;
534

Michael Meeks's avatar
Michael Meeks committed
535
			cell = sheet_cell_fetch (sheet, col_a + x, row_a + y);
536
			wrapper = expr_tree_new_array (x, y, num_rows, num_cols);
537
			cell_set_expr_internal (cell, wrapper, NULL);
538
539
			dependent_changed (CELL_TO_DEP (cell),
					   &cell->pos, queue_recalc);
540
			expr_tree_unref (wrapper);
541
542
543
		}

	/* Put the corner at the head of the recalc list */
544
	dependent_changed (CELL_TO_DEP (corner), &corner->pos, queue_recalc);
545
546
}

547
/***************************************************************************/
Arturo Espinosa's avatar
Arturo Espinosa committed
548

549
gboolean
550
cell_is_blank (Cell const * cell)
Arturo Espinosa's avatar
Arturo Espinosa committed
551
{
552
553
	return (cell == NULL || cell->value == NULL ||
		cell->value->type == VALUE_EMPTY);
Arturo Espinosa's avatar
Arturo Espinosa committed
554
}
555

556
Value *
557
cell_is_error (Cell const * cell)
558
{
559
560
	g_return_val_if_fail (cell != NULL, NULL);
	g_return_val_if_fail (cell->value != NULL, NULL);
561

562
563
564
	if (cell->value->type == VALUE_ERROR)
		return cell->value;
	return NULL;
565
566
}

567
gboolean
568
cell_is_number (Cell const *cell)
569
{
570
571
	/* FIXME : This does not handle arrays or ranges */
	return (cell->value && VALUE_IS_NUMBER (cell->value));
572
}
573

574
gboolean
575
cell_is_zero (Cell const *cell)
576
577
578
579
580
{
	Value const * const v = cell->value;
	if (v == NULL)
		return FALSE;
	switch (v->type) {
581
582
	case VALUE_BOOLEAN : return !v->v_bool.val;
	case VALUE_INTEGER : return v->v_int.val == 0;
583
584
	case VALUE_FLOAT :
	{
585
		double const res = v->v_float.val;
586
587
588
589
590
591
592
		return (-1e-10 < res && res < 1e-10);
	}

	default :
		return FALSE;
	}
}
593

594
ExprArray const *
595
cell_is_array (Cell const *cell)
596
{
597
	if (cell != NULL && cell_has_expr (cell) &&
598
599
	    cell->base.expression->any.oper == OPER_ARRAY)
		return &cell->base.expression->array;
600
	return NULL;
601
602
}

603
gboolean
604
cell_is_partial_array (Cell const *cell)
605
{
606
	ExprArray const *ref = cell_is_array (cell);
607
	return ref != NULL && (ref->cols > 1 || ref->rows > 1);
608
609
}

610
/***************************************************************************/
611

612
613
/**
 * cell_render_value :
614
 * @cell: The cell whose value needs to be rendered
615
 * @dynamic_width : Allow format to depend on column width.
616
 *
617
618
619
620
621
 * TODO :
 * There is no reason currently for this to allocate the rendered value as
 * seperate entity.  However, in the future I'm thinking of referencing them
 * akin to strings.  We need to do some profiling of how frequently things
 * are shared.
622
623
 */
void
624
cell_render_value (Cell *cell, gboolean dynamic_width)
625
{
626
	RenderedValue *rv;
627
	MStyle *mstyle;
628

629
630
	g_return_if_fail (cell != NULL);

631
632
633
	mstyle = cell_get_mstyle (cell);

	rv = rendered_value_new (cell, mstyle, dynamic_width);
634
635
636
	if (cell->rendered_value)
		rendered_value_destroy (cell->rendered_value);
	cell->rendered_value = rv;
637
638

	rendered_value_calc_size_ext (cell, mstyle);
639
640
}

641

642
MStyle *
643
cell_get_mstyle (Cell const *cell)
644
{
645
646
647
648
	g_return_val_if_fail (cell != NULL, NULL);
	return sheet_style_get (cell->base.sheet,
				cell->pos.col,
				cell->pos.row);
649
650
}

Morten Welinder's avatar
Morten Welinder committed
651
char *
652
cell_get_format (Cell const *cell)
Morten Welinder's avatar
Morten Welinder committed
653
{
654
	char   *result = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
655
	MStyle *mstyle;
656

Jody Goldberg's avatar
Jody Goldberg committed
657
658
659
	g_return_val_if_fail (cell != NULL, g_strdup ("General"));

	mstyle = cell_get_mstyle (cell);
Morten Welinder's avatar
Morten Welinder committed
660
661

	if (mstyle_is_element_set (mstyle, MSTYLE_FORMAT)) {
Jody Goldberg's avatar
Jody Goldberg committed
662
		StyleFormat const *format = mstyle_get_format (mstyle);
663

Morten Welinder's avatar
Morten Welinder committed
664
		/* FIXME: we really should distinguish between "not assigned"
Jody Goldberg's avatar
Jody Goldberg committed
665
666
667
668
		 * and "assigned General".
		 *
		 * 8/20/00 JEG : Do we still need this test ?
		 */
669
670
671
672
		if (format) {
			/* If the format is General it may have been over
			 * ridden by the format used to parse the input text.
			 */
Jody Goldberg's avatar
Jody Goldberg committed
673
674
675
676
677
			result = style_format_as_XL (format, FALSE);
			if (!strcmp (result, "General") != 0 && cell->format != NULL) {
				g_free (result);
				result = style_format_as_XL (cell->format, FALSE);
			}
678
679
		}
	}
Morten Welinder's avatar
Morten Welinder committed
680
681
682

	return result;
}
683
684
685
686
687
688

/*
 * cell_set_format:
 *
 * Changes the format for CELL to be FORMAT.  FORMAT should be
 * a number display format as specified on the manual
689
690
 *
 * Does not render, redraw, or respan.
691
692
 */
void
693
cell_set_format (Cell *cell, char const *format)
694
{
695
	Range r;
Jody Goldberg's avatar
Jody Goldberg committed
696
	MStyle *mstyle = mstyle_new ();
697
698
699
700

	g_return_if_fail (mstyle != NULL);

	cell_dirty (cell);
701
702
703
704
	mstyle_set_format_text (mstyle, format);

	r.start = r.end = cell->pos;
	sheet_style_apply_range (cell->base.sheet, &r, mstyle);
705
706
}

Jody Goldberg's avatar
Jody Goldberg committed
707
/**
708
 * cell_convert_expr_to_value : drops the expression keeps its value.  Then uses the formatted
Jody Goldberg's avatar
Jody Goldberg committed
709
710
 *      result as if that had been entered.
 *
Morten Welinder's avatar
Morten Welinder committed
711
 * NOTE : the cell's expression cannot be linked into the expression * list.
Jody Goldberg's avatar
Jody Goldberg committed
712
713
714
715
716
717
718
719
 *
 * The cell is rendered but spans are not calculated,  the cell is NOT marked for
 * recalc.
 *
 * WARNING : This is an internal routine that does not queue redraws,
 *           does not auto-resize, and does not calculate spans.
 *
 * NOTE : This DOES NOT check for array partitioning.
720
721
 */
void
722
cell_convert_expr_to_value (Cell *cell)
723
724
725
726
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (cell_has_expr(cell));

727
728
729
730
	/* Clipboard cells, e.g., are not attached to a sheet.  */
	if (cell_expr_is_linked (cell))
		dependent_unlink (CELL_TO_DEP (cell), &cell->pos);

731
732
	expr_tree_unref (cell->base.expression);
	cell->base.expression = NULL;
733
	cell->base.flags &= ~CELL_HAS_EXPRESSION;
Jody Goldberg's avatar
Jody Goldberg committed
734
735

	if (cell->rendered_value == NULL)
736
		cell_render_value (cell, TRUE);
Jody Goldberg's avatar
Jody Goldberg committed
737

738
739
	cell_dirty (cell);
}
740

741
742
743
744
745
746
747
748
749
750
751
752
guint
cellpos_hash (CellPos const *key)
{
	return (key->row << 8) | key->col;
}

gint
cellpos_cmp (CellPos const * a, CellPos const * b)
{
	return (a->row == b->row && a->col == b->col);
}

753
754
755


CellComment *
756
cell_has_comment_pos (const Sheet *sheet, const CellPos *pos)
757
758
759
760
761
{
	Range r;
	GList *comments;
	CellComment *res;

762
	r.start = r.end = *pos;
763
764
765
766
767
768
769
770
771
	comments = sheet_get_objects (sheet, &r, CELL_COMMENT_TYPE);
	if (!comments)
		return NULL;

	/* This assumes just one comment per cell.  */
	res = comments->data;
	g_list_free (comments);
	return res;
}
772
773
774
775
776
777
778


CellComment *
cell_has_comment (const Cell *cell)
{
	return cell_has_comment_pos (cell->base.sheet, &cell->pos);
}