cell.c 19.2 KB
Newer Older
1
/* vim: set sw=8: */
2
/*
3
 * cell.c: Cell content and simple management.
4 5
 *
 * Author:
Jody Goldberg's avatar
Jody Goldberg committed
6
 *    Jody Goldberg 2000, 2001 (jody@gnome.org)
7
 *    Miguel de Icaza 1998, 1999 (miguel@kernel.org)
8
 */
9 10
#include <gnumeric-config.h>
#include "gnumeric.h"
11
#include "cell.h"
12

13
#include "workbook.h"
14
#include "sheet.h"
15
#include "expr.h"
16
#include "rendered-value.h"
17
#include "value.h"
18
#include "style.h"
Jody Goldberg's avatar
Jody Goldberg committed
19
#include "format.h"
20
#include "sheet-object-cell-comment.h"
21 22
#include "eval.h"
#include "sheet-style.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
23

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

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

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

	if (cell->value) {
		value_release (cell->value);
		cell->value = NULL;
	}
75 76 77 78 79
	if (cell->rendered_value) {
		rendered_value_destroy (cell->rendered_value);
		cell->rendered_value = NULL;
	}

80
	cell_dirty (cell);
81 82
}

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

96
	g_return_val_if_fail (cell != NULL, NULL);
97

98
	new_cell = g_new (Cell, 1);
99

100 101
	/* bitmap copy first */
	*new_cell = *cell;
102

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

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

111
	new_cell->rendered_value = NULL;
112

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

117
	return new_cell;
Arturo Espinosa's avatar
Arturo Espinosa committed
118
}
Arturo Espinosa's avatar
Arturo Espinosa committed
119

120 121 122 123 124 125
/**
 * cell_destroy: Frees all resources allocated to the cell's content and marks the
 *     Cell's container as dirty.
 *
 * @cell : The cell to destroy
 */
126
void
127
cell_destroy (Cell *cell)
128 129 130
{
	g_return_if_fail (cell != NULL);

131 132
	cell_cleanout (cell);
	g_free (cell);
133
}
134

135
/**
136 137
 * cell_eval_content:
 * @cell: the cell to evaluate.
138
 *
139 140 141 142
 * This function evaluates the contents of the cell,
 * it should not be used by anyone. It is an internal
 * function.
 **/
