cell.c 20 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 "cellspan.h"
12
13
14
#include "cell-comment.h"
#include "expr.h"
#include "eval.h"
15
#include "value.h"
16
#include "style.h"
17
18
19
#include "sheet.h"
#include "value.h"
#include "rendered-value.h"
20
#include "gnumeric-util.h"
21
#include "parse-util.h"
Jody Goldberg's avatar
Jody Goldberg committed
22
#include "format.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
23

24
25
extern int dependency_debugging;

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

	/* Cells from the clipboard do not have a sheet attached */
	if (sheet)
39
		sheet_set_dirty(sheet, TRUE);
40
41
}

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

	if (cell->value) {
		value_release (cell->value);
		cell->value = NULL;
	}
76
77
78
79
80
81
82
	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;
83
	}
84

85
	cell->base.flags &= ~(CELL_HAS_EXPRESSION|DEPENDENT_QUEUED_FOR_RECALC);
86
87
}

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

101
	g_return_val_if_fail (cell != NULL, NULL);
102

103
	new_cell = g_new (Cell, 1);
104

105
106
	/* bitmap copy first */
	*new_cell = *cell;
107

108
	/* The new cell is not linked into any of the major management structures */
109
	new_cell->base.sheet = NULL;
110
	new_cell->base.flags &= ~(DEPENDENT_QUEUED_FOR_RECALC|CELL_IN_SHEET_LIST|DEPENDENT_IN_EXPR_LIST);
Morten Welinder's avatar
Morten Welinder committed
111

112
113
	/* now copy properly the rest */
	if (cell_has_expr (new_cell))
114
		expr_tree_ref (new_cell->base.expression);
115

116
	new_cell->rendered_value = NULL;
117

118
119
120
	new_cell->value = (new_cell->value)
	    ? value_duplicate (new_cell->value)
	    : value_new_empty ();
Morten Welinder's avatar
Morten Welinder committed
121

122
123
124
	if (cell->format)
		style_format_ref (cell->format);

125
126
127
	if (cell->comment) {
		new_cell->comment = NULL;
		cell_set_comment (new_cell, cell->comment->comment->str);
Morten Welinder's avatar
Morten Welinder committed
128
	}
Miguel de Icaza's avatar
New:    
Miguel de Icaza committed
129

130
	return new_cell;
Arturo Espinosa's avatar
Arturo Espinosa committed
131
}
Arturo Espinosa's avatar
Arturo Espinosa committed
132

133
134
135
136
137
138
/**
 * cell_destroy: Frees all resources allocated to the cell's content and marks the
 *     Cell's container as dirty.
 *
 * @cell : The cell to destroy
 */
139
void
140
cell_destroy (Cell *cell)
141
142
143
{
	g_return_if_fail (cell != NULL);

144
145
146
147
	cell_dirty (cell);
	cell_cleanout (cell);
	cell_comment_destroy (cell);
	g_free (cell);
148
}
149

150
/**
151
152
 * cell_eval_content:
 * @cell: the cell to evaluate.
153
 *
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
 * This function evaluates the contents of the cell,
 * it should not be used by anyone. It is an internal
 * function.
 **/
void
cell_eval_content (Cell *cell)
{
	Value   *v;
	EvalPos	 pos;

	if (!cell_has_expr (cell))
		return;

#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

	v = eval_expr (eval_pos_init_cell (&pos, cell),
		       cell->base.expression, EVAL_STRICT);

#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);
195
196
197
198

	/* TODO : Can we Use spancalc without too much performance overhead
	 * Seems like a better approach may be to do this at display time */
	cell_render_value (cell, TRUE);
199
200
201
202
203
	sheet_redraw_cell (cell);
}

/**
 * cell_content_changed: Queues recalc of all of the cells depends.
204
205
206
 */
void
cell_content_changed (Cell *cell)
207
{
208
	GList   *deps;
209

210
211
	g_return_if_fail (cell != NULL);

212
213
214
	/* Queue all of the dependencies for this cell */
	deps = cell_get_dependencies (cell);
	if (deps)
215
		dependent_queue_recalc_list (deps, TRUE);
216
217
}

