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

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

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

37
38
39
40
/**
 * cell_formula_changed : Registers the expression with the sheet and
 *     optionally queues a recalc.
 * @cell : the dirty cell.
41
 * @queue_recalc: also queue a recalc for the cell.
42
43
44
45
 *
 * INTERNAL.
 */
static void
46
cell_formula_changed (Cell *cell, gboolean queue_recalc)
47
{
48
	sheet_cell_expr_link (cell);
49
	if (queue_recalc)
Jody Goldberg's avatar
Jody Goldberg committed
50
		eval_queue_cell (cell);
51
}
Morten Welinder's avatar
Morten Welinder committed
52

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
 * cell_cleanout :
 *      Empty a cell's
 *      	- value.
 *      	- rendered_value.
 *      	- entered_text/expression.
 *      	- optional format.
 *     
 *      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
71
static void
72
73
cell_cleanout (Cell *cell)
{
74
75
	/* A cell can have either an expression or entered text */
	if (cell_has_expr (cell)) {
76
		/* Clipboard cells, e.g., are not attached to a sheet.  */
77
78
		if (cell_expr_is_linked (cell))
			sheet_cell_expr_unlink (cell);
79
80
81
82
83
		expr_tree_unref (cell->u.expression);
		cell->u.expression = NULL;
	} else if (cell->u.entered_text) {
		string_unref (cell->u.entered_text);
		cell->u.entered_text = NULL;
84
85
86
87
88
89
	}

	if (cell->value) {
		value_release (cell->value);
		cell->value = NULL;
	}
90
91
92
93
94
95
96
	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;
97
	}
98
99

	cell->cell_flags &= ~(CELL_HAS_EXPRESSION|CELL_QUEUED_FOR_RECALC);
100
101
}

102
103
104
105
106
/**
 * cell_copy:
 * @cell: existing cell to duplicate
 *
 * Makes a copy of a Cell.
Michael Meeks's avatar
Michael Meeks committed
107
 *
108
 * Returns a copy of the cell.
Michael Meeks's avatar
Michael Meeks committed
109
 */
110
Cell *
111
cell_copy (Cell const *cell)
Michael Meeks's avatar
Michael Meeks committed
112
{
113
	Cell *new_cell;
Michael Meeks's avatar
Michael Meeks committed
114

115
	g_return_val_if_fail (cell != NULL, NULL);
116

117
	new_cell = g_new (Cell, 1);
118

119
120
	/* bitmap copy first */
	*new_cell = *cell;
121

122
123
124
	/* The new cell is not linked into any of the major management structures */
	new_cell->sheet = NULL;
	new_cell->cell_flags &= ~(CELL_QUEUED_FOR_RECALC|CELL_IN_SHEET_LIST|CELL_IN_EXPR_LIST);
Morten Welinder's avatar
Morten Welinder committed
125

126
127
128
129
130
	/* now copy properly the rest */
	if (cell_has_expr (new_cell))
		expr_tree_ref (new_cell->u.expression);
	else
		string_ref (new_cell->u.entered_text);
131

132
	new_cell->rendered_value = NULL;
133

134
135
136
	new_cell->value = (new_cell->value)
	    ? value_duplicate (new_cell->value)
	    : value_new_empty ();
Morten Welinder's avatar
Morten Welinder committed
137

138
139
140
	if (cell->format)
		style_format_ref (cell->format);

141
142
143
	if (cell->comment) {
		new_cell->comment = NULL;
		cell_set_comment (new_cell, cell->comment->comment->str);
Morten Welinder's avatar
Morten Welinder committed
144
	}
Miguel de Icaza's avatar
New:    
Miguel de Icaza committed
145

146
	return new_cell;
Arturo Espinosa's avatar
Arturo Espinosa committed
147
}
Arturo Espinosa's avatar
Arturo Espinosa committed
148

149
150
151
152
153
154
/**
 * cell_destroy: Frees all resources allocated to the cell's content and marks the
 *     Cell's container as dirty.
 *
 * @cell : The cell to destroy
 */
155
void
156
cell_destroy (Cell *cell)
157
158
159
{
	g_return_if_fail (cell != NULL);

160
161
162
163
	cell_dirty (cell);
	cell_cleanout (cell);
	cell_comment_destroy (cell);
	g_free (cell);
164
}
165

166
167
168
169
170
171
/**
 * cell_content_changed: Queues recalc of all of the cells depends.
 *
 */
void
cell_content_changed (Cell *cell)
172
{
173
	GList   *deps;
174

175
176
	g_return_if_fail (cell != NULL);

177
178
179
	/* Queue all of the dependencies for this cell */
	deps = cell_get_dependencies (cell);
	if (deps)
Jody Goldberg's avatar
Jody Goldberg committed
180
		eval_queue_list (deps, TRUE);
181
182
}