143
gboolean
144 145
cell_eval_content (Cell *cell)
{
146
	static Cell *iterating = NULL;
147 148
	Value   *v;
	EvalPos	 pos;
149
	int	 max_iteration;
150 151

	if (!cell_has_expr (cell))
152
		return TRUE;
153 154

#ifdef DEBUG_EVALUATION
155
	{
156
		ParsePos pp;
157 158
		char *str = expr_tree_as_string (cell->base.expression,
			parse_pos_init_cell (&pp, cell));
159
		printf ("{\nEvaluating %s: %s;\n", cell_name (cell), str);
160
		g_free (str);
161 162 163
	}
#endif

164
	/* This is the bottom of a cycle */
165
	if (cell->base.flags & DEPENDENT_BEING_CALCULATED) {
166 167 168
		if (!cell->base.sheet->workbook->iteration.enabled)
			return TRUE;

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 195 196 197
		/* but not the first bottom */
		if (cell->base.flags & CELL_BEING_ITERATED) {
#ifdef DEBUG_EVALUATION
			printf ("}; /* already-iterate (%d) */\n", iterating == NULL);
#endif
			return iterating == NULL;
		}

		/* if we are still marked as iterating then make this the last
		 * time through.
		 */
		if (iterating == cell) {
#ifdef DEBUG_EVALUATION
			puts ("}; /* NO-iterate (1) */");
#endif
			return TRUE;
		} else if (iterating == NULL) {
			cell->base.flags |= CELL_BEING_ITERATED;
			iterating = cell;
#ifdef DEBUG_EVALUATION
			puts ("}; /* START iterate = TRUE (0) */");
#endif
			return FALSE;
		} else {
#ifdef DEBUG_EVALUATION
			puts ("}; /* other-iterate (0) */");
#endif
			return FALSE;
		}
198 199
	}

200
	/* Prepare to calculate */
201 202
	eval_pos_init_cell (&pos, cell);
	cell->base.flags |= DEPENDENT_BEING_CALCULATED;
203
	max_iteration = cell->base.sheet->workbook->iteration.max_number;
204

205
iterate :
206
	v = expr_eval (cell->base.expression, &pos, EVAL_STRICT);
207 208
	if (v == NULL)
		v = value_new_error (&pos, "Internal error");
209 210

#ifdef DEBUG_EVALUATION
211
	{
212 213 214
		char *valtxt = v
			? value_get_as_string (v)
			: g_strdup ("NULL");
215
		printf ("Evaluation(%d) %s := %s\n", max_iteration, cell_name (cell), valtxt);
216 217 218 219
		g_free (valtxt);
	}
#endif

220 221 222 223 224
	/* The top of a cycle */
	if (cell->base.flags & CELL_BEING_ITERATED) {
		cell->base.flags &= ~CELL_BEING_ITERATED;

		/* We just completed the last iteration, don't change things */
225
		if (iterating && max_iteration-- > 0) {
226
			/* If we are within bounds make this the last round */
227 228
			if (value_diff (cell->value, v) < cell->base.sheet->workbook->iteration.tolerance)
				max_iteration = 0;
229 230 231 232 233 234 235 236 237
			else {
#ifdef DEBUG_EVALUATION
				puts ("/* iterate == NULL */");
#endif
				iterating = NULL;
			}
			value_release (cell->value);
			cell->value = v;
			puts ("/* LOOP */");
238
#ifdef DEBUG_EVALUATION
239 240 241 242 243
#endif
			goto iterate;
		}
		g_return_val_if_fail (iterating, TRUE);
		iterating = NULL;
244 245 246 247 248
	} else {
		/* do not use cell_assign_value unless you pass in the format */
		if (cell->value != NULL)
			value_release (cell->value);
		cell->value = v;
249

250 251 252
		/* Optimization : Since we don't span calculated cells
		 * it is ok, to wipe rendered values.  The drawing routine
		 * will handle it.
253
		 */
254 255 256 257
		if (cell->rendered_value != NULL) {
			rendered_value_destroy (cell->rendered_value);
			cell->rendered_value = NULL;
		}
258
	}
259 260 261

	if (iterating == cell)
		iterating = NULL;
262

263 264 265 266 267
#ifdef DEBUG_EVALUATION
	printf ("} (%d)\n", iterating == NULL);
#endif
	cell->base.flags &= ~DEPENDENT_BEING_CALCULATED;
	return iterating == NULL;
268 269
}

270 271
/*
 * cell_relocate:
Jody Goldberg's avatar
Jody Goldberg committed
272 273
 * @cell   : The cell that is changing position
 * @rwinfo : An OPTIONAL pointer to allow for bounds checking and relocation
274 275 276 277 278 279
 *
 * 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
280
cell_relocate (Cell *cell, ExprRewriteInfo const *rwinfo)
281
{
282
	g_return_if_fail (cell != NULL);
283

284 285
	/* 1. Tag the cell as dirty */
	cell_dirty (cell);
286

287 288
	/* 2. If the cell contains a formula, relocate the formula */
	if (cell_has_expr (cell)) {
289
		ExprTree *expr = cell->base.expression;
Jody Goldberg's avatar
Jody Goldberg committed
290

291
		if (cell_expr_is_linked (cell))
292
			dependent_unlink (CELL_TO_DEP (cell), &cell->pos);
293

Jody Goldberg's avatar
Jody Goldberg committed
294 295 296
		/* bounds check, and adjust local references from the cell */
		if (rwinfo != NULL) {
			expr = expr_rewrite (expr, rwinfo);
297

298
			if (expr != NULL) {
299
				/* expression was unlinked above */
300 301
				expr_tree_unref (cell->base.expression);
				cell->base.expression = expr;
302 303
			}
		}
304

305
		/* Relink the expression.  */
306
		dependent_link (CELL_TO_DEP (cell), &cell->pos);
307 308 309
	}
}