218
219
/*
 * cell_relocate:
Jody Goldberg's avatar
Jody Goldberg committed
220
221
 * @cell   : The cell that is changing position
 * @rwinfo : An OPTIONAL pointer to allow for bounds checking and relocation
222
223
224
225
226
227
 *
 * 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
228
cell_relocate (Cell *cell, ExprRewriteInfo *rwinfo)
229
{
230
	g_return_if_fail (cell != NULL);
231

232
233
	/* 1. Tag the cell as dirty */
	cell_dirty (cell);
234

235
236
	/* 2. If the cell contains a formula, relocate the formula */
	if (cell_has_expr (cell)) {
237
		ExprTree *expr = cell->base.expression;
Jody Goldberg's avatar
Jody Goldberg committed
238

239
		if (cell_expr_is_linked (cell))
240
			dependent_unlink (CELL_TO_DEP (cell), &cell->pos);
241

242
243
244
245
246
247
248
249
250
		/*
		 * WARNING WARNING WARNING
		 *
		 * This will only work if the new array cell has already
		 * been inserted.
		 *
		 * WARNING WARNING WARNING
		 */
		/* If cell was part of an array, reset the corner pointer */
Jody Goldberg's avatar
Jody Goldberg committed
251
252
253
		if (expr->any.oper == OPER_ARRAY) {
			int const x = expr->array.x;
			int const y = expr->array.y;
254
			if (x != 0 || y != 0)
Jody Goldberg's avatar
Jody Goldberg committed
255
				expr->array.corner.cell =
256
					sheet_cell_get (cell->base.sheet,
257
258
							cell->pos.col - x,
							cell->pos.row - y);
259
		}
260

Jody Goldberg's avatar
Jody Goldberg committed
261
262
263
		/* bounds check, and adjust local references from the cell */
		if (rwinfo != NULL) {
			expr = expr_rewrite (expr, rwinfo);
264

265
			if (expr != NULL) {
266
				/* expression was unlinked above */
267
268
				expr_tree_unref (cell->base.expression);
				cell->base.expression = expr;
269
270
			}
		}
271

272
		/* Relink the expression.  */
273
		dependent_changed (CELL_TO_DEP (cell), &cell->pos, TRUE);
274
275
	}

276
	/* 3. Move any auxiliary canvas items */
277
	if (cell->comment)
278
		cell_comment_reposition (cell);
279
280
}

281
282
283
/****************************************************************************/

/*
284
285
 * cell_set_text : Parses the supplied text for storage as a value or
 * 		expression.  It marks the sheet as dirty.
286
287
288
 *
 * If the text is an expression it IS queued for recalc.
 *        the format prefered by the expression is stored for later use.
289
 * If the text is a value it is NOT rendered and spans are NOT calculated.
290
291
292
293
294
295
296
 *        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.
 */
297
void
298
cell_set_text (Cell *cell, char const *text)
299
{
300
	StyleFormat *format;
301
302
	Value *val;
	ExprTree *expr;
303
	EvalPos pos;
304

305
	g_return_if_fail (cell != NULL);
306
307
	g_return_if_fail (text != NULL);
	g_return_if_fail (!cell_is_partial_array (cell));
308

309
	format = parse_text_value_or_expr (eval_pos_init_cell (&pos, cell),
Jody Goldberg's avatar
Jody Goldberg committed
310
311
					   text, &val, &expr,
					   NULL /* TODO : Use assigned format ? */);
312

313
314
	if (val != NULL) {	/* String was a value */
		cell_cleanout (cell);
315

316
		cell->base.flags &= ~CELL_HAS_EXPRESSION;
317
		cell->value = val;
318
		cell->format = format;
319
		cell_render_value (cell, TRUE);
320
	} else {		/* String was an expression */
Jody Goldberg's avatar
Jody Goldberg committed
321
		cell_set_expr (cell, expr, format);
322
		if (format) style_format_unref (format);
323
		expr_tree_unref (expr);
324
	}
325
	cell_dirty (cell);
326
327
}

