cell.c 33.2 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 <gnome.h>
Miguel de Icaza's avatar
Miguel de Icaza committed
9
#include <locale.h>
Arturo Espinosa's avatar
Arturo Espinosa committed
10
#include "gnumeric.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
11
#include "gnumeric-sheet.h"
12
#include "gnumeric-util.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
13
#include "eval.h"
14
#include "format.h"
15
#include "color.h"
16
#include "cursors.h"
17
#include "utils.h"
18
#include "gnumeric-util.h"
19
#include <ctype.h>
Arturo Espinosa's avatar
Arturo Espinosa committed
20

21 22
static int         redraws_frozen           = 0;
static int         redraws_deep_frozen      = 0;
23 24
static GHashTable *cell_hash_queue;

25
static void
26 27 28
cell_formula_changed (Cell *cell)
{
	g_return_if_fail (cell != NULL);
29

30
	sheet_cell_formula_link (cell);
31

32 33 34
	cell_queue_recalc (cell);
}

35 36 37
static inline void
cell_modified (Cell *cell)
{
38
	Sheet *sheet = cell->sheet;
39 40 41 42

	/* Cells from the clipboard do not have a sheet attached */
	if (sheet)
		sheet->modified = TRUE;
43 44
}

Morten Welinder's avatar
Morten Welinder committed
45

46 47 48 49 50
/* Empty a cell's value, entered_text, and parsed_node.  */
static void
cell_cleanout (Cell *cell)
{
	if (cell->parsed_node){
51 52 53
		/* Clipboard cells, e.g., are not attached to a sheet.  */
		if (cell->sheet)
			sheet_cell_formula_unlink (cell);
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
		expr_tree_unref (cell->parsed_node);
		cell->parsed_node = NULL;
	}

	if (cell->value) {
		value_release (cell->value);
		cell->value = NULL;
	}

	if (cell->entered_text) {
		string_unref (cell->entered_text);
		cell->entered_text = NULL;
	}
}


Arturo Espinosa's avatar
Arturo Espinosa committed
70
void
71
cell_set_formula (Cell *cell, const char *text)
Arturo Espinosa's avatar
Arturo Espinosa committed
72
{
73
	ExprTree *new_expr;
74
	char *error_msg = _("ERROR");
75
	const char *desired_format = NULL;
76
	ParsePosition pp;
77

Arturo Espinosa's avatar
Arturo Espinosa committed
78 79
	g_return_if_fail (cell != NULL);
	g_return_if_fail (text != NULL);
80

81
	cell_modified (cell);
82
	new_expr = expr_parse_string (&text [1],
83
				      parse_pos_cell (&pp, cell),
84 85
				      &desired_format,
				      &error_msg);
86 87
	cell_cleanout (cell);

88
	if (new_expr == NULL){
89
		cell_set_rendered_text (cell, error_msg);
90 91 92
		cell->entered_text = string_get (text);
		/* FIXME: Supply a proper position?  */
		cell->value = value_new_error (NULL, error_msg);
Arturo Espinosa's avatar
Arturo Espinosa committed
93
		return;
94 95
	}

96 97
	if (desired_format &&
	    strcmp (cell->style->format->format, "General") == 0){
Miguel de Icaza's avatar
New:  
Miguel de Icaza committed
98 99 100 101
		style_format_unref (cell->style->format);
		cell->style->format = style_format_new (desired_format);
	}

102 103
	if (new_expr->oper == OPER_ARRAY){
		/* The corner sets up the entire array block */
104
		if (new_expr->u.array.x != 0 || new_expr->u.array.y != 0) {
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
			expr_tree_unref (new_expr);
			return;
		}

		/* 
		 * NOTE : The wrapper supplied by the parser will be released
		 *        and recreated.  new_expr will NOT be valid on exit
		 *        from cell_set_array_formula.
		 */
		cell->parsed_node = new_expr;
		cell_set_array_formula (cell->sheet,
					cell->row->pos, cell->col->pos,
					cell->row->pos +
					    new_expr->u.array.rows -1,
					cell->col->pos +
					    new_expr->u.array.cols -1,
					new_expr->u.array.corner.func.expr);
	} else {
		cell->parsed_node = new_expr;
124 125
		/* Until the value is recomputed, we put in this value.  */
		cell->value = value_new_error (NULL, _("Circular reference"));
126 127
		cell_formula_changed (cell);
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
128
}
Arturo Espinosa's avatar
Arturo Espinosa committed
129

Miguel de Icaza's avatar
Miguel de Icaza committed
130 131 132 133 134 135 136 137 138 139 140
/*
 * cell_set_alignment:
 *
 * @cell: the cell to change the alignment of
 * @halign: the horizontal alignemnt
 * @valign: the vertical alignemnt
 * @orient: the text orientation
 *
 * This routine changes the alignment of a cell to those specified.
 */
void
Arturo Espinosa's avatar
Arturo Espinosa committed
141
cell_set_alignment (Cell *cell, int halign, int valign, int orient, int auto_return)
Miguel de Icaza's avatar
Miguel de Icaza committed
142 143 144 145
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (cell->style != NULL);

146 147 148
	if ((cell->style->halign      == halign) &&
	    (cell->style->valign      == valign) &&
	    (cell->style->fit_in_cell == auto_return) &&
Miguel de Icaza's avatar
Miguel de Icaza committed
149 150 151
	    (cell->style->orientation == orient))
		return;

152 153
	cell_modified (cell);

Arturo Espinosa's avatar
Arturo Espinosa committed
154
	cell_queue_redraw (cell);
155

Miguel de Icaza's avatar
Miguel de Icaza committed
156 157 158
	cell->style->halign = halign;
	cell->style->valign = valign;
	cell->style->orientation = orient;
Arturo Espinosa's avatar
Arturo Espinosa committed
159
	cell->style->fit_in_cell = auto_return;
160

Arturo Espinosa's avatar
Arturo Espinosa committed
161
	cell_calc_dimensions (cell);
162

Miguel de Icaza's avatar
Miguel de Icaza committed
163 164 165
	cell_queue_redraw (cell);
}