310 311 312
/****************************************************************************/

/*
313 314
 * cell_set_text : Parses the supplied text for storage as a value or
 * 		expression.  It marks the sheet as dirty.
315 316 317
 *
 * If the text is an expression it IS queued for recalc.
 *        the format prefered by the expression is stored for later use.
318
 * If the text is a value it is rendered and spans are NOT calculated.
319 320 321 322 323 324 325
 *        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.
 */
326
void
327
cell_set_text (Cell *cell, char const *text)
328
{
329 330 331
	ExprTree    *expr;
	Value	    *val;
	ParsePos     pos;
332

333
	g_return_if_fail (cell != NULL);
334 335
	g_return_if_fail (text != NULL);
	g_return_if_fail (!cell_is_partial_array (cell));
336

337
	parse_text_value_or_expr (parse_pos_init_cell (&pos, cell),
338
		text, &val, &expr, mstyle_get_format (cell_get_mstyle (cell)));
339

340 341 342
	if (val != NULL) {	/* String was a value */
		cell_cleanout (cell);
		cell->value = val;
343
		cell_render_value (cell, TRUE);
344
	} else {		/* String was an expression */
345
		cell_set_expr (cell, expr);
346
		expr_tree_unref (expr);
347 348 349
	}
}

Michael Meeks's avatar
Michael Meeks committed
350
/*
351 352 353 354
 * 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
355
 *
356
 * The value is rendered but spans are not calculated.
Michael Meeks's avatar
Michael Meeks committed
357
 *
358 359 360 361 362
 * 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
363 364
 */
void
365
cell_assign_value (Cell *cell, Value *v)
Michael Meeks's avatar
Michael Meeks committed
366 367 368 369
{
	g_return_if_fail (cell);
	g_return_if_fail (v);

370 371
	if (cell->value != NULL)
		value_release (cell->value);
Michael Meeks's avatar
Michael Meeks committed
372
	cell->value = v;
373
	cell_render_value (cell, TRUE);
Michael Meeks's avatar
Michael Meeks committed
374 375 376
}

/*
377 378 379 380 381
 * 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
382
 *
383 384 385 386
 * 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.
Michael Meeks's avatar
Michael Meeks committed
387 388
 */
void
389
cell_set_value (Cell *cell, Value *v)
Michael Meeks's avatar
Michael Meeks committed
390
{
391 392
	g_return_if_fail (cell != NULL);
	g_return_if_fail (v != NULL);
393
	g_return_if_fail (!cell_is_partial_array (cell));
394

395 396
	cell_cleanout (cell);
	cell->value = v;
Michael Meeks's avatar
Michael Meeks committed
397 398
}

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

423
	cell->base.expression = expr;
424
	cell->base.flags |= CELL_HAS_EXPRESSION;
425
	cell->value = v;
426 427
	if (link_expr)
		dependent_link (CELL_TO_DEP (cell), &cell->pos);
428
}
429

430 431
/**
 * cell_set_expr_internal:
432
 * @cell: the cell to set the formula to
433 434 435 436 437 438 439
 * @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
440
 * 	- link the expression into the master list.
441
 */
Jody Goldberg's avatar
Jody Goldberg committed
442
static void
443
cell_set_expr_internal (Cell *cell, ExprTree *expr)
444
{
445
	expr_tree_ref (expr);
446

447
	cell_cleanout (cell);
448

449
	cell->base.expression = expr;
450
	cell->base.flags |= CELL_HAS_EXPRESSION;
451

452
	/* Until the value is recomputed, we put in this value.  */
453
	cell->value = value_new_empty ();
454 455 456
}

/*
Jody Goldberg's avatar
Jody Goldberg committed
457 458 459
 * 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.
460
 *
461
 * The cell is NOT marked for recalc.
462 463 464
 *
 * 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
465 466
 *           It also DOES NOT CHECK FOR ARRAY DIVISION.  Be very careful
 *           using this.
467 468
 */