183
184
/*
 * cell_relocate:
Jody Goldberg's avatar
Jody Goldberg committed
185
186
 * @cell   : The cell that is changing position
 * @rwinfo : An OPTIONAL pointer to allow for bounds checking and relocation
187
188
189
190
191
192
 *
 * 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
193
cell_relocate (Cell *cell, ExprRewriteInfo *rwinfo)
194
{
195
	g_return_if_fail (cell != NULL);
196

197
198
	/* 1. Tag the cell as dirty */
	cell_dirty (cell);
199

200
201
	/* 2. If the cell contains a formula, relocate the formula */
	if (cell_has_expr (cell)) {
Jody Goldberg's avatar
Jody Goldberg committed
202
203
		ExprTree *expr = cell->u.expression;

204
		if (cell_expr_is_linked (cell))
205
			sheet_cell_expr_unlink (cell);
206

207
208
209
210
211
212
213
214
215
		/*
		 * 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
216
217
218
		if (expr->any.oper == OPER_ARRAY) {
			int const x = expr->array.x;
			int const y = expr->array.y;
219
			if (x != 0 || y != 0)
Jody Goldberg's avatar
Jody Goldberg committed
220
				expr->array.corner.cell =
221
					sheet_cell_get (cell->sheet,
222
223
							cell->pos.col - x,
							cell->pos.row - y);
224
		}
225

Jody Goldberg's avatar
Jody Goldberg committed
226
227
228
		/* bounds check, and adjust local references from the cell */
		if (rwinfo != NULL) {
			expr = expr_rewrite (expr, rwinfo);
229

230
			if (expr != NULL) {
231
				/* expression was unlinked above */
232
233
234
235
				expr_tree_unref (cell->u.expression);
				cell->u.expression = expr;
			}
		}
236

237
		/* Relink the expression.  */
238
		cell_formula_changed (cell, TRUE);
239
240
	}

241
	/* 3. Move any auxiliary canvas items */
242
	if (cell->comment)
243
		cell_comment_reposition (cell);
244
245
}

246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/****************************************************************************/

/*
 * cell_set_text : Stores the supplied text as the entered_text, then parses it
 *      for storage as a value or expression.  It marks the sheet as dirty.
 *
 * If the text is an expression it IS queued for recalc.
 *        the format prefered by the expression is stored for later use.
 * If the text is a value it is rendered but spans are not calculated.
 *        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.
 */
262
void
263
cell_set_text (Cell *cell, char const *text)
264
{
265
	StyleFormat *format;
266
267
	Value *val;
	ExprTree *expr;
268
	EvalPos pos;
269

270
	g_return_if_fail (cell != NULL);
271
272
	g_return_if_fail (text != NULL);
	g_return_if_fail (!cell_is_partial_array (cell));
273

274
	format = parse_text_value_or_expr (eval_pos_init_cell (&pos, cell),
Jody Goldberg's avatar
Jody Goldberg committed
275
276
					   text, &val, &expr,
					   NULL /* TODO : Use assigned format ? */);
277

278
279
	if (val != NULL) {	/* String was a value */
		cell_cleanout (cell);
280

281
282
283
		cell->cell_flags &= ~CELL_HAS_EXPRESSION;
		cell->value = val;
		cell->u.entered_text = string_get (text);
284
		cell->format = format;
285
286
		cell_render_value (cell);
	} else {		/* String was an expression */
Jody Goldberg's avatar
Jody Goldberg committed
287
		cell_set_expr (cell, expr, format);
288
		if (format) style_format_unref (format);
289
		expr_tree_unref (expr);
290
	}
291
	cell_dirty (cell);
292
293
}

Miguel de Icaza's avatar
Miguel de Icaza committed
294
/*
295
296
297
298
299
300
 * cell_set_text_and_value : Stores the supplied text as the entered_text, then
 *      stores (WITHOUT COPYING) the supplied value.
 *      It marks the sheet as dirty. The text is NOT parsed.
 *
 * The cell is rendered but spans are not calculated.
 * If an optional format is supplied it is stored for later use.
Miguel de Icaza's avatar
Miguel de Icaza committed
301
 *
302
303
304
305
 * 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.
Miguel de Icaza's avatar
Miguel de Icaza committed
306
 */
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
307
void
308
cell_set_text_and_value (Cell *cell, String *text,
Jody Goldberg's avatar
Jody Goldberg committed
309
			 Value *v, StyleFormat *opt_fmt)
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
310
{
311
312
313
314
	g_return_if_fail (cell);
	g_return_if_fail (text);
	g_return_if_fail (v);
	g_return_if_fail (!cell_is_partial_array (cell));
Arturo Espinosa's avatar
Arturo Espinosa committed
315

Jody Goldberg's avatar
Jody Goldberg committed
316
317
318
	if (opt_fmt != NULL)
		style_format_ref (opt_fmt);

319
320
	cell_dirty (cell);
	cell_cleanout (cell);
321

Jody Goldberg's avatar
Jody Goldberg committed
322
	cell->format = opt_fmt;
323
	cell->u.entered_text = string_ref (text);
324
325
	cell->value = v;
	cell_render_value (cell);
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
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
359
360
361
362
	cell->value = v;
	cell_render_value (cell);
}

