cell.c 18.7 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"
Arturo Espinosa's avatar
Arturo Espinosa committed
19

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

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

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

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
 * 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
69
static void
70
71
cell_cleanout (Cell *cell)
{
72
73
	/* A cell can have either an expression or entered text */
	if (cell_has_expr (cell)) {
74
75
76
		/* Clipboard cells, e.g., are not attached to a sheet.  */
		if (cell->sheet)
			sheet_cell_formula_unlink (cell);
77
78
79
80
81
		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;
82
83
84
85
86
87
	}

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

	cell->cell_flags &= ~(CELL_HAS_EXPRESSION|CELL_QUEUED_FOR_RECALC);
98
99
}

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

113
	g_return_val_if_fail (cell != NULL, NULL);
114

115
	new_cell = g_new (Cell, 1);
116

117
118
	/* bitmap copy first */
	*new_cell = *cell;
119

120
	new_cell->cell_flags &= ~CELL_QUEUED_FOR_RECALC;
Morten Welinder's avatar
Morten Welinder committed
121

122
123
124
125
126
	/* 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);
127

128
	new_cell->rendered_value = NULL;
129

130
131
132
	new_cell->value = (new_cell->value)
	    ? value_duplicate (new_cell->value)
	    : value_new_empty ();
Morten Welinder's avatar
Morten Welinder committed
133

134
135
136
	if (cell->comment) {
		new_cell->comment = NULL;
		cell_set_comment (new_cell, cell->comment->comment->str);
Morten Welinder's avatar
Morten Welinder committed
137
	}
Miguel de Icaza's avatar
New:    
Miguel de Icaza committed
138

139
	return new_cell;
Arturo Espinosa's avatar
Arturo Espinosa committed
140
}
Arturo Espinosa's avatar
Arturo Espinosa committed
141

142
143
144
145
146
147
/**
 * cell_destroy: Frees all resources allocated to the cell's content and marks the
 *     Cell's container as dirty.
 *
 * @cell : The cell to destroy
 */
148
void
149
cell_destroy (Cell *cell)
150
151
152
{
	g_return_if_fail (cell != NULL);

153
154
155
156
	cell_dirty (cell);
	cell_cleanout (cell);
	cell_comment_destroy (cell);
	g_free (cell);
157
}
158

159
160
161
162
163
164
/**
 * cell_content_changed: Queues recalc of all of the cells depends.
 *
 */
void
cell_content_changed (Cell *cell)
165
{
166
	GList   *deps;
167

168
169
	g_return_if_fail (cell != NULL);

170
171
172
173
	/* Queue all of the dependencies for this cell */
	deps = cell_get_dependencies (cell);
	if (deps)
		cell_queue_recalc_list (deps, TRUE);
174

175
	sheet_cell_changed (cell);
176
177
}

178
179
180
181
182
183
184
185
186
187
/*
 * cell_relocate:
 * @cell:           The cell that is changing position
 * @check_bonunds : Should expressions be bounds checked.
 *
 * This routine is used to move a cell to a different location:
 *
 * Auxiliary items canvas items attached to the cell are moved.
 */
void
188
cell_relocate (Cell *cell, gboolean check_bounds)
189
{
190
	g_return_if_fail (cell != NULL);
191

192
193
	/* 1. Tag the cell as dirty */
	cell_dirty (cell);
194

195
196
197
	/* 2. If the cell contains a formula, relocate the formula */
	if (cell_has_expr (cell)) {
		sheet_cell_formula_unlink (cell);
198

199
200
201
202
203
204
205
206
207
		/*
		 * 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 */
208
209
210
		if (cell->u.expression->any.oper == OPER_ARRAY) {
			int const x = cell->u.expression->array.x;
			int const y = cell->u.expression->array.y;
211
			if (x != 0 || y != 0)
212
				cell->u.expression->array.corner.cell =
213
214
215
					sheet_cell_get (cell->sheet,
							cell->col_info->pos - x,
							cell->row_info->pos - y);
216
		}
217

218
219
		/*
		 * We do not actually need to change any references
220
221
222
223
224
		 * the move is from its current location to its current
		 * location.  All the move is doing is a bounds check.
		 */
		if (check_bounds) {
			ExprRelocateInfo	rinfo;
225
			EvalPos 		pos;
226
			ExprTree    	*expr = cell->u.expression;
227

228
229
230
231
232
233
234
			rinfo.origin.start.col =
				rinfo.origin.end.col = cell->col_info->pos;
			rinfo.origin.start.row =
				rinfo.origin.end.row = cell->row_info->pos;
			rinfo.origin_sheet = rinfo.target_sheet = cell->sheet;
			rinfo.col_offset = 0;
			rinfo.row_offset = 0;
235
			expr = expr_relocate (expr, eval_pos_init_cell (&pos, cell), &rinfo);
236

237
			if (expr != NULL) {
238
				/* expression was unlinked above */
239
240
241
242
				expr_tree_unref (cell->u.expression);
				cell->u.expression = expr;
			}
		}
243

244
		/* Relink the expression.  */
245
		cell_formula_changed (cell, TRUE);
246
247
	}

248
	/* 3. Move any auxiliary canvas items */
249
	if (cell->comment)
250
		cell_comment_reposition (cell);
251

252
	cell_content_changed (cell);
253
254
}