Arturo Espinosa's avatar
Arturo Espinosa committed
166 167 168 169 170
void
cell_set_halign (Cell *cell, StyleHAlignFlags halign)
{
	g_return_if_fail (cell != NULL);

171
	if (((unsigned int)cell->style->halign) == ((unsigned int) halign))
Arturo Espinosa's avatar
Arturo Espinosa committed
172 173
		return;

174 175
	cell_modified (cell);

Arturo Espinosa's avatar
Arturo Espinosa committed
176 177 178 179 180 181 182
	cell_queue_redraw (cell);
	cell->style->halign = halign;

	cell_calc_dimensions (cell);
	cell_queue_redraw (cell);
}

183 184 185 186 187 188
void
cell_set_font_from_style (Cell *cell, StyleFont *style_font)
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (style_font != NULL);

189 190
	cell_modified (cell);

Arturo Espinosa's avatar
Arturo Espinosa committed
191
	cell_queue_redraw (cell);
192

193
	style_font_ref (style_font);
194
	style_font_unref (cell->style->font);
195

196
	cell->style->font = style_font;
197
	cell->style->valid_flags |= STYLE_FONT;
198

Arturo Espinosa's avatar
Arturo Espinosa committed
199
	cell_calc_dimensions (cell);
200

201 202 203
	cell_queue_redraw (cell);
}

204 205 206 207 208 209
void
cell_set_style (Cell *cell, Style *reference_style)
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (reference_style != NULL);

210 211
	cell_modified (cell);

212
	cell_queue_redraw (cell);
Miguel de Icaza's avatar
New:  
Miguel de Icaza committed
213
	style_destroy (cell->style);
214
	cell->style = style_duplicate (reference_style);
215 216
	if (cell->value)
		cell_render_value (cell);
217 218 219 220
	cell_calc_dimensions (cell);
	cell_queue_redraw (cell);
}

221 222 223 224 225
void
cell_comment_destroy (Cell *cell)
{
	CellComment *comment;
	GList *l;
226

227 228 229 230 231 232 233 234 235
	g_return_if_fail (cell != NULL);

	comment = cell->comment;
	if (!comment)
		return;
	cell->comment = NULL;

	/* Free resources */
	string_unref (comment->comment);
236 237 238 239 240

	if (comment->timer_tag != -1)
		gtk_timeout_remove (comment->timer_tag);

	if (comment->window)
241
		gtk_object_destroy (GTK_OBJECT (comment->window));
242

243
	for (l = comment->realized_list; l; l = l->next)
244
		gtk_object_destroy (l->data);
Morten Welinder's avatar
Morten Welinder committed
245
	g_list_free (comment->realized_list);
246

247 248 249
	g_free (comment);
}

250 251 252 253 254 255 256
static void
cell_comment_cancel_timer (Cell *cell)
{
	if (cell->comment->timer_tag != -1){
		gtk_timeout_remove (cell->comment->timer_tag);
		cell->comment->timer_tag = -1;
	}
257

258
}
259

260 261 262 263 264
static void
cell_display_comment (Cell *cell)
{
	GtkWidget *window, *label;
	int x, y;
265

266 267
	g_return_if_fail (cell != NULL);

268
	cell_comment_cancel_timer (cell);
269

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
	window = gtk_window_new (GTK_WINDOW_POPUP);
	label = gtk_label_new (cell->comment->comment->str);
	gtk_container_add (GTK_CONTAINER (window), label);

	gdk_window_get_pointer (NULL, &x, &y, NULL);
	gtk_widget_set_uposition (window, x+10, y+10);

	gtk_widget_show_all (window);

	cell->comment->window = window;
}

static gint
cell_popup_comment (gpointer data)
{
	Cell *cell = data;
286

287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	cell->comment->timer_tag = -1;

	cell_display_comment (cell);
	return FALSE;
}