void
469
cell_set_expr_unsafe (Cell *cell, ExprTree *expr)
470 471
{
	g_return_if_fail (cell != NULL);
472
	g_return_if_fail (expr != NULL);
473

474
	cell_set_expr_internal (cell, expr);
475
	dependent_link (CELL_TO_DEP (cell), &cell->pos);
476 477
}

Jody Goldberg's avatar
Jody Goldberg committed
478 479 480 481 482
/**
 * cell_set_expr : A utility wrapper for cell_set_expr_unsafe.  That adds
 *      checks for array subdivision.
 */
void
483
cell_set_expr (Cell *cell, ExprTree *expr)
Jody Goldberg's avatar
Jody Goldberg committed
484 485
{
	g_return_if_fail (!cell_is_partial_array (cell));
486 487
	g_return_if_fail (cell != NULL);
	g_return_if_fail (expr != NULL);
Jody Goldberg's avatar
Jody Goldberg committed
488

489 490
	cell_set_expr_internal (cell, expr);
	dependent_link (CELL_TO_DEP (cell), &cell->pos);
Jody Goldberg's avatar
Jody Goldberg committed
491 492
}

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

	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
532 533
	g_return_if_fail (col_a <= col_b);
	g_return_if_fail (row_a <= row_b);
534

535
	wrapper = expr_tree_new_array (0, 0, num_cols, num_rows);
536 537
	wrapper->array.corner.value = NULL;
	wrapper->array.corner.expr = formula;
538
	cell_set_expr_internal (corner, wrapper);
539
	expr_tree_unref (wrapper);
540 541

	for (x = 0; x < num_cols; ++x)
542
		for (y = 0; y < num_rows; ++y) {
543 544
			Cell *cell;

545 546
			if (x == 0 && y == 0)
				continue;
547

Michael Meeks's avatar
Michael Meeks committed
548
			cell = sheet_cell_fetch (sheet, col_a + x, row_a + y);
549
			wrapper = expr_tree_new_array (x, y, num_cols, num_rows);
550
			cell_set_expr_internal (cell, wrapper);
551
			dependent_link (CELL_TO_DEP (cell), &cell->pos);
552
			expr_tree_unref (wrapper);
553 554
		}

555
	dependent_link (CELL_TO_DEP (corner), &corner->pos);
556 557
}

558
/***************************************************************************/
Arturo Espinosa's avatar
Arturo Espinosa committed
559

560
gboolean
561
cell_is_blank (Cell const * cell)
Arturo Espinosa's avatar
Arturo Espinosa committed
562
{
563 564
	return (cell == NULL || cell->value == NULL ||
		cell->value->type == VALUE_EMPTY);
Arturo Espinosa's avatar
Arturo Espinosa committed
565
}
566

567
Value *
568
cell_is_error (Cell const * cell)
569
{
570 571
	g_return_val_if_fail (cell != NULL, NULL);
	g_return_val_if_fail (cell->value != NULL, NULL);
572

573 574 575
	if (cell->value->type == VALUE_ERROR)
		return cell->value;
	return NULL;
576 577
}

578
gboolean
579
cell_is_number (Cell const *cell)
580
{
581 582
	/* FIXME : This does not handle arrays or ranges */
	return (cell->value && VALUE_IS_NUMBER (cell->value));
583
}
584

585
gboolean
586
cell_is_zero (Cell const *cell)
587 588 589 590 591
{
	Value const * const v = cell->value;
	if (v == NULL)
		return FALSE;
	switch (v->type) {
592 593
	case VALUE_BOOLEAN : return !v->v_bool.val;
	case VALUE_INTEGER : return v->v_int.val == 0;
594 595
	case VALUE_FLOAT :
	{
596
		double const res = v->v_float.val;
597 598 599 600 601 602 603
		return (-1e-10 < res && res < 1e-10);
	}

	default :
		return FALSE;
	}
}
604