/*
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
374
375
376
377
378
379
380
 * 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.
 *
 * 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 imporove the parser to handle all formats that exist within
 *      the workbook.
 *
 * NOTE : This DOES check for array partitioning.
Michael Meeks's avatar
Michael Meeks committed
381
382
 */
void
Jody Goldberg's avatar
Jody Goldberg committed
383
cell_set_value (Cell *cell, Value *v, StyleFormat *opt_fmt)
Michael Meeks's avatar
Michael Meeks committed
384
385
386
{
	g_return_if_fail (cell);
	g_return_if_fail (v);
387
	g_return_if_fail (!cell_is_partial_array (cell));
388

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

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

Jody Goldberg's avatar
Jody Goldberg committed
395
	cell->format = opt_fmt;
396
397
	cell->value = v;
	cell_render_value (cell);
398
399
400
401
402
403
404

	/* Be careful that a value passes as a string stays a string */
	if (v->type == VALUE_STRING) {
		/* TODO : add new string routine to avoid the extra copy */
		char *tmp = g_strconcat ("\'", v->v_str.val->str, NULL);
		cell->u.entered_text = string_get (tmp);
		g_free (tmp);
Jody Goldberg's avatar
Jody Goldberg committed
405
406
407
	} else if (opt_fmt) {
		/* If available use the supplied format */
		cell->u.entered_text = string_get (format_value (opt_fmt, v, NULL, NULL));
408
	} else
Jody Goldberg's avatar
Jody Goldberg committed
409
		/* Fall back on using the format applied to the cell */
410
		cell->u.entered_text = string_ref (cell->rendered_value->rendered_text);
Michael Meeks's avatar
Michael Meeks committed
411
412
}

413
/*
414
 * cell_set_expr_and_value : Stores (WITHOUT COPYING) the supplied value, and
415
416
417
 *        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.
418
 *
419
 * If an optional format is supplied it is stored for later use.
420
 *
421
422
 * The cell is rendered but spans are not calculated,  the cell is NOT marked for
 * recalc.
423
 *
424
425
 * 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
426
 *
427
 * NOTE : This DOES check for array partitioning.
428
 */
429
void
430
cell_set_expr_and_value (Cell *cell, ExprTree *expr, Value *v)
431
{
Arturo Espinosa's avatar
Arturo Espinosa committed
432
	g_return_if_fail (cell != NULL);
433
434
435
436
437
	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);
Arturo Espinosa's avatar
Arturo Espinosa committed
438

439
	cell_dirty (cell);
440
	cell_cleanout (cell);
441

442
443
	cell->u.expression = expr;
	cell->cell_flags |= CELL_HAS_EXPRESSION;
444
	sheet_cell_expr_link (cell);
445
446
447
448
449
450
451
#if 0
	/* TODO : Should we add this for consistancy ? */
	cell->format = fmt;
#endif
	cell->value = v;
	cell_render_value (cell);
}
452

453
454
/**
 * cell_set_expr_internal:
455
 * @cell: the cell to set the formula to
456
 * @expr: an expression tree with the formula
457
 * opt_fmt: an optional format to apply to the cell.
458
459
460
461
462
463
 *
 * A private internal utility to store an expression.
 * Does NOT
 * 	- check for array subdivision
 * 	- queue recalcs.
 * 	- render value, calc dimension, compute spans
464
 * 	- link the expression into the master list.
465
 */