static int
cell_comment_clicked (GnomeCanvasItem *item, GdkEvent *event, Cell *cell)
{
	GnomeCanvas *canvas = item->canvas;

	switch (event->type){
	case GDK_BUTTON_RELEASE:
		if (event->button.button != 1)
			return FALSE;
		if (cell->comment->window)
			return FALSE;
		cell_display_comment (cell);
		break;

	case GDK_BUTTON_PRESS:
		if (event->button.button != 1)
			return FALSE;
		break;
311

312 313 314 315 316 317
	case GDK_ENTER_NOTIFY:
		cell->comment->timer_tag = gtk_timeout_add (1000, cell_popup_comment, cell);
		cursor_set_widget (canvas, GNUMERIC_CURSOR_ARROW);
		break;

	case GDK_LEAVE_NOTIFY:
318
		cell_comment_cancel_timer (cell);
319
		if (cell->comment->window){
320
			gtk_object_destroy (GTK_OBJECT (cell->comment->window));
321 322 323
			cell->comment->window = NULL;
		}
		break;
324

325 326 327 328 329 330
	default:
		return FALSE;
	}
	return TRUE;
}

331 332 333 334 335 336 337 338
static void
cell_comment_realize (Cell *cell)
{
	GList *l;

	g_return_if_fail (cell->comment != NULL);

	sheet_cell_comment_link (cell);
339
	for (l = cell->sheet->sheet_views; l; l = l->next){
340 341
		SheetView *sheet_view = SHEET_VIEW (l->data);
		GnomeCanvasItem *o;
342

343
		o = sheet_view_comment_create_marker (
344
			sheet_view,
345
			cell->col->pos, cell->row->pos);
346
		gtk_object_ref (GTK_OBJECT (o));
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366

		cell->comment->realized_list = g_list_prepend (
			cell->comment->realized_list, o);

		gtk_signal_connect (GTK_OBJECT (o), "event",
				    GTK_SIGNAL_FUNC (cell_comment_clicked), cell);
	}
}

static void
cell_comment_unrealize (Cell *cell)
{
	GList *l;

	g_return_if_fail (cell->comment != NULL);

	sheet_cell_comment_unlink (cell);
	for (l = cell->comment->realized_list; l; l = l->next){
		GnomeCanvasItem *o = l->data;

367
		gtk_object_unref (GTK_OBJECT (o));
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
	}
	g_list_free (cell->comment->realized_list);
	cell->comment->realized_list = NULL;
}

void
cell_realize (Cell *cell)
{
	g_return_if_fail (cell != NULL);

	if (cell->comment)
		cell_comment_realize (cell);
}

void
cell_unrealize (Cell *cell)
{
	g_return_if_fail (cell != NULL);

	if (cell->comment)
		cell_comment_unrealize (cell);
}

391
void
392
cell_set_comment (Cell *cell, const char *str)
393 394
{
	int had_comments = FALSE;
395

396 397 398 399 400 401 402 403 404 405 406
	g_return_if_fail (cell != NULL);
	g_return_if_fail (str != NULL);

	cell_modified (cell);

	cell_comment_destroy (cell);

	cell->comment = g_new (CellComment, 1);
	cell->comment->realized_list = NULL;
	cell->comment->timer_tag = -1;
	cell->comment->window = NULL;
407

408 409 410 411 412
	cell->comment->comment = string_get (str);

	if (had_comments)
		cell_queue_redraw (cell);

413 414
	if (cell->sheet)
		cell_comment_realize (cell);
415 416
}

417 418 419 420
void
cell_set_foreground (Cell *cell, gushort red, gushort green, gushort blue)
{
	g_return_if_fail (cell != NULL);
421 422

	cell_modified (cell);
423

424 425 426 427 428 429 430 431 432
	if (cell->style->valid_flags & STYLE_FORE_COLOR)
		style_color_unref (cell->style->fore_color);

	cell->style->valid_flags |= STYLE_FORE_COLOR;
	cell->style->fore_color = style_color_new (red, green, blue);

	cell_queue_redraw (cell);
}

433 434 435 436
void
cell_set_background (Cell *cell, gushort red, gushort green, gushort blue)
{
	g_return_if_fail (cell != NULL);
437

438 439
	cell_modified (cell);

440 441 442 443 444 445 446 447 448
	if (cell->style->valid_flags & STYLE_BACK_COLOR)
		style_color_unref (cell->style->back_color);

	cell->style->valid_flags |= STYLE_BACK_COLOR;
	cell->style->back_color = style_color_new (red, green, blue);

	cell_queue_redraw (cell);
}

449 450 451 452 453 454 455 456
/**
 * Null pointers unset the style.
 **/