605
ExprArray const *
606
cell_is_array (Cell const *cell)
607
{
608
	if (cell != NULL && cell_has_expr (cell) &&
609 610
	    cell->base.expression->any.oper == OPER_ARRAY)
		return &cell->base.expression->array;
611
	return NULL;
612 613
}

614
gboolean
615
cell_is_partial_array (Cell const *cell)
616
{
617
	ExprArray const *ref = cell_is_array (cell);
618
	return ref != NULL && (ref->cols > 1 || ref->rows > 1);
619 620
}

621
/***************************************************************************/
622

623 624
/**
 * cell_render_value :
625
 * @cell: The cell whose value needs to be rendered
626
 * @dynamic_width : Allow format to depend on column width.
627
 *
628
 * TODO :
Morten Welinder's avatar
Morten Welinder committed
629
 * The reason the rendered values are stored separately from the Cell is
630 631 632
 * that in the future only visible cells will be rendered.  The render
 * will be SheetControl specific to allow for multiple zooms and different
 * display resolutions.
633 634
 */
void
635
cell_render_value (Cell *cell, gboolean dynamic_width)
636
{
637
	RenderedValue *rv;
638
	MStyle *mstyle;
639

640 641
	g_return_if_fail (cell != NULL);

642 643 644
	mstyle = cell_get_mstyle (cell);

	rv = rendered_value_new (cell, mstyle, dynamic_width);
645 646 647
	if (cell->rendered_value)
		rendered_value_destroy (cell->rendered_value);
	cell->rendered_value = rv;
648 649

	rendered_value_calc_size_ext (cell, mstyle);
650 651
}

652
MStyle *
653
cell_get_mstyle (Cell const *cell)
654
{
655 656 657 658
	g_return_val_if_fail (cell != NULL, NULL);
	return sheet_style_get (cell->base.sheet,
				cell->pos.col,
				cell->pos.row);
659 660
}

661 662 663 664 665 666 667
/**
 * cell_get_format :
 * @cell :
 *
 * Get the display format.  If the assigned format is General,
 * the format of the value will be used.
 */
668
StyleFormat *
669
cell_get_format (Cell const *cell)
Morten Welinder's avatar
Morten Welinder committed
670
{
Jody Goldberg's avatar
Jody Goldberg committed
671
	StyleFormat *fmt;
672

673
	g_return_val_if_fail (cell != NULL, style_format_general ());
Jody Goldberg's avatar
Jody Goldberg committed
674

675
	fmt = mstyle_get_format (cell_get_mstyle (cell));
Morten Welinder's avatar
Morten Welinder committed
676

677
	g_return_val_if_fail (fmt != NULL, style_format_general ());
678

679 680 681
	if (style_format_is_general (fmt) &&
	    cell->value != NULL && VALUE_FMT (cell->value))
		fmt = VALUE_FMT (cell->value);
Morten Welinder's avatar
Morten Welinder committed
682

683
	return fmt;
Morten Welinder's avatar
Morten Welinder committed
684
}
685 686 687 688 689 690

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

	g_return_if_fail (mstyle != NULL);

	cell_dirty (cell);
703 704 705 706
	mstyle_set_format_text (mstyle, format);

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

Jody Goldberg's avatar
Jody Goldberg committed
709
/**
710
 * cell_convert_expr_to_value : drops the expression keeps its value.  Then uses the formatted
Jody Goldberg's avatar
Jody Goldberg committed
711 712
 *      result as if that had been entered.
 *
Morten Welinder's avatar
Morten Welinder committed
713
 * NOTE : the cell's expression cannot be linked into the expression * list.
Jody Goldberg's avatar
Jody Goldberg committed
714 715 716 717 718 719 720 721
 *
 * 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.
722 723
 */
void
724
cell_convert_expr_to_value (Cell *cell)
725 726 727 728
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (cell_has_expr(cell));

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

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

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

740 741
	cell_dirty (cell);
}
742

743 744 745 746 747 748 749 750 751 752 753 754
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);
}

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

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

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


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