Jody Goldberg's avatar
Jody Goldberg committed
466
static void
Jody Goldberg's avatar
Jody Goldberg committed
467
cell_set_expr_internal (Cell *cell, ExprTree *expr, StyleFormat *opt_fmt)
468
{
Jody Goldberg's avatar
Jody Goldberg committed
469
470
	if (opt_fmt != NULL)
		style_format_ref (opt_fmt);
471

472
	expr_tree_ref (expr);
473

474
475
	cell_dirty (cell);
	cell_cleanout (cell);
476

477
478
479
	if (cell->u.expression)
		expr_tree_unref (cell->u.expression);

Jody Goldberg's avatar
Jody Goldberg committed
480
	cell->format = opt_fmt;
481
482
	cell->u.expression = expr;
	cell->cell_flags |= CELL_HAS_EXPRESSION;
483

484
485
	/* Until the value is recomputed, we put in this value.  */
	cell->value = value_new_error (NULL, gnumeric_err_RECALC);
486
487
488
}

/*
Jody Goldberg's avatar
Jody Goldberg committed
489
490
491
 * 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.
492
493
494
495
496
497
498
 *
 * 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
499
500
 *           It also DOES NOT CHECK FOR ARRAY DIVISION.  Be very careful
 *           using this.
501
502
 */
void
Jody Goldberg's avatar
Jody Goldberg committed
503
cell_set_expr_unsafe (Cell *cell, ExprTree *expr, StyleFormat *opt_fmt)
504
505
{
	g_return_if_fail (cell != NULL);
506
	g_return_if_fail (expr != NULL);
507

Jody Goldberg's avatar
Jody Goldberg committed
508
	cell_set_expr_internal (cell, expr, opt_fmt);
509
	cell_formula_changed (cell, TRUE);
510
511
}

Jody Goldberg's avatar
Jody Goldberg committed
512
513
514
515
516
/**
 * 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
517
cell_set_expr (Cell *cell, ExprTree *expr, StyleFormat *opt_fmt)
Jody Goldberg's avatar
Jody Goldberg committed
518
519
520
{
	g_return_if_fail (!cell_is_partial_array (cell));

Jody Goldberg's avatar
Jody Goldberg committed
521
	cell_set_expr_unsafe (cell, expr, opt_fmt);
Jody Goldberg's avatar
Jody Goldberg committed
522
523
}

524
525
526
527
528
529
530
531
/**
 * 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
532
533
 * @queue_recalc : A flag that if true indicates that the cells should be
 *                 queued for recalc.
534
 *
535
 * Uses cell_set_expr_internal to store the formula as an
536
537
538
 * '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
539
540
 * put it at the head of the recalc queue if recalcs are requested.
 *
Jody Goldberg's avatar
Jody Goldberg committed
541
542
543
 * NOTE : Does not add a reference to the expression.  It takes over the callers
 *        reference.
 *
544
545
546
 * Does not regenerate spans, dimensions or autosize cols/rows.
 *
 * DOES NOT CHECK for array partitioning.
547
548
549
550
 */
void
cell_set_array_formula (Sheet *sheet,
			int row_a, int col_a, int row_b, int col_b,
551
			ExprTree *formula,
552
			gboolean queue_recalc)
553
554
555
556
557
{
	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);
558
	ExprTree *wrapper;
559
560
561
562
563

	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
564
565
	g_return_if_fail (col_a <= col_b);
	g_return_if_fail (row_a <= row_b);
566

567
568
569
	wrapper = expr_tree_new_array (0, 0, num_rows, num_cols);
	wrapper->array.corner.func.value = NULL;
	wrapper->array.corner.func.expr = formula;
570
	cell_set_expr_internal (corner, wrapper, NULL);
571
	expr_tree_unref (wrapper);
572
573

	for (x = 0; x < num_cols; ++x)
574
		for (y = 0; y < num_rows; ++y) {
575
576
			Cell *cell;

577
578
			if (x == 0 && y == 0)
				continue;
579

Michael Meeks's avatar
Michael Meeks committed
580
			cell = sheet_cell_fetch (sheet, col_a + x, row_a + y);
581
582
			wrapper = expr_tree_new_array (x, y, num_rows, num_cols);
			wrapper->array.corner.cell = corner;
583
			cell_set_expr_internal (cell, wrapper, NULL);
Jody Goldberg's avatar
Jody Goldberg committed
584
			cell_formula_changed (cell, queue_recalc);
585
			expr_tree_unref (wrapper);
586
587
588
		}

	/* Put the corner at the head of the recalc list */
589
	cell_formula_changed (corner, queue_recalc);
590
591
}

592
/***************************************************************************/
Arturo Espinosa's avatar
Arturo Espinosa committed
593

594
gboolean
595
cell_is_blank (Cell const * cell)
Arturo Espinosa's avatar
Arturo Espinosa committed
596
{
597
598
	return (cell == NULL || cell->value == NULL ||
		cell->value->type == VALUE_EMPTY);
Arturo Espinosa's avatar
Arturo Espinosa committed
599
}
600

