cell.c 20.2 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
#include "expr.h"
#include "eval.h"
14
#include "value.h"
15
#include "style.h"
16
#include "sheet.h"
Jody Goldberg's avatar
Jody Goldberg committed
17
#include "sheet-style.h"
18
#include "rendered-value.h"
19
#include "gnumeric-util.h"
20
#include "parse-util.h"
Jody Goldberg's avatar
Jody Goldberg committed
21
#include "format.h"
22
#include "sheet-object-cell-comment.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
 *      Clears the flags to
 *      	- not queued for recalc.
 *      	- has no expression.
53
 *
54
55
56
57
58
59
 *      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
	return new_cell;
Arturo Espinosa's avatar
Arturo Espinosa committed
126
}
Arturo Espinosa's avatar
Arturo Espinosa committed
127

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

139
140
141
	cell_dirty (cell);
	cell_cleanout (cell);
	g_free (cell);
142
}
143

144
/**
145
146
 * cell_eval_content:
 * @cell: the cell to evaluate.
147
 *
148
149
150
151
152
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
 * 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);
189
190
191
192

	/* 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);
193
194
195
196
197
	sheet_redraw_cell (cell);
}

/**
 * cell_content_changed: Queues recalc of all of the cells depends.
198
199
200
 */
void
cell_content_changed (Cell *cell)
201
{
202
	GList   *deps;
203

204
205
	g_return_if_fail (cell != NULL);

206
207
208
	/* Queue all of the dependencies for this cell */
	deps = cell_get_dependencies (cell);
	if (deps)
209
		dependent_queue_recalc_list (deps, 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
614
615
StyleHAlignFlags
cell_default_halign (Cell const *c, MStyle const *mstyle)
{
	StyleHAlignFlags align = mstyle_get_align_h (mstyle);

	if (align == HALIGN_GENERAL) {
616
617
		Value *v;

618
619
		g_return_val_if_fail (c != NULL, HALIGN_RIGHT);

620
621
622
		if (c->base.sheet && c->base.sheet->display_formulas &&
		    cell_has_expr (c))
			return HALIGN_LEFT;
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641

		for (v = c->value; v != NULL ; )
			switch (v->type) {
			case VALUE_BOOLEAN :
				return HALIGN_CENTER;

			case VALUE_INTEGER :
			case VALUE_FLOAT :
				return HALIGN_RIGHT;

			case VALUE_ARRAY :
				if (v->v_array.x > 0 && v->v_array.y > 0) {
					v = v->v_array.vals [0][0];
					break;
				}

			default :
				return HALIGN_LEFT;
			}
642
643
644
645
646
	}

	return align;
}

647
/***************************************************************************/
648

649
650
/**
 * cell_render_value :
651
 * @cell: The cell whose value needs to be rendered
652
 * @dynamic_width : Allow format to depend on column width.
653
 *
654
655
656
657
658
 * 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.
659
660
 */
void
661
cell_render_value (Cell *cell, gboolean dynamic_width)
662
{
663
	RenderedValue *rv;
664
	MStyle *mstyle;
665

666
667
	g_return_if_fail (cell != NULL);

668
669
670
	mstyle = cell_get_mstyle (cell);

	rv = rendered_value_new (cell, mstyle, dynamic_width);
671
672
673
	if (cell->rendered_value)
		rendered_value_destroy (cell->rendered_value);
	cell->rendered_value = rv;
674
675

	rendered_value_calc_size_ext (cell, mstyle);
676
677
}

678

679
MStyle *
680
cell_get_mstyle (Cell const *cell)
681
{
682
683
684
685
	g_return_val_if_fail (cell != NULL, NULL);
	return sheet_style_get (cell->base.sheet,
				cell->pos.col,
				cell->pos.row);
686
687
}

Morten Welinder's avatar
Morten Welinder committed
688
char *
689
cell_get_format (Cell const *cell)
Morten Welinder's avatar
Morten Welinder committed
690
{
691
	char   *result = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
692
	MStyle *mstyle;
693

Jody Goldberg's avatar
Jody Goldberg committed
694
695
696
	g_return_val_if_fail (cell != NULL, g_strdup ("General"));

	mstyle = cell_get_mstyle (cell);
Morten Welinder's avatar
Morten Welinder committed
697
698

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

Morten Welinder's avatar
Morten Welinder committed
701
		/* FIXME: we really should distinguish between "not assigned"
Jody Goldberg's avatar
Jody Goldberg committed
702
703
704
705
		 * and "assigned General".
		 *
		 * 8/20/00 JEG : Do we still need this test ?
		 */
706
707
708
709
		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
710
711
712
713
714
			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);
			}
715
716
		}
	}
Morten Welinder's avatar
Morten Welinder committed
717
718
719

	return result;
}
720
721
722
723
724
725

/*
 * cell_set_format:
 *
 * Changes the format for CELL to be FORMAT.  FORMAT should be
 * a number display format as specified on the manual
726
727
 *
 * Does not render, redraw, or respan.
728
729
 */
void
730
cell_set_format (Cell *cell, char const *format)
731
{
732
	Range r;
Jody Goldberg's avatar
Jody Goldberg committed
733
	MStyle *mstyle = mstyle_new ();
734
735
736
737

	g_return_if_fail (mstyle != NULL);

	cell_dirty (cell);
738
739
740
741
	mstyle_set_format_text (mstyle, format);

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

Jody Goldberg's avatar
Jody Goldberg committed
744
/**
745
 * cell_convert_expr_to_value : drops the expression keeps its value.  Then uses the formatted
Jody Goldberg's avatar
Jody Goldberg committed
746
747
 *      result as if that had been entered.
 *
Morten Welinder's avatar
Morten Welinder committed
748
 * NOTE : the cell's expression cannot be linked into the expression * list.
Jody Goldberg's avatar
Jody Goldberg committed
749
750
751
752
753
754
755
756
 *
 * 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.
757
758
 */
void
759
cell_convert_expr_to_value (Cell *cell)
760
761
762
763
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (cell_has_expr(cell));

764
765
766
767
	/* Clipboard cells, e.g., are not attached to a sheet.  */
	if (cell_expr_is_linked (cell))
		dependent_unlink (CELL_TO_DEP (cell), &cell->pos);

768
769
	expr_tree_unref (cell->base.expression);
	cell->base.expression = NULL;
770
	cell->base.flags &= ~CELL_HAS_EXPRESSION;
Jody Goldberg's avatar
Jody Goldberg committed
771
772

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

775
776
	cell_dirty (cell);
}
777
778
779
780
781
782
783
784
785
786
787
788
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);
}

789
790
791


CellComment *
792
cell_has_comment_pos (const Sheet *sheet, const CellPos *pos)
793
794
795
796
797
{
	Range r;
	GList *comments;
	CellComment *res;

798
	r.start = r.end = *pos;
799
800
801
802
803
804
805
806
807
	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;
}
808
809
810
811
812
813
814


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