cell.c 33.5 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_unref (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_unref (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);
Morten Welinder's avatar
Morten Welinder committed
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
Today:    
Miguel de Icaza committed
532
void
533
cell_set_rendered_text (Cell *cell, const char *rendered_text)
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
534
{
535
	String *oldtext;
536

Miguel de Icaza's avatar
Today:    
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
Today:    
Miguel de Icaza committed
541

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

Miguel de Icaza's avatar
Today:    
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
Today:    
Miguel de Icaza committed
556
557
558
void
cell_render_value (Cell *cell)
{
559
	StyleColor *color;
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
560
	char *str;
561

Miguel de Icaza's avatar
Today:    
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;
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
569

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

Miguel de Icaza's avatar
Today:    
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

Morten Welinder's avatar
Morten Welinder committed
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;
Morten Welinder's avatar
Morten Welinder committed
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
Today:    
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
693
694
695
696
	/* Queue all of the dependencies for this cell */
	deps = cell_get_dependencies (cell->sheet,
				      cell->col->pos,
				      cell->row->pos);
	if (deps)
Morten Welinder's avatar
Morten Welinder committed
697
		cell_queue_recalc_list (deps, TRUE);
698
699
}

700

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

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

717
718
719
	cell_queue_redraw (cell);

	cell_set_text_simple (cell, text);
720
	cell_content_changed (cell);
721

722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
	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).
 *
737
 *   - It does not queue any recomputations.  You have to queue the
738
 *     recompute yourself.
739
740
741
742
743
744
745
 */
void
cell_set_formula_tree_simple (Cell *cell, ExprTree *formula)
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (formula != NULL);

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

749
750
	cell_modified (cell);
	cell_cleanout (cell);
751
752

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

758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
/**
 * 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;
783
	ExprTree *wrapper;
784
785
786
787
788
789
790
791
792
793
794

	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);
795
	expr_tree_unref (wrapper);
796
797
798
799
800

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

	for (x = 0; x < num_cols; ++x)
801
		for (y = 0; y < num_rows; ++y) {
802
803
804
805
806
807
808
			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);
809
			expr_tree_unref (wrapper);
810
811
812
813
814
815
		}

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

816
817
818
819
820
821
822
823
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);
824
	cell_content_changed (cell);
Arturo Espinosa's avatar
Today:    
Arturo Espinosa committed
825
826

	cell_queue_redraw (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
827
}
Arturo Espinosa's avatar
Arturo Espinosa committed
828

829
830
831
832
/**
 * cell_copy:
 * @cell: existing cell to duplicate
 *
833
 * Makes a copy of a Cell.
834
 *
835
 * Returns a copy of the cell.
Arturo Espinosa's avatar
Arturo Espinosa committed
836
837
 */
Cell *
838
cell_copy (const Cell *cell)
Arturo Espinosa's avatar
Arturo Espinosa committed
839
840
841
842
843
844
845
846
847
848
{
	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
849
	new_cell->flags &= ~CELL_QUEUED_FOR_RECALC;
850

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

	if (new_cell->text)
		string_ref (new_cell->text);
857
858
859
860

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

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

	if (new_cell->render_color)
		style_color_ref (new_cell->render_color);
866
867
868

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

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

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

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

Morten Welinder's avatar
Morten Welinder committed
883
884
885
886
887
888
	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);
	}

889
	cell_modified (cell);
890
	cell_cleanout (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
891

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

896
	cell_comment_destroy (cell);
897
898

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

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

905
	g_free (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
906
}
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
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
934
935
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
936
937
938
939
940
941
942
943
944
945
946
947
948
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");
}
949
950
951
952
953
954
955
956
957

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
Today:    
Miguel de Icaza committed
958
959
960
void
cell_queue_redraw (Cell *cell)
{
Michael Meeks's avatar
Michael Meeks committed
961
	/* You wake up dead after a deep freeze */
962
	if (redraws_deep_frozen > 0)
Michael Meeks's avatar
Michael Meeks committed
963
964
		return;

965
	g_return_if_fail (cell != NULL);
966
967
968
969
970

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

Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
972
973
974
975
976
	sheet_redraw_cell_region (cell->sheet,
				  cell->col->pos, cell->row->pos,
				  cell->col->pos, cell->row->pos);
}

977
978
979
980
981
982
983
984
985
/*
 * 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
986
cell_set_format_simple (Cell *cell, const char *format)
987
988
989
{
	g_return_if_fail (cell != NULL);
	g_return_if_fail (format != NULL);
990

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

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

1001
1002
1003
1004
1005
1006
/*
 * 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
Today:    
Miguel de Icaza committed
1007
void
1008
cell_set_format (Cell *cell, const char *format)
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
1009
{
1010
	g_return_if_fail (cell != NULL);
1011

1012
	cell_set_format_simple (cell, format);
1013

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

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

1026
1027
	cell_modified (cell);
	cell_queue_redraw (cell);
1028

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

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

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

1042
1043
1044
1045
void
cell_comment_reposition (Cell *cell)
{
	GList *l;
1046

1047
1048
	g_return_if_fail (cell != NULL);
	g_return_if_fail (cell->comment != NULL);
1049

1050
1051
1052
1053
1054
1055
1056
1057
	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);
	}
}

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

	/* 1. Tag the cell as modified */
1074
1075
	cell_modified (cell);

1076
	/* 2. If the cell contains a formula, relocate the formula */
1077
	if (cell->parsed_node){
1078
1079
		EvalPosition pos;
		ExprTree * newtree;
1080
		sheet_cell_formula_unlink (cell);
1081
1082
1083
1084

		/*
		 * WARNING WARNING WARNING
		 *
1085
		 * This will only work if the new array cell has already
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
		 * 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);
		}

1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
		newtree = expr_relocate (cell->parsed_node,
					 eval_pos_cell (&pos, cell),
					 col_diff, row_diff);

		if (newtree) {
			expr_tree_ref (newtree);
			expr_tree_unref (cell->parsed_node);
			cell->parsed_node = newtree;
		}

1111
		/* The following call also relinks the cell.  */
1112
		cell_formula_changed (cell);
1113
	}
1114

1115
	/* 3. Move any auxiliary canvas items */
Miguel de Icaza's avatar
Miguel de Icaza committed
1116
1117
	if (cell->comment)
		cell_comment_reposition (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
}

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

1129
	/* FIXME: does this work at all?  -- MW */
1130
	cell_modified (cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
1131
}
1132
1133

int
1134
cell_get_horizontal_align (const Cell *cell)
1135
1136
1137
{
	g_return_val_if_fail (cell != NULL, HALIGN_LEFT);

1138
	if (cell->style->halign == HALIGN_GENERAL){