601
Value *
602
cell_is_error (Cell const * cell)
603
{
604
605
	g_return_val_if_fail (cell != NULL, NULL);
	g_return_val_if_fail (cell->value != NULL, NULL);
606

607
608
609
	if (cell->value->type == VALUE_ERROR)
		return cell->value;
	return NULL;
610
611
}

612
gboolean
613
cell_is_number (Cell const *cell)
614
{
615
616
	/* FIXME : This does not handle arrays or ranges */
	return (cell->value && VALUE_IS_NUMBER (cell->value));
617
}
618

619
gboolean
620
cell_is_zero (Cell const *cell)
621
622
623
624
625
{
	Value const * const v = cell->value;
	if (v == NULL)
		return FALSE;
	switch (v->type) {
626
627
	case VALUE_BOOLEAN : return !v->v_bool.val;
	case VALUE_INTEGER : return v->v_int.val == 0;
628
629
	case VALUE_FLOAT :
	{
630
		double const res = v->v_float.val;
631
632
633
634
635
636
637
		return (-1e-10 < res && res < 1e-10);
	}

	default :
		return FALSE;
	}
}
638

639
ExprArray const *
640
cell_is_array (Cell const *cell)
641
{
642
	if (cell != NULL && cell_has_expr (cell) &&
643
644
	    cell->u.expression->any.oper == OPER_ARRAY)
		return &cell->u.expression->array;
645
	return NULL;
646
647
}

648
gboolean
649
cell_is_partial_array (Cell const *cell)
650
{
651
	ExprArray const *ref = cell_is_array (cell);
652
	return ref != NULL && (ref->cols > 1 || ref->rows > 1);
653
654
}

655
/***************************************************************************/
656
657

/*
658
659
 * cell_render_value
 * @cell: The cell whose value needs to be rendered
660
 *
661
662
663
664
665
 * 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.
666
667
 */
void
668
cell_render_value (Cell *cell)
669
{
670
	RenderedValue *rv;
671
672
	g_return_if_fail (cell != NULL);

673
	rv = rendered_value_new (cell, NULL);
674
675
676
	if (cell->rendered_value)
		rendered_value_destroy (cell->rendered_value);
	cell->rendered_value = rv;
677
678
}

679

680
MStyle *
681
cell_get_mstyle (Cell const *cell)
682
{
683
	return sheet_style_compute (cell->sheet,
684
685
				    cell->pos.col,
				    cell->pos.row);
686
687
688
}

void
689
cell_set_mstyle (Cell const *cell, MStyle *mstyle)
690
691
692
{
	Range         range;

693
694
	range.start = cell->pos;
	range.end   = range.start;
695
696
697
698

	sheet_style_attach (cell->sheet, range, mstyle);
}

Morten Welinder's avatar
Morten Welinder committed
699
char *
700
cell_get_format (Cell const *cell)
Morten Welinder's avatar
Morten Welinder committed
701
{
702
703
	char   *result = NULL;
	MStyle *mstyle = cell_get_mstyle (cell);
Morten Welinder's avatar
Morten Welinder committed
704
705

	if (mstyle_is_element_set (mstyle, MSTYLE_FORMAT)) {
706
		char const *format;
Morten Welinder's avatar
Morten Welinder committed
707
		format = mstyle_get_format (mstyle)->format;
708

Morten Welinder's avatar
Morten Welinder committed
709
710
		/* FIXME: we really should distinguish between "not assigned"
		   and "assigned General".  */
711
712
713
714
715
716
717
718
719
720
		if (format) {
			/* If the format is General it may have been over
			 * ridden by the format used to parse the input text.
			 */
			if (strcmp (format, "General") != 0)
				result = g_strdup (format);
			else if (cell->format)
				result = g_strdup (cell->format->format);
		}
	}
Morten Welinder's avatar
Morten Welinder committed
721
722
723
724

	mstyle_unref (mstyle);
	return result;
}
725
726
727
728
729
730

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

	g_return_if_fail (mstyle != NULL);

741
	mstyle_set_format_text (mstyle, format);
742
743
744
745
	cell_set_mstyle (cell, mstyle);
	cell_dirty (cell);
}

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

Jody Goldberg's avatar
Jody Goldberg committed
766
767
768
769
770
771
772
773
774
775
	expr_tree_unref (cell->u.expression);
	cell->u.expression = NULL;
	cell->cell_flags &= ~CELL_HAS_EXPRESSION;

	if (cell->rendered_value == NULL)
		cell_render_value (cell);

	g_return_if_fail (cell->rendered_value != NULL);

	cell->u.entered_text = string_ref (cell->rendered_value->rendered_text);
776
777
	cell_dirty (cell);
}