255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/****************************************************************************/

/*
 * 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.
 */
271
void
272
cell_set_text (Cell *cell, char const *text)
273
{
274
275
276
	char const *format;
	Value *val;
	ExprTree *expr;
277
	EvalPos pos;
278

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

283
	format = parse_text_value_or_expr (eval_pos_init_cell (&pos, cell),
284
					   text, &val, &expr);
285

286
287
288
289
	if (val != NULL) {	/* String was a value */
		/* If there was a prefered format remember it */
		StyleFormat * const fmt = (format != NULL)
		    ? style_format_new (format) : NULL;
290

291
		cell_cleanout (cell);
292

293
294
295
296
297
298
299
300
301
		cell->cell_flags &= ~CELL_HAS_EXPRESSION;
		cell->value = val;
		cell->u.entered_text = string_get (text);
		cell->format = fmt;
		cell_render_value (cell);
		cell_content_changed (cell);
	} else {		/* String was an expression */
		cell_set_expr (cell, expr, format);
		expr_tree_unref (expr);
302
	}
303
	cell_dirty (cell);
304
305
}

Miguel de Icaza's avatar
Miguel de Icaza committed
306
/*
307
308
309
310
311
312
 * 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
313
 *
314
315
316
317
 * 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
318
 */
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
319
void
320
321
cell_set_text_and_value (Cell *cell, String *text,
			 Value *v, char const * optional_format)
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
322
{
323
324
325
326
	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
327

328
329
	cell_dirty (cell);
	cell_cleanout (cell);
330

331
332
333
334
335
336
337
338
	/* FIXME : When we remerge the number recognition and the formating
	 * this should be a StyleFormat
	 */
	if (optional_format)
		cell->format = style_format_new (optional_format);
	cell->value = v;
	cell_render_value (cell);
	cell->u.entered_text = string_ref (text);
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
339
340
}

Michael Meeks's avatar
Michael Meeks committed
341
/*
342
343
344
345
 * 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
346
 *
347
 * The value is rendered but spans are not calculated.
Michael Meeks's avatar
Michael Meeks committed
348
 *
349
 * If an optional format is supplied it is stored for later use.
Michael Meeks's avatar
Michael Meeks committed
350
 *
351
352
353
354
355
 * 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
356
357
 */
void
358
cell_assign_value (Cell *cell, Value *v, char const * optional_format)
Michael Meeks's avatar
Michael Meeks committed
359
360
361
362
{
	g_return_if_fail (cell);
	g_return_if_fail (v);

363
364
	if (optional_format)
		cell->format = style_format_new (optional_format);
365
366
367

	if (cell->value != NULL)
		value_release (cell->value);
Michael Meeks's avatar
Michael Meeks committed
368
369
370
371
372
	cell->value = v;
	cell_render_value (cell);
}

/*
373
374
375
376
377
 * 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
378
 *
379
380
381
382
383
384
385
386
387
388
389
390
 * 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
391
392
 */
void
393
cell_set_value (Cell *cell, Value *v, char const * optional_format)
Michael Meeks's avatar
Michael Meeks committed
394
395
396
{
	g_return_if_fail (cell);
	g_return_if_fail (v);
397
	g_return_if_fail (!cell_is_partial_array (cell));
398

399
400
	cell_dirty (cell);
	cell_cleanout (cell);
Michael Meeks's avatar
Michael Meeks committed
401

402
403
404
405
406
	if (optional_format)
		cell->format = style_format_new (optional_format);
	cell->value = v;
	cell_render_value (cell);
	cell->u.entered_text = string_ref (cell->rendered_value->rendered_text);
Michael Meeks's avatar
Michael Meeks committed
407
408
}

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

435
	cell_dirty (cell);
436
	cell_cleanout (cell);
437

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

449
450
451
452
453
454
455
456
457
458
/**
 * cell_set_expr_internal:
 * @cell:    the cell to set the formula to
 * @expr: an expression tree with the formula
 *
 * A private internal utility to store an expression.
 * Does NOT
 * 	- check for array subdivision
 * 	- queue recalcs.
 * 	- render value, calc dimension, compute spans
459
 * 	- link the expression into the master list.
460
461
462
463
464
 */