Michael Meeks's avatar
Michael Meeks committed
328
/*
329
330
331
332
 * 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
333
 *
334
 * The value is rendered but spans are not calculated.
Michael Meeks's avatar
Michael Meeks committed
335
 *
336
 * If an optional format is supplied it is stored for later use.
Michael Meeks's avatar
Michael Meeks committed
337
 *
338
339
340
341
342
 * 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
343
344
 */
void
Jody Goldberg's avatar
Jody Goldberg committed
345
cell_assign_value (Cell *cell, Value *v, StyleFormat *opt_fmt)
Michael Meeks's avatar
Michael Meeks committed
346
347
348
349
{
	g_return_if_fail (cell);
	g_return_if_fail (v);

Jody Goldberg's avatar
Jody Goldberg committed
350
351
352
353
354
	if (cell->format)
		style_format_unref (cell->format);
	if (opt_fmt)
		style_format_ref (opt_fmt);
	cell->format = opt_fmt;
355
356
357

	if (cell->value != NULL)
		value_release (cell->value);
Michael Meeks's avatar
Michael Meeks committed
358
	cell->value = v;
359
	cell_render_value (cell, TRUE);
Michael Meeks's avatar
Michael Meeks committed
360
361
362
}

/*
363
364
365
366
367
 * 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
368
 *
369
370
371
372
373
 * 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.
 *
374
375
376
377
 * 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.
378
379
 *
 * NOTE : This DOES check for array partitioning.
Michael Meeks's avatar
Michael Meeks committed
380
381
 */
void
Jody Goldberg's avatar
Jody Goldberg committed
382
cell_set_value (Cell *cell, Value *v, StyleFormat *opt_fmt)
Michael Meeks's avatar
Michael Meeks committed
383
384
385
{
	g_return_if_fail (cell);
	g_return_if_fail (v);
386
	g_return_if_fail (!cell_is_partial_array (cell));
387

Jody Goldberg's avatar
Jody Goldberg committed
388
389
390
	if (opt_fmt)
		style_format_ref (opt_fmt);

391
392
	cell_dirty (cell);
	cell_cleanout (cell);
Michael Meeks's avatar
Michael Meeks committed
393

394
	/* TODO : It would be nice to standardize on NULL == General */
395
396
	cell->format = (opt_fmt == NULL || style_format_is_general (opt_fmt))
		? NULL : opt_fmt;
397
	cell->value = v;
Michael Meeks's avatar
Michael Meeks committed
398
399
}

400
/*
401
 * cell_set_expr_and_value : Stores (WITHOUT COPYING) the supplied value, and
402
403
404
 *        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.
405
 *
406
 * If an optional format is supplied it is stored for later use.
407
 *
408
 * WARNING : This is an internal routine that does not queue redraws,
409
410
 *           does not auto-resize, does not calculate spans, and does
 *           not render the value.
Jody Goldberg's avatar
Jody Goldberg committed
411
 *
412
 * NOTE : This DOES check for array partitioning.
413
 */
414
void
415
416
cell_set_expr_and_value (Cell *cell, ExprTree *expr, Value *v,
			 StyleFormat *opt_fmt)
417
{
Arturo Espinosa's avatar
Arturo Espinosa committed
418
	g_return_if_fail (cell != NULL);
419
420
421
422
423
	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);
424
425
	if (opt_fmt != NULL)
		style_format_ref (opt_fmt);
Arturo Espinosa's avatar
Arturo Espinosa committed
426

427
	cell_dirty (cell);
428
	cell_cleanout (cell);
429

430
	cell->format = opt_fmt;
431
	cell->base.expression = expr;
432
	cell->base.flags |= CELL_HAS_EXPRESSION;
433
	dependent_link (CELL_TO_DEP (cell), &cell->pos);