void
cell_set_color_from_style (Cell *cell, StyleColor *foreground,
			   StyleColor *background)
{
	g_return_if_fail (cell != NULL);
457

458 459
	cell_modified (cell);

460
	if (cell->style->valid_flags & STYLE_FORE_COLOR) {
Arturo Espinosa's avatar
Arturo Espinosa committed
461
		cell->style->valid_flags ^= STYLE_FORE_COLOR;
462 463 464
		style_color_unref (cell->style->fore_color);
	}

465
	if (cell->style->valid_flags & STYLE_BACK_COLOR) {
Arturo Espinosa's avatar
Arturo Espinosa committed
466
		cell->style->valid_flags ^= STYLE_BACK_COLOR;
467 468 469
		style_color_unref (cell->style->back_color);
	}

470
	if (background) {
471
		cell->style->valid_flags |= STYLE_BACK_COLOR;
Arturo Espinosa's avatar
Arturo Espinosa committed
472
		style_color_ref (background);
473
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
474
	cell->style->back_color = background;
475

476
	if (foreground) {
477
		cell->style->valid_flags |= STYLE_FORE_COLOR;
Arturo Espinosa's avatar
Arturo Espinosa committed
478
		style_color_ref (foreground);
479
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
480
	cell->style->fore_color = foreground;
481 482 483 484

	cell_queue_redraw (cell);
}

485 486 487 488 489 490

void
cell_set_pattern (Cell *cell, int pattern)
{
	g_return_if_fail (cell != NULL);

491 492
	cell_modified (cell);

493 494 495 496 497 498
	cell->style->valid_flags |= STYLE_PATTERN;
	cell->style->pattern = pattern;

	cell_queue_redraw (cell);
}

499 500 501 502
/**
 * cell_set_border:
 * @cell: the cell
 * @border_type: an array containing the borders for the cell
503
 * @border_color: an array of StyleColors with the
504 505 506
 * NB. don't unref the StyleColor *s you pass.
 */
void
507
cell_set_border (Cell *cell,
508
		 StyleBorderType  const border_type[4],
509
		 StyleColor      *border_color[4])
510 511 512 513
{
	g_return_if_fail (cell != NULL);

	cell_modified (cell);
514

515
  	if (cell->style->valid_flags & STYLE_BORDER)
516
		style_border_unref (cell->style->border);
517 518

	cell->style->valid_flags |= STYLE_BORDER;
519
	cell->style->border = style_border_new (border_type, border_color);
520 521 522 523

	cell_queue_redraw (cell);
}

Miguel de Icaza's avatar
Miguel de Icaza committed
524 525 526 527 528 529 530 531
/*
 * cell_set_rendered_text
 * @cell:          the cell we will modify
 * @rendered_text: the text we will display
 *
 * This routine sets the rendered text field of the cell
 * it recomputes the bounding box for the cell as well
 */
Miguel de Icaza's avatar
Miguel de Icaza committed
532
void
533
cell_set_rendered_text (Cell *cell, const char *rendered_text)
Miguel de Icaza's avatar
Miguel de Icaza committed
534
{
535
	String *oldtext;
536

Miguel de Icaza's avatar
Miguel de Icaza committed
537 538
	g_return_if_fail (cell != NULL);
	g_return_if_fail (rendered_text != NULL);
539

540
	cell_modified (cell);
Miguel de Icaza's avatar
Miguel de Icaza committed
541

542
	oldtext = cell->text;
Miguel de Icaza's avatar
Miguel de Icaza committed
543
	cell->text = string_get (rendered_text);
544 545
	if (oldtext)
		string_unref (oldtext);
546

Miguel de Icaza's avatar
Miguel de Icaza committed
547 548 549
	cell_calc_dimensions (cell);
}

Miguel de Icaza's avatar
Miguel de Icaza committed
550 551 552 553 554 555
/*
 * cell_render_value
 * @cell: The cell whose value needs to be rendered
 *
 * The value of the cell is formated according to the format style
 */
Miguel de Icaza's avatar
Miguel de Icaza committed
556 557 558
void
cell_render_value (Cell *cell)
{
559
	StyleColor *color;
Miguel de Icaza's avatar
Miguel de Icaza committed
560
	char *str;
561

Miguel de Icaza's avatar
Miguel de Icaza committed
562 563 564
	g_return_if_fail (cell != NULL);
	g_return_if_fail (cell->value != NULL);

565 566 567 568
	if (cell->render_color){
		style_color_unref (cell->render_color);
		cell->render_color = NULL;
	}
569

570 571
	str = format_value (cell->style->format, cell->value, &color);
	cell->render_color = color;
572

Miguel de Icaza's avatar
Miguel de Icaza committed
573 574 575 576
	cell_set_rendered_text (cell, str);
	g_free (str);
}

Michael Meeks's avatar
Michael Meeks committed
577 578 579 580 581 582 583 584 585 586 587 588 589 590
/*
 * Sets the value for a cell:
 *
 * This is kind of an internal function and should be only called by
 * routines that know what they are doing.  These are the important
 * differences from cell_set_value:
 *
 *    - It does not queue redraws (so you have to queue the redraw yourself
 *      or queue a full redraw).
 *
 *    - It does not queue any recomputations.  You have to queue the recompute
 *      yourself.
 */
void
Morten Welinder's avatar
Morten Welinder committed
591
cell_set_value_simple (Cell *cell, Value *v)
Michael Meeks's avatar
Michael Meeks committed
592 593 594 595 596
{
	g_return_if_fail (cell);
	g_return_if_fail (v);

	cell_modified (cell);
597
	cell_cleanout (cell);
Michael Meeks's avatar
Michael Meeks committed
598 599 600 601 602 603 604 605 606 607 608

	cell->value = v;
	cell_render_value (cell);
}

/*
 * cell_set_value
 *
 * Changes the value of a cell
 */
void
Morten Welinder's avatar
Morten Welinder committed
609
cell_set_value (Cell *cell, Value *v)
Michael Meeks's avatar
Michael Meeks committed
610 611 612
{
	g_return_if_fail (cell);
	g_return_if_fail (v);
613

Michael Meeks's avatar
Michael Meeks committed
614 615 616 617 618 619 620 621
	cell_queue_redraw (cell);

	cell_set_value_simple (cell, v);
	cell_content_changed (cell);

	cell_queue_redraw (cell);
}

622 623 624 625 626 627 628 629 630 631 632 633 634
/*
 * Sets the text for a cell:
 *
 * This is kind of an internal function and should be only called by
 * routines that know what they are doing.  These are the important
 * differences from cell_set_text:
 *
 *    - It does not queue redraws (so you have to queue the redraw yourself
 *      or queue a full redraw).
 *
 *    - It does not queue any recomputations.  You have to queue the recompute
 *      yourself.
 */
635
void
636
cell_set_text_simple (Cell *cell, const char *text)
637
{
Arturo Espinosa's avatar
Arturo Espinosa committed
638 639
	g_return_if_fail (cell != NULL);
	g_return_if_fail (text != NULL);
Arturo Espinosa's avatar
Arturo Espinosa committed
640

641
	cell_modified (cell);
642
	cell_cleanout (cell);
643

644
 	if (text [0] == '=' && text [1] != 0){
645
		cell_set_formula (cell, text);
Arturo Espinosa's avatar
Arturo Espinosa committed
646
	} else {
647 648
		char *end;
		long l;
649
		int  set=0;
650

651
		l = strtol (text, &end, 10);
652 653
		if (l != LONG_MAX && l != LONG_MIN &&
		    text != end && (l == (int)l)) {
654 655 656
			/* Allow and ignore spaces at the end of integers.  */
			while (*end == ' ')
				end++;
657 658 659 660 661 662 663
			if (*end == 0) {
				cell->value = value_new_int (l);
				set = 1;
			}
		}
		
		if (!set) {
664
			double d;
665
			d = strtod (text, &end);
666
			if (text != end && *end == 0) {
667 668
				/* It is a floating point number.  */
				cell->value = value_new_float ((float_t)d);
Arturo Espinosa's avatar
Arturo Espinosa committed
669
			} else {
670 671
				/* It is text.  */
				cell->value = value_new_string (text);
Arturo Espinosa's avatar
Arturo Espinosa committed
672 673
			}
		}
674

Miguel de Icaza's avatar
Miguel de Icaza committed
675
		cell_render_value (cell);
676
	}
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
}

/*
 * cell_content_changed:
 *
 * Call this routine if you modify the contents of a cell
 * to trigger a recompute on any dependencies
 */
void
cell_content_changed (Cell *cell)
{
	GList   *deps;

	g_return_if_fail (cell != NULL);

Arturo Espinosa's avatar
Arturo Espinosa committed
692
	/* Queue all of the dependencies for this cell */
693
	deps = cell_get_dependencies (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
694
	if (deps)
695
		cell_queue_recalc_list (deps, TRUE);
696 697
}

698

699 700 701 702 703 704
/*
 * cell_set_text
 *
 * Changes the content of a cell
 */
void
705
cell_set_text (Cell *cell, const char *text)
706 707 708
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (text != NULL);
709

710
	if (cell->parsed_node != NULL && cell->parsed_node->oper == OPER_ARRAY) {
711 712 713 714
		gnumeric_no_modify_array_notice (cell->sheet->workbook);
		return;
	}

715 716 717
	cell_queue_redraw (cell);

	cell_set_text_simple (cell, text);
718
	cell_content_changed (cell);
719

720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
	cell_queue_redraw (cell);
}

/**
 * cell_set_formula_tree_simple:
 * @cell:    the cell to set the formula to
 * @formula: an expression tree with the formula
 *
 * This is an internal function.  It should be only called by routines that
 * know what they are doing.  These are the important differences from
 * cell_set_formula:
 *
 *   - It does not queue redraws (so you have to queue the redraw yourself
 *     or queue a full redraw).
 *
735
 *   - It does not queue any recomputations.  You have to queue the
736
 *     recompute yourself.
737 738 739 740 741 742 743
 */
void
cell_set_formula_tree_simple (Cell *cell, ExprTree *formula)
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (formula != NULL);

744
	/* Ref before unref.  Repeat after me.  */
Morten Welinder's avatar
Morten Welinder committed
745 746
	expr_tree_ref (formula);

747 748
	cell_modified (cell);
	cell_cleanout (cell);
749 750

	cell->parsed_node = formula;
751 752
	/* Until the value is recomputed, we put in this value.  */
	cell->value = value_new_error (NULL, _("Circular reference"));
753 754 755
	cell_formula_changed (cell);
}

756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
/**
 * 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
 *
 * Uses cell_set_formula_tree_simple to store the formula as an 
 * '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
 * out it at the head of the recalc queue.
 */
void
cell_set_array_formula (Sheet *sheet,
			int row_a, int col_a, int row_b, int col_b,
			ExprTree *formula)
{
	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);
	Cell * cell = NULL;
781
	ExprTree *wrapper;
782 783 784 785 786 787 788 789 790 791 792

	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);

	wrapper = expr_tree_array_formula (0, 0, num_rows, num_cols);
	wrapper->u.array.corner.func.value = NULL;
	wrapper->u.array.corner.func.expr = formula;
	expr_tree_ref (formula);
	cell_set_formula_tree_simple (corner, wrapper);