static void
cell_set_expr_internal (Cell *cell, ExprTree *expr, char const *optional_format)
{
	StyleFormat * fmt;
465

466
467
468
	/* Repeat after me.  Ref before unref. */
	expr_tree_ref (expr);
	fmt = (optional_format != NULL) ? style_format_new (optional_format) : NULL;
469

470
471
	cell_dirty (cell);
	cell_cleanout (cell);
472

473
474
	cell->u.expression = expr;
	cell->cell_flags |= CELL_HAS_EXPRESSION;
475

476
477
	/* Until the value is recomputed, we put in this value.  */
	cell->value = value_new_error (NULL, gnumeric_err_RECALC);
478
479
480
}

/*
481
482
483
484
485
486
487
488
489
490
 * cell_set_expr : A routine that stores and references the supplied
 *         expression.  It marks the sheet as dirty.  Intented for use by
 *         import routines that do bulk assignment.
 *
 * 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.
491
 *
492
 * NOTE : This DOES check for array partitioning.
493
494
 */
void
495
cell_set_expr (Cell *cell, ExprTree *expr, char const *optional_format)
496
497
{
	g_return_if_fail (cell != NULL);
498
499
	g_return_if_fail (expr != NULL);
	g_return_if_fail (!cell_is_partial_array (cell));
500

501
502
	cell_set_expr_internal (cell, expr, optional_format);
	cell_formula_changed (cell, TRUE);
503
504
}

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

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

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

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

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

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

	/* Put the corner at the head of the recalc list */
570
	cell_formula_changed (corner, 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
inline 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
621
inline ExprArray const *
cell_is_array (Cell const *cell)
622
{
623
	if (cell != NULL && cell_has_expr (cell) &&
624
625
	    cell->u.expression->any.oper == OPER_ARRAY)
		return &cell->u.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
 * cell_render_value
 * @cell: The cell whose value needs to be rendered
641
 *
642
643
644
645
646
 * 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.
647
648
 */
void
649
cell_render_value (Cell *cell)
650
{
651
	RenderedValue *rv;
652
653
	g_return_if_fail (cell != NULL);

654
655
656
657
	rv = rendered_value_new (cell);
	if (cell->rendered_value)
		rendered_value_destroy (cell->rendered_value);
	cell->rendered_value = rv;
658
659
}

660

661
MStyle *
662
cell_get_mstyle (Cell const *cell)
663
{
664
665
666
	return sheet_style_compute (cell->sheet,
				    cell->col_info->pos,
				    cell->row_info->pos);
667
668
669
}

void
670
cell_set_mstyle (Cell const *cell, MStyle *mstyle)
671
672
673
{
	Range         range;

674
675
	range.start.col = cell->col_info->pos;
	range.start.row = cell->row_info->pos;
676
677
678
679
680
	range.end       = range.start;

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

Morten Welinder's avatar
Morten Welinder committed
681
char *
682
cell_get_format (Cell const *cell)
Morten Welinder's avatar
Morten Welinder committed
683
684
685
686
{
	MStyle *mstyle;
	char *result;

687
	mstyle = cell_get_mstyle (cell);
Morten Welinder's avatar
Morten Welinder committed
688
	if (mstyle_is_element_set (mstyle, MSTYLE_FORMAT)) {
689
		char const *format;
Morten Welinder's avatar
Morten Welinder committed
690
691
692
693
694
695
696
697
698
699
700
701
702
		format = mstyle_get_format (mstyle)->format;
		/* FIXME: we really should distinguish between "not assigned"
		   and "assigned General".  */
		if (format && strcmp (format, "General") != 0)
			result = g_strdup (format);
		else
			result = NULL;
	} else
		result = NULL;

	mstyle_unref (mstyle);
	return result;
}
703
704
705
706
707
708

/*
 * cell_set_format:
 *
 * Changes the format for CELL to be FORMAT.  FORMAT should be
 * a number display format as specified on the manual
709
710
 *
 * Does not render, redraw, or respan.
711
712
 */
void
713
cell_set_format (Cell *cell, char const *format)
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
{
	MStyle * mstyle = cell_get_mstyle (cell);

	g_return_if_fail (mstyle != NULL);

	mstyle_set_format (mstyle, format);
	cell_set_mstyle (cell, mstyle);
	cell_dirty (cell);
}

/*
 * This routine drops the formula and just keeps the value
 */
void
cell_make_value (Cell *cell)
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (cell_has_expr(cell));

	/* FIXME: does this work at all?  -- MW */
	/* THIS IS CRAP fix soon */
	cell_dirty (cell);
}