434
435
	cell->value = v;
}
436

437
438
/**
 * cell_set_expr_internal:
439
 * @cell: the cell to set the formula to
440
 * @expr: an expression tree with the formula
441
 * opt_fmt: an optional format to apply to the cell.
442
443
444
445
446
447
 *
 * A private internal utility to store an expression.
 * Does NOT
 * 	- check for array subdivision
 * 	- queue recalcs.
 * 	- render value, calc dimension, compute spans
448
 * 	- link the expression into the master list.
449
 */
Jody Goldberg's avatar
Jody Goldberg committed
450
static void
Jody Goldberg's avatar
Jody Goldberg committed
451
cell_set_expr_internal (Cell *cell, ExprTree *expr, StyleFormat *opt_fmt)
452
{
453
	expr_tree_ref (expr);
Jody Goldberg's avatar
Jody Goldberg committed
454
455
	if (opt_fmt != NULL)
		style_format_ref (opt_fmt);
456

457
458
	cell_dirty (cell);
	cell_cleanout (cell);
459

Jody Goldberg's avatar
Jody Goldberg committed
460
	cell->format = opt_fmt;
461
	cell->base.expression = expr;
462
	cell->base.flags |= CELL_HAS_EXPRESSION;
463

464
465
	/* Until the value is recomputed, we put in this value.  */
	cell->value = value_new_error (NULL, gnumeric_err_RECALC);
466
467
468
}

/*
Jody Goldberg's avatar
Jody Goldberg committed
469
470
471
 * 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.
472
473
474
475
476
477
478
 *
 * 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
479
480
 *           It also DOES NOT CHECK FOR ARRAY DIVISION.  Be very careful
 *           using this.
481
482
 */
void
Jody Goldberg's avatar
Jody Goldberg committed
483
cell_set_expr_unsafe (Cell *cell, ExprTree *expr, StyleFormat *opt_fmt)
484
485
{
	g_return_if_fail (cell != NULL);
486
	g_return_if_fail (expr != NULL);
487

Jody Goldberg's avatar
Jody Goldberg committed
488
	cell_set_expr_internal (cell, expr, opt_fmt);
489
	dependent_changed (CELL_TO_DEP (cell), &cell->pos, TRUE);
490
491
}

Jody Goldberg's avatar
Jody Goldberg committed
492
493
494
495
496
/**
 * 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
497
cell_set_expr (Cell *cell, ExprTree *expr, StyleFormat *opt_fmt)
Jody Goldberg's avatar
Jody Goldberg committed
498
499
500
{
	g_return_if_fail (!cell_is_partial_array (cell));

Jody Goldberg's avatar
Jody Goldberg committed
501
	cell_set_expr_unsafe (cell, expr, opt_fmt);
Jody Goldberg's avatar
Jody Goldberg committed
502
503
}

504
505
506
507
508
509
510
511
/**
 * 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
512
513
 * @queue_recalc : A flag that if true indicates that the cells should be
 *                 queued for recalc.
514
 *
515
 * Uses cell_set_expr_internal to store the formula as an
516
517
518
 * '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
519
520
 * put it at the head of the recalc queue if recalcs are requested.
 *
Jody Goldberg's avatar
Jody Goldberg committed
521
522
523
 * NOTE : Does not add a reference to the expression.  It takes over the callers
 *        reference.
 *
524
525
526
 * Does not regenerate spans, dimensions or autosize cols/rows.
 *
 * DOES NOT CHECK for array partitioning.
527
528
529
530
 */
void
cell_set_array_formula (Sheet *sheet,
			int row_a, int col_a, int row_b, int col_b,
531
			ExprTree *formula,
532
			gboolean queue_recalc)
533
534
535
536
537
{
	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);
538
	ExprTree *wrapper;
539
540
541
542
543

	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
544
545
	g_return_if_fail (col_a <= col_b);
	g_return_if_fail (row_a <= row_b);
546