793
	expr_tree_unref (wrapper);
794 795 796 797 798

	/* The corner must be 1st on the recalc list, queue it later */
	cell_unqueue_from_recalc (corner);

	for (x = 0; x < num_cols; ++x)
799
		for (y = 0; y < num_rows; ++y) {
800 801 802 803 804 805 806
			if (x == 0 && y == 0)
				continue;
			cell = sheet_cell_fetch (sheet, col_a+x,row_a+y);
			wrapper = expr_tree_array_formula (x, y,
							   num_rows, num_cols);
			wrapper->u.array.corner.cell = corner;
			cell_set_formula_tree_simple (cell, wrapper);
807
			expr_tree_unref (wrapper);
808 809 810 811 812 813
		}

	/* Put the corner at the head of the recalc list */
	cell_queue_recalc (corner);
}

814 815 816 817 818 819 820 821
void
cell_set_formula_tree (Cell *cell, ExprTree *formula)
{
	g_return_if_fail (cell != NULL);

	cell_queue_redraw (cell);

	cell_set_formula_tree_simple (cell, formula);
822
	cell_content_changed (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
823 824

	cell_queue_redraw (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
825
}
Arturo Espinosa's avatar
Arturo Espinosa committed
826

827 828 829 830
/**
 * cell_copy:
 * @cell: existing cell to duplicate
 *
831
 * Makes a copy of a Cell.
832
 *
833
 * Returns a copy of the cell.
Arturo Espinosa's avatar
Arturo Espinosa committed
834 835
 */
Cell *
836
cell_copy (const Cell *cell)
Arturo Espinosa's avatar
Arturo Espinosa committed
837 838 839 840 841 842 843 844 845 846
{
	Cell *new_cell;

	g_return_val_if_fail (cell != NULL, NULL);

	new_cell = g_new (Cell, 1);

	/* bitmap copy first */
	*new_cell = *cell;

Morten Welinder's avatar
Morten Welinder committed
847
	new_cell->flags &= ~CELL_QUEUED_FOR_RECALC;
848

Morten Welinder's avatar
Morten Welinder committed
849
	/* now copy properly the rest */
850
	if (new_cell->parsed_node)
Morten Welinder's avatar
Morten Welinder committed
851 852 853 854
		expr_tree_ref (new_cell->parsed_node);

	if (new_cell->text)
		string_ref (new_cell->text);
855 856 857 858

	if (new_cell->entered_text)
		string_ref (new_cell->entered_text);

Morten Welinder's avatar
Morten Welinder committed
859 860 861 862 863
	if (new_cell->style)
		new_cell->style = style_duplicate (new_cell->style);

	if (new_cell->render_color)
		style_color_ref (new_cell->render_color);
864 865 866

	if (new_cell->value)
		new_cell->value = value_duplicate (new_cell->value);
Arturo Espinosa's avatar
Arturo Espinosa committed
867

Morten Welinder's avatar
Morten Welinder committed
868 869
	if (cell->comment) {
		new_cell->comment = NULL;
870
		cell_set_comment (new_cell, cell->comment->comment->str);
Morten Welinder's avatar
Morten Welinder committed
871
	}
872

Arturo Espinosa's avatar
Arturo Espinosa committed
873 874 875 876 877 878 879 880
	return new_cell;
}

void
cell_destroy (Cell *cell)
{
	g_return_if_fail (cell != NULL);

Morten Welinder's avatar
Morten Welinder committed
881 882 883 884 885 886
	if (cell_hash_queue && g_hash_table_lookup (cell_hash_queue, cell)) {
		g_warning ("FIXME: Deleting cell %s which was queued for redraw",
			   cell_name (cell->col->pos, cell->row->pos));
		g_hash_table_remove (cell_hash_queue, cell);
	}

887
	cell_modified (cell);
888
	cell_cleanout (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
889

890 891
	if (cell->render_color)
		style_color_unref (cell->render_color);
Morten Welinder's avatar
Morten Welinder committed
892
	cell->render_color = (void *)0xdeadbeef;
893

894
	cell_comment_destroy (cell);
895 896

	if (cell->text)
897
		string_unref (cell->text);
Morten Welinder's avatar
Morten Welinder committed
898 899
	cell->text = (void *)0xdeadbeef;

900
	style_destroy (cell->style);
Morten Welinder's avatar
Morten Welinder committed
901
	cell->style = (void *)0xdeadbeef;
902

903
	g_free (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
904
}
Miguel de Icaza's avatar
Miguel de Icaza committed
905

906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
void
cell_freeze_redraws (void)
{
	redraws_frozen++;
	if (redraws_frozen == 1)
		cell_hash_queue = g_hash_table_new (g_direct_hash, g_direct_equal);
}

static void
call_cell_queue_redraw (gpointer key, gpointer value, gpointer user_data)
{
	cell_queue_redraw (value);
}

void
cell_thaw_redraws (void)
{
	redraws_frozen--;
	if (redraws_frozen < 0){
		g_warning ("unbalanced freeze/thaw\n");
		return;
	}
	if (redraws_frozen == 0){
		g_hash_table_foreach (cell_hash_queue, call_cell_queue_redraw, NULL);
		g_hash_table_destroy (cell_hash_queue);
		cell_hash_queue = NULL;
	}
}
Michael Meeks's avatar
Michael Meeks committed
934 935 936 937 938 939 940 941 942 943 944 945 946
void
cell_deep_freeze_redraws (void)
{
	redraws_deep_frozen++;
}

void
cell_deep_thaw_redraws (void)
{
	redraws_deep_frozen--;
	if (redraws_frozen < 0)
		g_warning ("unbalanced deep freeze/thaw\n");
}
947 948 949 950 951 952 953 954 955

static void
queue_cell (Cell *cell)
{
	if (g_hash_table_lookup (cell_hash_queue, cell))
		return;
	g_hash_table_insert (cell_hash_queue, cell, cell);
}

Miguel de Icaza's avatar
Miguel de Icaza committed
956 957 958
void
cell_queue_redraw (Cell *cell)
{
Michael Meeks's avatar
Michael Meeks committed
959
	/* You wake up dead after a deep freeze */
960
	if (redraws_deep_frozen > 0)
Michael Meeks's avatar
Michael Meeks committed
961 962
		return;

963
	g_return_if_fail (cell != NULL);
964 965 966 967 968

	if (redraws_frozen){
		queue_cell (cell);
		return;
	}
Morten Welinder's avatar
Morten Welinder committed
969

Miguel de Icaza's avatar
Miguel de Icaza committed
970 971 972 973 974
	sheet_redraw_cell_region (cell->sheet,
				  cell->col->pos, cell->row->pos,
				  cell->col->pos, cell->row->pos);
}

975 976 977 978 979 980 981 982 983
/*
 * cell_set_format_simple:
 *
 * This routine is similar to cell_set_format, but it does not queue
 * any redraws, nor expects the cell to have a value.
 *
 * Make sure you queue a draw in the future for this cell.
 */
void
984
cell_set_format_simple (Cell *cell, const char *format)
985 986 987
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (format != NULL);
988

989 990 991 992
	if (strcmp (format, cell->style->format->format) == 0)
		return;

	/* Change the format */
993
	cell_modified (cell);
994 995
	style_format_unref (cell->style->format);
	cell->style->format = style_format_new (format);
996
	cell->flags |= CELL_FORMAT_SET;
997 998
}

999 1000 1001 1002 1003 1004
/*
 * cell_set_format:
 *
 * Changes the format for CELL to be FORMAT.  FORMAT should be
 * a number display format as specified on the manual
 */
Miguel de Icaza's avatar
Miguel de Icaza committed
1005
void
1006
cell_set_format (Cell *cell, const char *format)
Miguel de Icaza's avatar
Miguel de Icaza committed
1007
{
1008
	g_return_if_fail (cell != NULL);
1009

1010
	cell_set_format_simple (cell, format);
1011

1012 1013 1014
	/* re-render the cell text */
	cell_render_value (cell);
	cell_queue_redraw (cell);
1015 1016 1017 1018 1019
}

void
cell_set_format_from_style (Cell *cell, StyleFormat *style_format)
{
Arturo Espinosa's avatar
Arturo Espinosa committed
1020 1021 1022
	g_return_if_fail (cell != NULL);
	g_return_if_fail (cell->value);
	g_return_if_fail (style_format != NULL);
1023

1024 1025
	cell_modified (cell);
	cell_queue_redraw (cell);
1026

1027
	/* Change the format */
Arturo Espinosa's avatar
Arturo Espinosa committed
1028
	style_format_ref (style_format);
1029
	style_format_unref (cell->style->format);
1030

Arturo Espinosa's avatar
Arturo Espinosa committed
1031
	cell->style->format = style_format;
1032
	cell->style->valid_flags |= STYLE_FORMAT;
1033
	cell->flags |= CELL_FORMAT_SET;
1034

Miguel de Icaza's avatar
Miguel de Icaza committed
1035 1036
	/* re-render the cell text */
	cell_render_value (cell);
1037
	cell_queue_redraw (cell);
Miguel de Icaza's avatar
Miguel de Icaza committed
1038
}
1039

1040 1041 1042 1043
void
cell_comment_reposition (Cell *cell)
{
	GList *l;
1044

1045 1046
	g_return_if_fail (cell != NULL);
	g_return_if_fail (cell->comment != NULL);
1047

1048 1049 1050 1051 1052 1053 1054 1055
	for (l = cell->comment->realized_list; l; l = l->next){
		GnomeCanvasItem *o = l->data;
		SheetView *sheet_view = GNUMERIC_SHEET (o->canvas)->sheet_view;

		sheet_view_comment_relocate (sheet_view, cell->col->pos, cell->row->pos, o);
	}
}

1056
/*
1057
 * cell_relocate:
1058
 * @cell:     The cell that is changing position
1059 1060
 *
 * This routine is used to move a cell to a different location:
1061 1062
 *
 * Auxiliary items canvas items attached to the cell are moved.
1063
 */
Arturo Espinosa's avatar
Arturo Espinosa committed
1064
void
1065
cell_relocate (Cell *cell)
Arturo Espinosa's avatar
Arturo Espinosa committed
1066 1067
{
	g_return_if_fail (cell != NULL);
1068 1069

	/* 1. Tag the cell as modified */
1070 1071
	cell_modified (cell);

1072
	/* 2. If the cell contains a formula, relocate the formula */
1073
	if (cell->parsed_node){
1074
		sheet_cell_formula_unlink (cell);
1075 1076 1077 1078

		/*
		 * WARNING WARNING WARNING
		 *
1079
		 * This will only work if the new array cell has already
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
		 * been inserted.
		 *
		 * WARNING WARNING WARNING
		 */
		/* If cell was part of an array, reset the corner pointer */
		if (cell->parsed_node->oper == OPER_ARRAY) {
			int const x = cell->parsed_node->u.array.x;
			int const y = cell->parsed_node->u.array.y;
			if (x != 0 || y != 0)
				cell->parsed_node->u.array.corner.cell =
					sheet_cell_get (cell->sheet,
							cell->col->pos - x,
							cell->row->pos - y);
		}

1095
		/* The following call also relinks the cell.  */
1096
		cell_formula_changed (cell);
1097
	}
1098

1099
	/* 3. Move any auxiliary canvas items */
Miguel de Icaza's avatar
Miguel de Icaza committed
1100 1101
	if (cell->comment)
		cell_comment_reposition (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
}

/*
 * 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->parsed_node != NULL);

1113
	/* FIXME: does this work at all?  -- MW */
1114
	cell_modified (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
1115
}
1116 1117

int
1118
cell_get_horizontal_align (const Cell *cell)
1119 1120 1121
{
	g_return_val_if_fail (cell != NULL, HALIGN_LEFT);

1122
	if (cell->style->halign == HALIGN_GENERAL){
1123 1124 1125 1126 1127 1128 1129 1130
		if (cell->value){
			if (cell->value->type== VALUE_FLOAT ||
			    cell->value->type == VALUE_INTEGER)
				return HALIGN_RIGHT;
			else
				return HALIGN_LEFT;
		} else
			return HALIGN_RIGHT;
1131
	} else
1132 1133 1134
		return cell->style->halign;
}

1135
int
1136
cell_is_number (const Cell *cell)
1137
{
1138
	return cell->value && VALUE_IS_NUMBER (cell->value);
1139 1140 1141
}

static inline int
1142
cell_contents_fit_inside_column (const Cell *cell)
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
{
	if (cell->width < COL_INTERNAL_WIDTH (cell->col))
		return TRUE;
	else
		return FALSE;
}

/*
 * cell_get_span:
 * @cell:   The cell we will examine
 * @col1:   return value: the first column used by this cell
 * @col2:   return value: the last column used by this cell
 *
 * This routine returns the column interval used by a Cell.
 */
void
cell_get_span (Cell *cell, int *col1, int *col2)
{
	Sheet *sheet;
	int align, left;
	int row, pos, margin;
1164

1165 1166
	g_return_if_fail (cell != NULL);

1167 1168 1169 1170
        /*
	 * If the cell is a number, or the text fits inside the column, or the
	 * alignment modes are set to "justify", then we report only one
	 * column is used.
1171 1172
	 */
	if (cell_is_number (cell) ||
1173 1174
	    cell->style->fit_in_cell ||
	    cell->style->valign == VALIGN_JUSTIFY ||
1175
	    cell->style->halign == HALIGN_JUSTIFY ||
Arturo Espinosa's avatar
Arturo Espinosa committed
1176
	    cell->style->halign == HALIGN_FILL    ||
1177 1178 1179 1180 1181 1182 1183 1184 1185
	    cell_contents_fit_inside_column (cell)){
		*col1 = *col2 = cell->col->pos;
		return;
	}

	sheet = cell->sheet;
	align = cell_get_horizontal_align (cell);
	row   = cell->row->pos;

Arturo Espinosa's avatar
Arturo Espinosa committed
1186
	switch (align){
1187 1188 1189 1190 1191
	case HALIGN_LEFT:
		*col1 = *col2 = cell->col->pos;
		pos = cell->col->pos + 1;
		left = cell->width - COL_INTERNAL_WIDTH (cell->col);
		margin = cell->col->margin_b;
1192

1193 1194 1195 1196 1197 1198
		for (; left > 0 && pos < SHEET_MAX_COLS-1; pos++){
			ColRowInfo *ci;
			Cell *sibling;

			sibling = sheet_cell_get (sheet, pos, row);

Jody Goldberg's avatar
Jody Goldberg committed
1199
			if (!cell_is_blank(sibling))
1200 1201 1202
				return;

			ci = sheet_col_get_info (sheet, pos);
1203

1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
			/* The space consumed is:
			 *    - The margin_b from the last column
			 *    - The width of the cell
			 */
			left -= COL_INTERNAL_WIDTH (ci) +
				margin + ci->margin_a;
			margin = ci->margin_b;
			(*col2)++;
		}
		return;
1214

1215 1216 1217 1218 1219
	case HALIGN_RIGHT:
		*col1 = *col2 = cell->col->pos;
		pos = cell->col->pos - 1;
		left = cell->width - COL_INTERNAL_WIDTH (cell->col);
		margin = cell->col->margin_a;
1220