547
548
549
	wrapper = expr_tree_new_array (0, 0, num_rows, num_cols);
	wrapper->array.corner.func.value = NULL;
	wrapper->array.corner.func.expr = formula;
550
	cell_set_expr_internal (corner, wrapper, NULL);
551
	expr_tree_unref (wrapper);
552
553

	for (x = 0; x < num_cols; ++x)
554
		for (y = 0; y < num_rows; ++y) {
555
556
			Cell *cell;

557
558
			if (x == 0 && y == 0)
				continue;
559

Michael Meeks's avatar
Michael Meeks committed
560
			cell = sheet_cell_fetch (sheet, col_a + x, row_a + y);
561
562
			wrapper = expr_tree_new_array (x, y, num_rows, num_cols);
			wrapper->array.corner.cell = corner;
563
			cell_set_expr_internal (cell, wrapper, NULL);
564
565
			dependent_changed (CELL_TO_DEP (cell),
					   &cell->pos, queue_recalc);
566
			expr_tree_unref (wrapper);
567
568
569
		}

	/* Put the corner at the head of the recalc list */
570
	dependent_changed (CELL_TO_DEP (corner), &corner->pos, queue_recalc);
571
572
}

573
/***************************************************************************/
Arturo Espinosa's avatar
Arturo Espinosa committed
574

575
gboolean
576
cell_is_blank (Cell const * cell)
Arturo Espinosa's avatar
Arturo Espinosa committed
577
{
578
579
	return (cell == NULL || cell->value == NULL ||
		cell->value->type == VALUE_EMPTY);
Arturo Espinosa's avatar
Arturo Espinosa committed
580
}
581

582
Value *
583
cell_is_error (Cell const * cell)
584
{
585
586
	g_return_val_if_fail (cell != NULL, NULL);
	g_return_val_if_fail (cell->value != NULL, NULL);
587

588
589
590
	if (cell->value->type == VALUE_ERROR)
		return cell->value;
	return NULL;
591
592
}

593
gboolean
594
cell_is_number (Cell const *cell)
595
{
596
597
	/* FIXME : This does not handle arrays or ranges */
	return (cell->value && VALUE_IS_NUMBER (cell->value));
598
}
599

600
gboolean
601
cell_is_zero (Cell const *cell)
602
603
604
605
606
{
	Value const * const v = cell->value;
	if (v == NULL)
		return FALSE;
	switch (v->type) {
607
608
	case VALUE_BOOLEAN : return !v->v_bool.val;
	case VALUE_INTEGER : return v->v_int.val == 0;
609
610
	case VALUE_FLOAT :
	{
611
		double const res = v->v_float.val;
612
613
614
615
616
617
618
		return (-1e-10 < res && res < 1e-10);
	}

	default :
		return FALSE;
	}
}
619

620
ExprArray const *
621
cell_is_array (Cell const *cell)
622
{
623
	if (cell != NULL && cell_has_expr (cell) &&
624
625
	    cell->base.expression->any.oper == OPER_ARRAY)
		return &cell->base.expression->array;
626
	return NULL;
627
628
}

629
gboolean
630
cell_is_partial_array (Cell const *cell)
631
{
632
	ExprArray const *ref = cell_is_array (cell);
633
	return ref != NULL && (ref->cols > 1 || ref->rows > 1);
634
635
}

636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
StyleHAlignFlags
cell_default_halign (Cell const *c, MStyle const *mstyle)
{
	StyleHAlignFlags align = mstyle_get_align_h (mstyle);

	if (align == HALIGN_GENERAL) {
		g_return_val_if_fail (c != NULL, HALIGN_RIGHT);

		if (cell_is_number (c) &&
		    c->base.sheet && !c->base.sheet->display_formulas)
			return HALIGN_RIGHT;
		return HALIGN_LEFT;
	}

	return align;
}

653
/***************************************************************************/
654

655
656
/**
 * cell_render_value :
657
 * @cell: The cell whose value needs to be rendered
658
 * @dynamic_width : Allow format to depend on column width.
659
 *
660
661
662
663
664
 * 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.
665
666
 */
void
667
cell_render_value (Cell *cell, gboolean dynamic_width)
668
{
669
	RenderedValue *rv;
670
671
	MStyle *mstyle;
		
672
673
	g_return_if_fail (cell != NULL);

674
675
676
	mstyle = cell_get_mstyle (cell);

	rv = rendered_value_new (cell, mstyle, dynamic_width);
677
678
679
	if (cell->rendered_value)
		rendered_value_destroy (cell->rendered_value);
	cell->rendered_value = rv;
680
681
682

	rendered_value_calc_size_ext (cell, mstyle);
	mstyle_unref (mstyle);
683
684
}

685

686
MStyle *
687
cell_get_mstyle (Cell const *cell)
688
{
689
	return sheet_style_compute (cell->base.sheet,
690
691
				    cell->pos.col,
				    cell->pos.row);
692
693
694
}

void
695
cell_set_mstyle (Cell const *cell, MStyle *mstyle)
696
697
698
{
	Range         range;

699
700
	range.start = cell->pos;
	range.end   = range.start;
701

702
	sheet_style_attach (cell->base.sheet, range, mstyle);
703
704
}

Morten Welinder's avatar
Morten Welinder committed
705
char *
706
cell_get_format (Cell const *cell)
Morten Welinder's avatar
Morten Welinder committed
707
{
708
	char   *result = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
709
710
711
712
713
	MStyle *mstyle;
	
	g_return_val_if_fail (cell != NULL, g_strdup ("General"));

	mstyle = cell_get_mstyle (cell);
Morten Welinder's avatar
Morten Welinder committed
714
715

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

Morten Welinder's avatar
Morten Welinder committed
718
		/* FIXME: we really should distinguish between "not assigned"
Jody Goldberg's avatar
Jody Goldberg committed
719
720
721
722
		 * and "assigned General".
		 *
		 * 8/20/00 JEG : Do we still need this test ?
		 */
723
724
725
726
		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
727
728
729
730
731
			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);
			}
732
733
		}
	}
Morten Welinder's avatar
Morten Welinder committed
734
735
736
737

	mstyle_unref (mstyle);
	return result;
}
738
739
740
741
742
743

/*
 * cell_set_format:
 *
 * Changes the format for CELL to be FORMAT.  FORMAT should be
 * a number display format as specified on the manual
744
745
 *
 * Does not render, redraw, or respan.
746
747
 */
void
748
cell_set_format (Cell *cell, char const *format)
749
{
Jody Goldberg's avatar
Jody Goldberg committed
750
	MStyle *mstyle = mstyle_new ();
751
752
753

	g_return_if_fail (mstyle != NULL);

754
	mstyle_set_format_text (mstyle, format);
755
756
757
758
	cell_set_mstyle (cell, mstyle);
	cell_dirty (cell);
}

Jody Goldberg's avatar
Jody Goldberg committed
759
760
761
762
/**
 * cell_make_value : drops the expression keeps its value.  Then uses the formatted
 *      result as if that had been entered.
 *
Morten Welinder's avatar
Morten Welinder committed
763
 * NOTE : the cell's expression cannot be linked into the expression * list.
Jody Goldberg's avatar
Jody Goldberg committed
764
765
766
767
768
769
770
771
 *
 * 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.
772
773
774
775
776
777
778
 */
void
cell_make_value (Cell *cell)
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (cell_has_expr(cell));

779
780
781
782
	/* Clipboard cells, e.g., are not attached to a sheet.  */
	if (cell_expr_is_linked (cell))
		dependent_unlink (CELL_TO_DEP (cell), &cell->pos);

783
784
	expr_tree_unref (cell->base.expression);
	cell->base.expression = NULL;
785
	cell->base.flags &= ~CELL_HAS_EXPRESSION;
Jody Goldberg's avatar
Jody Goldberg committed
786
787

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

790
791
	cell_dirty (cell);
}